// 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" "slices" "strings" "sync" "time" "golang.org/x/mod/semver" "golang.org/x/tools/internal/gopathwalk" ) type directory struct { path Relpath importPath string version string // semantic version syms []symbol } // filterDirs 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) 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 } return ans, 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)) }) } // 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) { m := modCacheRegexp.FindStringSubmatch(string(dir)) // m[1] is the module path // m[2] is the version major.minor.patch(-