diff options
Diffstat (limited to 'vendor/golang.org/x/tools/internal/modindex/directories.go')
| -rw-r--r-- | vendor/golang.org/x/tools/internal/modindex/directories.go | 148 |
1 files changed, 72 insertions, 76 deletions
diff --git a/vendor/golang.org/x/tools/internal/modindex/directories.go b/vendor/golang.org/x/tools/internal/modindex/directories.go index 2faa6ce0b..9a963744b 100644 --- a/vendor/golang.org/x/tools/internal/modindex/directories.go +++ b/vendor/golang.org/x/tools/internal/modindex/directories.go @@ -10,7 +10,6 @@ import ( "os" "path/filepath" "regexp" - "slices" "strings" "sync" "time" @@ -20,50 +19,48 @@ import ( ) type directory struct { - path Relpath + path string // relative to GOMODCACHE importPath string version string // semantic version - syms []symbol } -// byImportPath groups the directories by import path, -// sorting the ones with the same import path by semantic version, -// most recent first. -func byImportPath(dirs []Relpath) (map[string][]*directory, error) { - ans := make(map[string][]*directory) // key is import path - for _, d := range dirs { - ip, sv, err := DirToImportPathVersion(d) +// bestDirByImportPath returns the best directory for each import +// path, where "best" means most recent semantic version. These import +// paths are inferred from the GOMODCACHE-relative dir names in dirs. +func bestDirByImportPath(dirs []string) (map[string]directory, error) { + dirsByPath := make(map[string]directory) + for _, dir := range dirs { + importPath, version, err := dirToImportPathVersion(dir) if err != nil { return nil, err } - ans[ip] = append(ans[ip], &directory{ - path: d, - importPath: ip, - version: sv, - }) - } - for k, v := range ans { - semanticSort(v) - ans[k] = v + new := directory{ + path: dir, + importPath: importPath, + version: version, + } + if old, ok := dirsByPath[importPath]; !ok || compareDirectory(new, old) < 0 { + dirsByPath[importPath] = new + } } - return ans, nil + return dirsByPath, nil } -// sort the directories by semantic version, latest first -func semanticSort(v []*directory) { - slices.SortFunc(v, func(l, r *directory) int { - if n := semver.Compare(l.version, r.version); n != 0 { - return -n // latest first - } - return strings.Compare(string(l.path), string(r.path)) - }) +// compareDirectory defines an ordering of path@version directories, +// by descending version, then by ascending path. +func compareDirectory(x, y directory) int { + if sign := -semver.Compare(x.version, y.version); sign != 0 { + return sign // latest first + } + return strings.Compare(string(x.path), string(y.path)) } // modCacheRegexp splits a relpathpath into module, module version, and package. var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) -// DirToImportPathVersion computes import path and semantic version -func DirToImportPathVersion(dir Relpath) (string, string, error) { +// dirToImportPathVersion computes import path and semantic version +// from a GOMODCACHE-relative directory name. +func dirToImportPathVersion(dir string) (string, string, error) { m := modCacheRegexp.FindStringSubmatch(string(dir)) // m[1] is the module path // m[2] is the version major.minor.patch(-<pre release identifier) @@ -74,62 +71,61 @@ func DirToImportPathVersion(dir Relpath) (string, string, error) { if !semver.IsValid(m[2]) { return "", "", fmt.Errorf("bad semantic version %s", m[2]) } - // ToSlash is required for Windows. + // ToSlash is required to convert Windows file paths + // into Go package import paths. return filepath.ToSlash(m[1] + m[3]), m[2], nil } -// a region controls what directories to look at, for -// updating the index incrementally, and for testing that. -// (for testing one builds an index as of A, incrementally -// updates it to B, and compares the result to an index build -// as of B.) -type region struct { - onlyAfter, onlyBefore time.Time - sync.Mutex - ans []Relpath -} +// findDirs returns an unordered list of relevant package directories, +// relative to the specified module cache root. The result includes only +// module dirs whose mtime is within (start, end). +func findDirs(root string, start, end time.Time) []string { + var ( + resMu sync.Mutex + res []string + ) -func findDirs(root string, onlyAfter, onlyBefore time.Time) []Relpath { - roots := []gopathwalk.Root{{Path: root, Type: gopathwalk.RootModuleCache}} - // TODO(PJW): adjust concurrency - opts := gopathwalk.Options{ModulesEnabled: true, Concurrency: 1 /* ,Logf: log.Printf*/} - betw := ®ion{ - onlyAfter: onlyAfter, - onlyBefore: onlyBefore, + addDir := func(root gopathwalk.Root, dir string) { + // TODO(pjw): do we need to check times? + resMu.Lock() + defer resMu.Unlock() + res = append(res, relative(root.Path, dir)) } - gopathwalk.WalkSkip(roots, betw.addDir, betw.skipDir, opts) - return betw.ans -} - -func (r *region) addDir(rt gopathwalk.Root, dir string) { - // do we need to check times? - r.Lock() - defer r.Unlock() - x := filepath.ToSlash(string(toRelpath(Abspath(rt.Path), dir))) - r.ans = append(r.ans, toRelpath(Abspath(rt.Path), x)) -} -func (r *region) skipDir(_ gopathwalk.Root, dir string) bool { - // The cache directory is already ignored in gopathwalk\ - if filepath.Base(dir) == "internal" { - return true - } - if strings.Contains(dir, "toolchain@") { - return true - } - // don't look inside @ directories that are too old - if strings.Contains(filepath.Base(dir), "@") { - st, err := os.Stat(dir) - if err != nil { - log.Printf("can't stat dir %s %v", dir, err) + skipDir := func(_ gopathwalk.Root, dir string) bool { + // The cache directory is already ignored in gopathwalk. + if filepath.Base(dir) == "internal" { return true } - if st.ModTime().Before(r.onlyAfter) { + + // Skip toolchains. + if strings.Contains(dir, "toolchain@") { return true } - if st.ModTime().After(r.onlyBefore) { - return true + + // Don't look inside @ directories that are too old/new. + if strings.Contains(filepath.Base(dir), "@") { + st, err := os.Stat(dir) + if err != nil { + log.Printf("can't stat dir %s %v", dir, err) + return true + } + mtime := st.ModTime() + return mtime.Before(start) || mtime.After(end) } + + return false } - return false + + // TODO(adonovan): parallelize this. Even with a hot buffer cache, + // find $(go env GOMODCACHE) -type d + // can easily take up a minute. + roots := []gopathwalk.Root{{Path: root, Type: gopathwalk.RootModuleCache}} + gopathwalk.WalkSkip(roots, addDir, skipDir, gopathwalk.Options{ + ModulesEnabled: true, + Concurrency: 1, // TODO(pjw): adjust concurrency + // Logf: log.Printf, + }) + + return res } |
