diff --git a/apply.go b/apply.go index de1d4c7..ef2eb64 100644 --- a/apply.go +++ b/apply.go @@ -54,7 +54,7 @@ func runApply(cmd *Command, args []string) { run("go", "get", "-u", "-d", path.Join(cmd.importPath, "...")) // update that dependency - var repo, err = repoRootForImportPath(cmd.importPath) + var repo, err = glockRepoRootForImportPath(cmd.importPath) if err != nil { fmt.Println("error determining repo root for", cmd.importPath, err) continue diff --git a/util.go b/util.go index 1ee6222..0aabb96 100644 --- a/util.go +++ b/util.go @@ -42,28 +42,16 @@ func managedRepoRoot(importPath string) (*managedRepo, error) { // This is done to support repos with non-go-get friendly names. // Also, returns an error if it doesn't exist (e.g. it needs to be go gotten). func glockRepoRootForImportPath(importPath string) (*repoRoot, error) { - var pkg, err = build.Import(importPath, "", build.FindOnly) + pkg, err := build.Import(importPath, "", build.FindOnly) if err != nil { return nil, err } - rr, err := repoRootForImportPath(importPath) - if err == nil { - // it may not exist, even with err == nil - _, err = os.Stat(pkg.Dir) - if err != nil { - return nil, err - } - return rr, nil - } - - var dir = pkg.ImportPath - for len(dir) > 1 { + for dir := pkg.ImportPath; len(dir) > 1; dir = filepath.Dir(dir) { rr, err := fastRepoRoot(dir) if err == nil { return rr, nil } - dir = filepath.Dir(dir) } return nil, fmt.Errorf("no version control directory found for %q", importPath) @@ -73,7 +61,7 @@ func glockRepoRootForImportPath(importPath string) (*repoRoot, error) { // which VCS to use for the given import path. // If none are found, an error is returned. func fastRepoRoot(rootImportPath string) (*repoRoot, error) { - var pkg, err = build.Import(rootImportPath, "", build.FindOnly) + pkg, err := build.Import(rootImportPath, "", build.FindOnly) if err != nil { return nil, err } diff --git a/vcs.go b/vcs.go index 388b918..e7086b3 100644 --- a/vcs.go +++ b/vcs.go @@ -357,178 +357,8 @@ type repoRoot struct { root string } -// repoRootForImportPath analyzes importPath to determine the -// version control system, and code repository to use. -func repoRootForImportPath(importPath string) (*repoRoot, error) { - rr, err := repoRootForImportPathStatic(importPath, "") - if err == errUnknownSite { - rr, err = repoRootForImportDynamic(importPath) - - // repoRootForImportDynamic returns error detail - // that is irrelevant if the user didn't intend to use a - // dynamic import in the first place. - // Squelch it. - if err != nil { - if buildV { - log.Printf("import %q: %v", importPath, err) - } - err = fmt.Errorf("unrecognized import path %q", importPath) - } - } - - if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") { - // Do not allow wildcards in the repo root. - rr = nil - err = fmt.Errorf("cannot expand ... in %q", importPath) - } - return rr, err -} - var errUnknownSite = errors.New("dynamic lookup required to find mapping") -// repoRootForImportPathStatic attempts to map importPath to a -// repoRoot using the commonly-used VCS hosting sites in vcsPaths -// (github.com/user/dir), or from a fully-qualified importPath already -// containing its VCS type (foo.com/repo.git/dir) -// -// If scheme is non-empty, that scheme is forced. -func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) { - if strings.Contains(importPath, "://") { - return nil, fmt.Errorf("invalid import path %q", importPath) - } - for _, srv := range vcsPaths { - if !strings.HasPrefix(importPath, srv.prefix) { - continue - } - m := srv.regexp.FindStringSubmatch(importPath) - if m == nil { - if srv.prefix != "" { - return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath) - } - continue - } - - // Build map of named subexpression matches for expand. - match := map[string]string{ - "prefix": srv.prefix, - "import": importPath, - } - for i, name := range srv.regexp.SubexpNames() { - if name != "" && match[name] == "" { - match[name] = m[i] - } - } - if srv.vcs != "" { - match["vcs"] = expand(match, srv.vcs) - } - if srv.repo != "" { - match["repo"] = expand(match, srv.repo) - } - if srv.check != nil { - if err := srv.check(match); err != nil { - return nil, err - } - } - vcs := vcsByCmd(match["vcs"]) - if vcs == nil { - return nil, fmt.Errorf("unknown version control system %q", match["vcs"]) - } - if srv.ping { - if scheme != "" { - match["repo"] = scheme + "://" + match["repo"] - } else { - for _, scheme := range vcs.scheme { - if vcs.ping(scheme, match["repo"]) == nil { - match["repo"] = scheme + "://" + match["repo"] - break - } - } - } - } - rr := &repoRoot{ - vcs: vcs, - repo: match["repo"], - root: match["root"], - } - return rr, nil - } - return nil, errUnknownSite -} - -// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not -// statically known by repoRootForImportPathStatic. -// -// This handles "vanity import paths" like "name.tld/pkg/foo". -func repoRootForImportDynamic(importPath string) (*repoRoot, error) { - slash := strings.Index(importPath, "/") - if slash < 0 { - return nil, errors.New("import path doesn't contain a slash") - } - host := importPath[:slash] - if !strings.Contains(host, ".") { - return nil, errors.New("import path doesn't contain a hostname") - } - urlStr, body, err := httpsOrHTTP(importPath) - if err != nil { - return nil, fmt.Errorf("http/https fetch: %v", err) - } - defer body.Close() - imports, err := parseMetaGoImports(body) - if err != nil { - return nil, fmt.Errorf("parsing %s: %v", importPath, err) - } - metaImport, err := matchGoImport(imports, importPath) - if err != nil { - if err != errNoMatch { - return nil, fmt.Errorf("parse %s: %v", urlStr, err) - } - return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr) - } - if buildV { - log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr) - } - // If the import was "uni.edu/bob/project", which said the - // prefix was "uni.edu" and the RepoRoot was "evilroot.com", - // make sure we don't trust Bob and check out evilroot.com to - // "uni.edu" yet (possibly overwriting/preempting another - // non-evil student). Instead, first verify the root and see - // if it matches Bob's claim. - if metaImport.Prefix != importPath { - if buildV { - log.Printf("get %q: verifying non-authoritative meta tag", importPath) - } - urlStr0 := urlStr - urlStr, body, err = httpsOrHTTP(metaImport.Prefix) - if err != nil { - return nil, fmt.Errorf("fetch %s: %v", urlStr, err) - } - imports, err := parseMetaGoImports(body) - if err != nil { - return nil, fmt.Errorf("parsing %s: %v", importPath, err) - } - if len(imports) == 0 { - return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr) - } - metaImport2, err := matchGoImport(imports, importPath) - if err != nil || metaImport != metaImport2 { - return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix) - } - } - - if !strings.Contains(metaImport.RepoRoot, "://") { - return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot) - } - rr := &repoRoot{ - vcs: vcsByCmd(metaImport.VCS), - repo: metaImport.RepoRoot, - root: metaImport.Prefix, - } - if rr.vcs == nil { - return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS) - } - return rr, nil -} - // metaImport represents the parsed tags from HTML files. type metaImport struct {