// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package modindex import ( "fmt" "log" "os" "path/filepath" "regexp" "strings" "sync" "time" "golang.org/x/mod/semver" "golang.org/x/tools/internal/gopathwalk" ) type directory struct { path string // relative to GOMODCACHE importPath string version string // semantic version } // 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 } new := directory{ path: dir, importPath: importPath, version: version, } if old, ok := dirsByPath[importPath]; !ok || compareDirectory(new, old) < 0 { dirsByPath[importPath] = new } } return dirsByPath, nil } // 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 // 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(-