6
0
mirror of https://github.com/grdl/git-get.git synced 2026-03-22 18:05:07 +00:00

Add --skip-host flag to get command (#7)

When set, git-get won't create a directory for the repo host.
So instead of `<root>/<host>/<user>/<repo>`, a repo will be cloned into `<root>/<user>/<repo>`.
It's useful if all repos some from the same host and that additional folder feels redundant.
This commit is contained in:
Grzegorz Dlugoszewski
2020-07-07 18:35:30 +02:00
committed by GitHub
parent 0097681f89
commit 0064fc3b8e
6 changed files with 108 additions and 28 deletions

View File

@@ -22,6 +22,7 @@ var (
KeyDefaultHost = "host"
KeyFetch = "fetch"
KeyOutput = "out"
KeySkipHost = "skip-host"
KeyReposRoot = "root"
)
@@ -30,6 +31,7 @@ var Defaults = map[string]string{
KeyDefaultHost: "github.com",
KeyOutput: OutTree,
KeyReposRoot: fmt.Sprintf("~%c%s", filepath.Separator, "repositories"),
// KeySkipHost: "false",
}
// Values for the --out flag.
@@ -78,6 +80,7 @@ func Init(cfg Gitconfig) {
func readGitconfig(cfg Gitconfig) {
var lines []string
// TODO: Can we somehow iterate over all possible flags?
for key := range Defaults {
if val := cfg.Get(fmt.Sprintf("%s.%s", GitgetPrefix, key)); val != "" {
lines = append(lines, fmt.Sprintf("%s=%s", key, val))
@@ -86,6 +89,11 @@ func readGitconfig(cfg Gitconfig) {
viper.SetConfigType("env")
viper.ReadConfig(bytes.NewBuffer([]byte(strings.Join(lines, "\n"))))
// TODO: A hacky way to read boolean flag from gitconfig. Find a cleaner way.
if val := cfg.Get(fmt.Sprintf("%s.%s", GitgetPrefix, KeySkipHost)); strings.ToLower(val) == "true" {
viper.Set(KeySkipHost, true)
}
}
// Expand applies the variables expansion to a viper config of given key.

View File

@@ -9,11 +9,12 @@ import (
// GetCfg provides configuration for the Get command.
type GetCfg struct {
Branch string
DefHost string
Dump string
Root string
URL string
Branch string
DefHost string
Dump string
Root string
SkipHost bool
URL string
}
// Get executes the "git get" command.
@@ -40,7 +41,7 @@ func cloneSingleRepo(c *GetCfg) error {
opts := &git.CloneOpts{
URL: url,
Path: filepath.Join(c.Root, URLToPath(url)),
Path: filepath.Join(c.Root, URLToPath(*url, c.SkipHost)),
Branch: c.Branch,
}
@@ -63,7 +64,7 @@ func cloneDumpFile(c *GetCfg) error {
opts := &git.CloneOpts{
URL: url,
Path: filepath.Join(c.Root, URLToPath(url)),
Path: filepath.Join(c.Root, URLToPath(*url, c.SkipHost)),
Branch: line.branch,
}

View File

@@ -2,6 +2,7 @@ package pkg
import (
urlpkg "net/url"
"path"
"path/filepath"
"regexp"
"strings"
@@ -52,6 +53,12 @@ func ParseURL(rawURL string, defaultHost string) (url *urlpkg.URL, err error) {
url.Host = defaultHost
}
// Don't use host when scheme is file://. The fragment detected as url.Host should be a first directory of url.Path
if url.Scheme == "file" && url.Host != "" {
url.Path = path.Join(url.Host, url.Path)
url.Host = ""
}
// Default to https when scheme is empty
if url.Scheme == "" {
url.Scheme = "https"
@@ -60,18 +67,30 @@ func ParseURL(rawURL string, defaultHost string) (url *urlpkg.URL, err error) {
return url, nil
}
// URLToPath cleans up the URL and converts it into a path string.
// URLToPath cleans up the URL and converts it into a path string with correct separators for the current OS.
// Eg, ssh://git@github.com:22/~user/repo.git => github.com/user/repo
func URLToPath(url *urlpkg.URL) (repoPath string) {
// Remove port numbers from host
repoHost := strings.Split(url.Host, ":")[0]
//
// If skipHost is true, it removes the host part from the path.
// Eg, ssh://git@github.com:22/~user/repo.git => user/repo
func URLToPath(url urlpkg.URL, skipHost bool) string {
// Remove port numbers from host.
url.Host = strings.Split(url.Host, ":")[0]
// Remove trailing ".git" from repo name
repoPath = filepath.Join(repoHost, url.Path)
repoPath = strings.TrimSuffix(repoPath, ".git")
// Remove tilde (~) char from username.
url.Path = strings.ReplaceAll(url.Path, "~", "")
// Remove tilde (~) char from username
repoPath = strings.ReplaceAll(repoPath, "~", "")
// Remove leading and trailing slashes (correct separator is added by the filepath.Join() below).
url.Path = strings.Trim(url.Path, "/")
return repoPath
// Remove trailing ".git" from repo name.
url.Path = strings.TrimSuffix(url.Path, ".git")
// Replace slashes with separator correct for the current OS.
url.Path = strings.ReplaceAll(url.Path, "/", string(filepath.Separator))
if skipHost {
url.Host = ""
}
return filepath.Join(url.Host, url.Path)
}

View File

@@ -52,13 +52,58 @@ func TestURLParse(t *testing.T) {
for _, test := range tests {
url, err := ParseURL(test.in, cfg.Defaults[cfg.KeyDefaultHost])
if err != nil {
t.Errorf("Error parsing Path: %+v", err)
t.Fatalf("got error: %+v", err)
}
got := URLToPath(url)
got := URLToPath(*url, false)
if got != test.want {
t.Errorf("Wrong result of parsing Path: %s, got: %s; wantBranch: %s", test.in, got, test.want)
t.Errorf("wrong result for %q; expected %q; got %q", test.in, test.want, got)
}
}
}
func TestURLParseSkipHost(t *testing.T) {
tests := []struct {
in string
want string
}{
{"ssh://github.com/grdl/git-get.git", "grdl/git-get"},
{"ssh://user@github.com/grdl/git-get.git", "grdl/git-get"},
{"ssh://user@github.com:1234/grdl/git-get.git", "grdl/git-get"},
{"ssh://user@github.com/~user/grdl/git-get.git", "user/grdl/git-get"},
{"git+ssh://github.com/grdl/git-get.git", "grdl/git-get"},
{"git@github.com:grdl/git-get.git", "grdl/git-get"},
{"git@github.com:/~user/grdl/git-get.git", "user/grdl/git-get"},
{"git://github.com/grdl/git-get.git", "grdl/git-get"},
{"git://github.com/~user/grdl/git-get.git", "user/grdl/git-get"},
{"https://github.com/grdl/git-get.git", "grdl/git-get"},
{"http://github.com/grdl/git-get.git", "grdl/git-get"},
{"https://github.com/grdl/git-get", "grdl/git-get"},
{"https://github.com/git-get.git", "git-get"},
{"https://github.com/git-get", "git-get"},
{"https://github.com/grdl/sub/path/git-get.git", "grdl/sub/path/git-get"},
{"https://github.com:1234/grdl/git-get.git", "grdl/git-get"},
{"https://github.com/grdl/git-get.git/", "grdl/git-get"},
{"https://github.com/grdl/git-get/", "grdl/git-get"},
{"https://github.com/grdl/git-get/////", "grdl/git-get"},
{"https://github.com/grdl/git-get.git/////", "grdl/git-get"},
{"ftp://github.com/grdl/git-get.git", "grdl/git-get"},
{"ftps://github.com/grdl/git-get.git", "grdl/git-get"},
{"rsync://github.com/grdl/git-get.git", "grdl/git-get"},
{"local/grdl/git-get/", "local/grdl/git-get"},
{"file://local/grdl/git-get", "local/grdl/git-get"},
}
for _, test := range tests {
url, err := ParseURL(test.in, cfg.Defaults[cfg.KeyDefaultHost])
if err != nil {
t.Fatalf("got error: %+v", err)
}
got := URLToPath(*url, true)
if got != test.want {
t.Errorf("wrong result for %q; expected %q; got %q", test.in, test.want, got)
}
}
}
@@ -73,10 +118,10 @@ func TestInvalidURLParse(t *testing.T) {
//"git@github.com:1234:grdl/git-get.git",
}
for _, in := range invalidURLs {
got, err := ParseURL(in, cfg.Defaults[cfg.KeyDefaultHost])
for _, test := range invalidURLs {
got, err := ParseURL(test, cfg.Defaults[cfg.KeyDefaultHost])
if err == nil {
t.Errorf("Wrong result of parsing invalid Path: %s, got: %s, wantBranch: error", in, got)
t.Errorf("expected error; got %q", got)
}
}
}