Skip to content

Commit

Permalink
save: remove repoRootForImportPath
Browse files Browse the repository at this point in the history
This greatly speeds up `glock save`. Closes robfig#25.

Before:

$ time glock save github.com/cockroachdb/cockroach

real	0m59.388s
user	0m7.946s
sys	0m3.877s

After:

$ time glock save github.com/cockroachdb/cockroach

real	0m3.729s
user	0m7.353s
sys	0m3.442s
  • Loading branch information
tamird committed Aug 8, 2016
1 parent c7fb89f commit 1768949
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 186 deletions.
2 changes: 1 addition & 1 deletion apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 3 additions & 15 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}
Expand Down
170 changes: 0 additions & 170 deletions vcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 <meta name="go-import"
// content="prefix vcs reporoot" /> tags from HTML files.
type metaImport struct {
Expand Down

0 comments on commit 1768949

Please sign in to comment.