From 2237341b8223bcf5f6e91362e723dff7ca2e0f67 Mon Sep 17 00:00:00 2001 From: Songmu Date: Tue, 24 Dec 2019 02:06:43 +0900 Subject: [PATCH] fix interface of newURL --- cmd_list.go | 2 +- cmd_look.go | 2 +- getter.go | 37 +-------------------------- url.go | 72 +++++++++++++++++++++++++++++++++++++++-------------- url_test.go | 10 ++++---- 5 files changed, 62 insertions(+), 61 deletions(-) diff --git a/cmd_list.go b/cmd_list.go index cce1ffc..d8b3479 100644 --- a/cmd_list.go +++ b/cmd_list.go @@ -24,7 +24,7 @@ func doList(c *cli.Context) error { } if query != "" { if hasSchemePattern.MatchString(query) || scpLikeURLPattern.MatchString(query) { - if url, err := newURL(query, false); err == nil { + if url, err := newURL(query, false, false); err == nil { if repo, err := LocalRepositoryFromURL(url); err == nil { query = filepath.ToSlash(repo.RelPath) } diff --git a/cmd_look.go b/cmd_look.go index f32b84e..47343b5 100644 --- a/cmd_look.go +++ b/cmd_look.go @@ -47,7 +47,7 @@ func doLook(c *cli.Context) error { } if len(reposFound) == 0 { - if url, err := newURL(name, false); err == nil { + if url, err := newURL(name, false, false); err == nil { repo, err := LocalRepositoryFromURL(url) if err != nil { return err diff --git a/getter.go b/getter.go index 273fc5b..a9a1028 100644 --- a/getter.go +++ b/getter.go @@ -31,46 +31,11 @@ type getter struct { } func (g *getter) get(argURL string) error { - // If argURL is a "./foo" or "../bar" form, - // find repository name trailing after github.com/USER/. - argURL = filepath.ToSlash(argURL) - parts := strings.Split(argURL, "/") - if parts[0] == "." || parts[0] == ".." { - if wd, err := os.Getwd(); err == nil { - path := filepath.Clean(filepath.Join(wd, filepath.Join(parts...))) - - var localRepoRoot string - roots, err := localRepositoryRoots(true) - if err != nil { - return err - } - for _, r := range roots { - p := strings.TrimPrefix(path, r+string(filepath.Separator)) - if p != path && (localRepoRoot == "" || len(p) < len(localRepoRoot)) { - localRepoRoot = filepath.ToSlash(p) - } - } - - if localRepoRoot != "" { - // Guess it - logger.Log("resolved", fmt.Sprintf("relative %q to %q", argURL, "https://"+localRepoRoot)) - argURL = "https://" + localRepoRoot - } - } - } - - u, err := newURL(argURL, false) + u, err := newURL(argURL, g.ssh, false) if err != nil { return fmt.Errorf("Could not parse URL %q: %w", argURL, err) } - if g.ssh { - // Assume Git repository if `-p` is given. - if u, err = convertGitURLHTTPToSSH(u); err != nil { - return fmt.Errorf("Could not convert URL %q: %w", u, err) - } - } - remote, err := NewRemoteRepository(u) if err != nil { return err diff --git a/url.go b/url.go index 54d2a1d..dfac8ca 100644 --- a/url.go +++ b/url.go @@ -4,11 +4,13 @@ import ( "fmt" "net/url" "os" + "path/filepath" "regexp" "runtime" "strings" "github.com/Songmu/gitconfig" + "github.com/motemen/ghq/logger" ) // Convert SCP-like URL to SSH URL(e.g. [user@]host.xz:path/to/repo.git/) @@ -20,7 +22,35 @@ var ( looksLikeAuthorityPattern = regexp.MustCompile(`[A-Za-z0-9]\.[A-Za-z]+(?::\d{1,5})?$`) ) -func newURL(ref string, forceMe bool) (*url.URL, error) { +func newURL(ref string, ssh, forceMe bool) (*url.URL, error) { + // If argURL is a "./foo" or "../bar" form, + // find repository name trailing after github.com/USER/. + ref = filepath.ToSlash(ref) + parts := strings.Split(ref, "/") + if parts[0] == "." || parts[0] == ".." { + if wd, err := os.Getwd(); err == nil { + path := filepath.Clean(filepath.Join(wd, filepath.Join(parts...))) + + var localRepoRoot string + roots, err := localRepositoryRoots(true) + if err != nil { + return nil, err + } + for _, r := range roots { + p := strings.TrimPrefix(path, r+string(filepath.Separator)) + if p != path && (localRepoRoot == "" || len(p) < len(localRepoRoot)) { + localRepoRoot = filepath.ToSlash(p) + } + } + + if localRepoRoot != "" { + // Guess it + logger.Log("resolved", fmt.Sprintf("relative %q to %q", ref, "https://"+localRepoRoot)) + ref = "https://" + localRepoRoot + } + } + } + if !hasSchemePattern.MatchString(ref) { if scpLikeURLPattern.MatchString(ref) { matched := scpLikeURLPattern.FindStringSubmatch(ref) @@ -42,35 +72,41 @@ func newURL(ref string, forceMe bool) (*url.URL, error) { } } - url, err := url.Parse(ref) + u, err := url.Parse(ref) if err != nil { - return url, err + return nil, err } - - if !url.IsAbs() { - if !strings.Contains(url.Path, "/") { - url.Path, err = fillUsernameToPath(url.Path, forceMe) + if !u.IsAbs() { + if !strings.Contains(u.Path, "/") { + u.Path, err = fillUsernameToPath(u.Path, forceMe) if err != nil { - return url, err + return nil, err } } - url.Scheme = "https" - url.Host = "github.com" - if url.Path[0] != '/' { - url.Path = "/" + url.Path + u.Scheme = "https" + u.Host = "github.com" + if u.Path[0] != '/' { + u.Path = "/" + u.Path } } - return url, nil + if ssh { + // Assume Git repository if `-p` is given. + if u, err = convertGitURLHTTPToSSH(u); err != nil { + return nil, fmt.Errorf("Could not convert URL %q: %w", u, err) + } + } + + return u, nil } -func convertGitURLHTTPToSSH(url *url.URL) (*url.URL, error) { +func convertGitURLHTTPToSSH(u *url.URL) (*url.URL, error) { user := "git" - if url.User != nil { - user = url.User.Username() + if u.User != nil { + user = u.User.Username() } - sshURL := fmt.Sprintf("ssh://%s@%s%s", user, url.Host, url.Path) - return url.Parse(sshURL) + sshURL := fmt.Sprintf("ssh://%s@%s%s", user, u.Host, u.Path) + return u.Parse(sshURL) } func detectUserName() (string, error) { diff --git a/url_test.go b/url_test.go index 68af702..f7bcddf 100644 --- a/url_test.go +++ b/url_test.go @@ -77,7 +77,7 @@ completeUser = false`) if tc.setup != nil { defer tc.setup()() } - repo, err := newURL(tc.url, false) + repo, err := newURL(tc.url, false, false) if err != nil { t.Errorf("error should be nil but: %s", err) } @@ -107,7 +107,7 @@ func TestConvertGitURLHTTPToSSH(t *testing.T) { for _, tc := range testCases { t.Run(tc.url, func(t *testing.T) { - httpsURL, err := newURL(tc.url, false) + httpsURL, err := newURL(tc.url, false, false) if err != nil { t.Errorf("error should be nil but: %s", err) } @@ -124,15 +124,15 @@ func TestConvertGitURLHTTPToSSH(t *testing.T) { func TestNewURL_err(t *testing.T) { invalidURL := "http://foo.com/?foo\nbar" - _, err := newURL(invalidURL, false) + _, err := newURL(invalidURL, false, false) const wantSub = "net/url: invalid control character in URL" if got := fmt.Sprint(err); !strings.Contains(got, wantSub) { - t.Errorf("newURL(%q, false) error = %q; want substring %q", invalidURL, got, wantSub) + t.Errorf("newURL(%q, false, false) error = %q; want substring %q", invalidURL, got, wantSub) } defer gitconfig.WithConfig(t, `[[[`)() var exitError *exec.ExitError - _, err = newURL("peco", false) + _, err = newURL("peco", false, false) if !errors.As(err, &exitError) { t.Errorf("error should be occurred but nil") }