mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 12:09:57 +00:00
TUN-9016: update go to 1.24
## Summary Update several moving parts of cloudflared build system: * use goboring 1.24.2 in cfsetup * update linter and fix lint issues * update packages namely **quic-go and net** * install script for macos * update docker files to use go 1.24.1 * remove usage of cloudflare-go * pin golang linter Closes TUN-9016
This commit is contained in:
135
vendor/golang.org/x/tools/internal/modindex/directories.go
generated
vendored
Normal file
135
vendor/golang.org/x/tools/internal/modindex/directories.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
// 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(-<pre release identifier)
|
||||
// m[3] is the rest of the package path
|
||||
if len(m) != 4 {
|
||||
return "", "", fmt.Errorf("bad dir %s", dir)
|
||||
}
|
||||
if !semver.IsValid(m[2]) {
|
||||
return "", "", fmt.Errorf("bad semantic version %s", m[2])
|
||||
}
|
||||
// ToSlash is required for Windows.
|
||||
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
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
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)
|
||||
return true
|
||||
}
|
||||
if st.ModTime().Before(r.onlyAfter) {
|
||||
return true
|
||||
}
|
||||
if st.ModTime().After(r.onlyBefore) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
266
vendor/golang.org/x/tools/internal/modindex/index.go
generated
vendored
Normal file
266
vendor/golang.org/x/tools/internal/modindex/index.go
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
// 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 (
|
||||
"bufio"
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
The on-disk index is a text file.
|
||||
The first 3 lines are header information containing CurrentVersion,
|
||||
the value of GOMODCACHE, and the validity date of the index.
|
||||
(This is when the code started building the index.)
|
||||
Following the header are sections of lines, one section for each
|
||||
import path. These sections are sorted by package name.
|
||||
The first line of each section, marked by a leading :, contains
|
||||
the package name, the import path, the name of the directory relative
|
||||
to GOMODCACHE, and its semantic version.
|
||||
The rest of each section consists of one line per exported symbol.
|
||||
The lines are sorted by the symbol's name and contain the name,
|
||||
an indication of its lexical type (C, T, V, F), and if it is the
|
||||
name of a function, information about the signature.
|
||||
|
||||
The fields in the section header lines are separated by commas, and
|
||||
in the unlikely event this would be confusing, the csv package is used
|
||||
to write (and read) them.
|
||||
|
||||
In the lines containing exported names, C=const, V=var, T=type, F=func.
|
||||
If it is a func, the next field is the number of returned values,
|
||||
followed by pairs consisting of formal parameter names and types.
|
||||
All these fields are separated by spaces. Any spaces in a type
|
||||
(e.g., chan struct{}) are replaced by $s on the disk. The $s are
|
||||
turned back into spaces when read.
|
||||
|
||||
Here is an index header (the comments are not part of the index):
|
||||
0 // version (of the index format)
|
||||
/usr/local/google/home/pjw/go/pkg/mod // GOMODCACHE
|
||||
2024-09-11 18:55:09 // validity date of the index
|
||||
|
||||
Here is an index section:
|
||||
:yaml,gopkg.in/yaml.v1,gopkg.in/yaml.v1@v1.0.0-20140924161607-9f9df34309c0,v1.0.0-20140924161607-9f9df34309c0
|
||||
Getter T
|
||||
Marshal F 2 in interface{}
|
||||
Setter T
|
||||
Unmarshal F 1 in []byte out interface{}
|
||||
|
||||
The package name is yaml, the import path is gopkg.in/yaml.v1.
|
||||
Getter and Setter are types, and Marshal and Unmarshal are functions.
|
||||
The latter returns one value and has two arguments, 'in' and 'out'
|
||||
whose types are []byte and interface{}.
|
||||
*/
|
||||
|
||||
// CurrentVersion tells readers about the format of the index.
|
||||
const CurrentVersion int = 0
|
||||
|
||||
// Index is returned by ReadIndex().
|
||||
type Index struct {
|
||||
Version int
|
||||
Cachedir Abspath // The directory containing the module cache
|
||||
Changed time.Time // The index is up to date as of Changed
|
||||
Entries []Entry
|
||||
}
|
||||
|
||||
// An Entry contains information for an import path.
|
||||
type Entry struct {
|
||||
Dir Relpath // directory in modcache
|
||||
ImportPath string
|
||||
PkgName string
|
||||
Version string
|
||||
//ModTime STime // is this useful?
|
||||
Names []string // exported names and information
|
||||
}
|
||||
|
||||
// IndexDir is where the module index is stored.
|
||||
var IndexDir string
|
||||
|
||||
// Set IndexDir
|
||||
func init() {
|
||||
var dir string
|
||||
var err error
|
||||
if testing.Testing() {
|
||||
dir = os.TempDir()
|
||||
} else {
|
||||
dir, err = os.UserCacheDir()
|
||||
// shouldn't happen, but TempDir is better than
|
||||
// creating ./go/imports
|
||||
if err != nil {
|
||||
dir = os.TempDir()
|
||||
}
|
||||
}
|
||||
dir = filepath.Join(dir, "go", "imports")
|
||||
os.MkdirAll(dir, 0777)
|
||||
IndexDir = dir
|
||||
}
|
||||
|
||||
// ReadIndex reads the latest version of the on-disk index
|
||||
// for the cache directory cd.
|
||||
// It returns (nil, nil) if there is no index, but returns
|
||||
// a non-nil error if the index exists but could not be read.
|
||||
func ReadIndex(cachedir string) (*Index, error) {
|
||||
cachedir, err := filepath.Abs(cachedir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cd := Abspath(cachedir)
|
||||
dir := IndexDir
|
||||
base := indexNameBase(cd)
|
||||
iname := filepath.Join(dir, base)
|
||||
buf, err := os.ReadFile(iname)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf("cannot read %s: %w", iname, err)
|
||||
}
|
||||
fname := filepath.Join(dir, string(buf))
|
||||
fd, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
r := bufio.NewReader(fd)
|
||||
ix, err := readIndexFrom(cd, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ix, nil
|
||||
}
|
||||
|
||||
func readIndexFrom(cd Abspath, bx io.Reader) (*Index, error) {
|
||||
b := bufio.NewScanner(bx)
|
||||
var ans Index
|
||||
// header
|
||||
ok := b.Scan()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected scan error")
|
||||
}
|
||||
l := b.Text()
|
||||
var err error
|
||||
ans.Version, err = strconv.Atoi(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ans.Version != CurrentVersion {
|
||||
return nil, fmt.Errorf("got version %d, expected %d", ans.Version, CurrentVersion)
|
||||
}
|
||||
if ok := b.Scan(); !ok {
|
||||
return nil, fmt.Errorf("scanner error reading cachedir")
|
||||
}
|
||||
ans.Cachedir = Abspath(b.Text())
|
||||
if ok := b.Scan(); !ok {
|
||||
return nil, fmt.Errorf("scanner error reading index creation time")
|
||||
}
|
||||
// TODO(pjw): need to check that this is the expected cachedir
|
||||
// so the tag should be passed in to this function
|
||||
ans.Changed, err = time.ParseInLocation(time.DateTime, b.Text(), time.Local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var curEntry *Entry
|
||||
for b.Scan() {
|
||||
v := b.Text()
|
||||
if v[0] == ':' {
|
||||
if curEntry != nil {
|
||||
ans.Entries = append(ans.Entries, *curEntry)
|
||||
}
|
||||
// as directories may contain commas and quotes, they need to be read as csv.
|
||||
rdr := strings.NewReader(v[1:])
|
||||
cs := csv.NewReader(rdr)
|
||||
flds, err := cs.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(flds) != 4 {
|
||||
return nil, fmt.Errorf("header contains %d fields, not 4: %q", len(v), v)
|
||||
}
|
||||
curEntry = &Entry{PkgName: flds[0], ImportPath: flds[1], Dir: toRelpath(cd, flds[2]), Version: flds[3]}
|
||||
continue
|
||||
}
|
||||
curEntry.Names = append(curEntry.Names, v)
|
||||
}
|
||||
if curEntry != nil {
|
||||
ans.Entries = append(ans.Entries, *curEntry)
|
||||
}
|
||||
if err := b.Err(); err != nil {
|
||||
return nil, fmt.Errorf("scanner failed %v", err)
|
||||
}
|
||||
return &ans, nil
|
||||
}
|
||||
|
||||
// write the index as a text file
|
||||
func writeIndex(cachedir Abspath, ix *Index) error {
|
||||
ipat := fmt.Sprintf("index-%d-*", CurrentVersion)
|
||||
fd, err := os.CreateTemp(IndexDir, ipat)
|
||||
if err != nil {
|
||||
return err // can this happen?
|
||||
}
|
||||
defer fd.Close()
|
||||
if err := writeIndexToFile(ix, fd); err != nil {
|
||||
return err
|
||||
}
|
||||
content := fd.Name()
|
||||
content = filepath.Base(content)
|
||||
base := indexNameBase(cachedir)
|
||||
nm := filepath.Join(IndexDir, base)
|
||||
err = os.WriteFile(nm, []byte(content), 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeIndexToFile(x *Index, fd *os.File) error {
|
||||
cnt := 0
|
||||
w := bufio.NewWriter(fd)
|
||||
fmt.Fprintf(w, "%d\n", x.Version)
|
||||
fmt.Fprintf(w, "%s\n", x.Cachedir)
|
||||
// round the time down
|
||||
tm := x.Changed.Add(-time.Second / 2)
|
||||
fmt.Fprintf(w, "%s\n", tm.Format(time.DateTime))
|
||||
for _, e := range x.Entries {
|
||||
if e.ImportPath == "" {
|
||||
continue // shouldn't happen
|
||||
}
|
||||
// PJW: maybe always write these headers as csv?
|
||||
if strings.ContainsAny(string(e.Dir), ",\"") {
|
||||
log.Printf("DIR: %s", e.Dir)
|
||||
cw := csv.NewWriter(w)
|
||||
cw.Write([]string{":" + e.PkgName, e.ImportPath, string(e.Dir), e.Version})
|
||||
cw.Flush()
|
||||
} else {
|
||||
fmt.Fprintf(w, ":%s,%s,%s,%s\n", e.PkgName, e.ImportPath, e.Dir, e.Version)
|
||||
}
|
||||
for _, x := range e.Names {
|
||||
fmt.Fprintf(w, "%s\n", x)
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
if err := w.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// return the base name of the file containing the name of the current index
|
||||
func indexNameBase(cachedir Abspath) string {
|
||||
// crc64 is a way to convert path names into 16 hex digits.
|
||||
h := crc64.Checksum([]byte(cachedir), crc64.MakeTable(crc64.ECMA))
|
||||
fname := fmt.Sprintf("index-name-%d-%016x", CurrentVersion, h)
|
||||
return fname
|
||||
}
|
178
vendor/golang.org/x/tools/internal/modindex/lookup.go
generated
vendored
Normal file
178
vendor/golang.org/x/tools/internal/modindex/lookup.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
// 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 (
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Candidate struct {
|
||||
PkgName string
|
||||
Name string
|
||||
Dir string
|
||||
ImportPath string
|
||||
Type LexType
|
||||
Deprecated bool
|
||||
// information for Funcs
|
||||
Results int16 // how many results
|
||||
Sig []Field // arg names and types
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
Arg, Type string
|
||||
}
|
||||
|
||||
type LexType int8
|
||||
|
||||
const (
|
||||
Const LexType = iota
|
||||
Var
|
||||
Type
|
||||
Func
|
||||
)
|
||||
|
||||
// LookupAll only returns those Candidates whose import path
|
||||
// finds all the nms.
|
||||
func (ix *Index) LookupAll(pkg string, names ...string) map[string][]Candidate {
|
||||
// this can be made faster when benchmarks show that it needs to be
|
||||
names = uniquify(names)
|
||||
byImpPath := make(map[string][]Candidate)
|
||||
for _, nm := range names {
|
||||
cands := ix.Lookup(pkg, nm, false)
|
||||
for _, c := range cands {
|
||||
byImpPath[c.ImportPath] = append(byImpPath[c.ImportPath], c)
|
||||
}
|
||||
}
|
||||
for k, v := range byImpPath {
|
||||
if len(v) != len(names) {
|
||||
delete(byImpPath, k)
|
||||
}
|
||||
}
|
||||
return byImpPath
|
||||
}
|
||||
|
||||
// remove duplicates
|
||||
func uniquify(in []string) []string {
|
||||
if len(in) == 0 {
|
||||
return in
|
||||
}
|
||||
in = slices.Clone(in)
|
||||
slices.Sort(in)
|
||||
return slices.Compact(in)
|
||||
}
|
||||
|
||||
// Lookup finds all the symbols in the index with the given PkgName and name.
|
||||
// If prefix is true, it finds all of these with name as a prefix.
|
||||
func (ix *Index) Lookup(pkg, name string, prefix bool) []Candidate {
|
||||
loc, ok := slices.BinarySearchFunc(ix.Entries, pkg, func(e Entry, pkg string) int {
|
||||
return strings.Compare(e.PkgName, pkg)
|
||||
})
|
||||
if !ok {
|
||||
return nil // didn't find the package
|
||||
}
|
||||
var ans []Candidate
|
||||
// loc is the first entry for this package name, but there may be severeal
|
||||
for i := loc; i < len(ix.Entries); i++ {
|
||||
e := ix.Entries[i]
|
||||
if e.PkgName != pkg {
|
||||
break // end of sorted package names
|
||||
}
|
||||
nloc, ok := slices.BinarySearchFunc(e.Names, name, func(s string, name string) int {
|
||||
if strings.HasPrefix(s, name) {
|
||||
return 0
|
||||
}
|
||||
if s < name {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
})
|
||||
if !ok {
|
||||
continue // didn't find the name, nor any symbols with name as a prefix
|
||||
}
|
||||
for j := nloc; j < len(e.Names); j++ {
|
||||
nstr := e.Names[j]
|
||||
// benchmarks show this makes a difference when there are a lot of Possibilities
|
||||
flds := fastSplit(nstr)
|
||||
if !(flds[0] == name || prefix && strings.HasPrefix(flds[0], name)) {
|
||||
// past range of matching Names
|
||||
break
|
||||
}
|
||||
if len(flds) < 2 {
|
||||
continue // should never happen
|
||||
}
|
||||
px := Candidate{
|
||||
PkgName: pkg,
|
||||
Name: flds[0],
|
||||
Dir: string(e.Dir),
|
||||
ImportPath: e.ImportPath,
|
||||
Type: asLexType(flds[1][0]),
|
||||
Deprecated: len(flds[1]) > 1 && flds[1][1] == 'D',
|
||||
}
|
||||
if px.Type == Func {
|
||||
n, err := strconv.Atoi(flds[2])
|
||||
if err != nil {
|
||||
continue // should never happen
|
||||
}
|
||||
px.Results = int16(n)
|
||||
if len(flds) >= 4 {
|
||||
sig := strings.Split(flds[3], " ")
|
||||
for i := range sig {
|
||||
// $ cannot otherwise occur. removing the spaces
|
||||
// almost works, but for chan struct{}, e.g.
|
||||
sig[i] = strings.Replace(sig[i], "$", " ", -1)
|
||||
}
|
||||
px.Sig = toFields(sig)
|
||||
}
|
||||
}
|
||||
ans = append(ans, px)
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func toFields(sig []string) []Field {
|
||||
ans := make([]Field, len(sig)/2)
|
||||
for i := range ans {
|
||||
ans[i] = Field{Arg: sig[2*i], Type: sig[2*i+1]}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
// benchmarks show this is measurably better than strings.Split
|
||||
// split into first 4 fields separated by single space
|
||||
func fastSplit(x string) []string {
|
||||
ans := make([]string, 0, 4)
|
||||
nxt := 0
|
||||
start := 0
|
||||
for i := 0; i < len(x); i++ {
|
||||
if x[i] != ' ' {
|
||||
continue
|
||||
}
|
||||
ans = append(ans, x[start:i])
|
||||
nxt++
|
||||
start = i + 1
|
||||
if nxt >= 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
ans = append(ans, x[start:])
|
||||
return ans
|
||||
}
|
||||
|
||||
func asLexType(c byte) LexType {
|
||||
switch c {
|
||||
case 'C':
|
||||
return Const
|
||||
case 'V':
|
||||
return Var
|
||||
case 'T':
|
||||
return Type
|
||||
case 'F':
|
||||
return Func
|
||||
}
|
||||
return -1
|
||||
}
|
164
vendor/golang.org/x/tools/internal/modindex/modindex.go
generated
vendored
Normal file
164
vendor/golang.org/x/tools/internal/modindex/modindex.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// 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 contains code for building and searching an index to
|
||||
// the Go module cache. The directory containing the index, returned by
|
||||
// IndexDir(), contains a file index-name-<ver> that contains the name
|
||||
// of the current index. We believe writing that short file is atomic.
|
||||
// ReadIndex reads that file to get the file name of the index.
|
||||
// WriteIndex writes an index with a unique name and then
|
||||
// writes that name into a new version of index-name-<ver>.
|
||||
// (<ver> stands for the CurrentVersion of the index format.)
|
||||
package modindex
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
// Create always creates a new index for the go module cache that is in cachedir.
|
||||
func Create(cachedir string) error {
|
||||
_, err := indexModCache(cachedir, true)
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the index for the go module cache that is in cachedir,
|
||||
// If there is no existing index it will build one.
|
||||
// If there are changed directories since the last index, it will
|
||||
// write a new one and return true. Otherwise it returns false.
|
||||
func Update(cachedir string) (bool, error) {
|
||||
return indexModCache(cachedir, false)
|
||||
}
|
||||
|
||||
// indexModCache writes an index current as of when it is called.
|
||||
// If clear is true the index is constructed from all of GOMODCACHE
|
||||
// otherwise the index is constructed from the last previous index
|
||||
// and the updates to the cache. It returns true if it wrote an index,
|
||||
// false otherwise.
|
||||
func indexModCache(cachedir string, clear bool) (bool, error) {
|
||||
cachedir, err := filepath.Abs(cachedir)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
cd := Abspath(cachedir)
|
||||
future := time.Now().Add(24 * time.Hour) // safely in the future
|
||||
ok, err := modindexTimed(future, cd, clear)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// modindexTimed writes an index current as of onlyBefore.
|
||||
// If clear is true the index is constructed from all of GOMODCACHE
|
||||
// otherwise the index is constructed from the last previous index
|
||||
// and all the updates to the cache before onlyBefore.
|
||||
// It returns true if it wrote a new index, false if it wrote nothing.
|
||||
func modindexTimed(onlyBefore time.Time, cachedir Abspath, clear bool) (bool, error) {
|
||||
var curIndex *Index
|
||||
if !clear {
|
||||
var err error
|
||||
curIndex, err = ReadIndex(string(cachedir))
|
||||
if clear && err != nil {
|
||||
return false, err
|
||||
}
|
||||
// TODO(pjw): check that most of those directories still exist
|
||||
}
|
||||
cfg := &work{
|
||||
onlyBefore: onlyBefore,
|
||||
oldIndex: curIndex,
|
||||
cacheDir: cachedir,
|
||||
}
|
||||
if curIndex != nil {
|
||||
cfg.onlyAfter = curIndex.Changed
|
||||
}
|
||||
if err := cfg.buildIndex(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(cfg.newIndex.Entries) == 0 && curIndex != nil {
|
||||
// no changes from existing curIndex, don't write a new index
|
||||
return false, nil
|
||||
}
|
||||
if err := cfg.writeIndex(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
type work struct {
|
||||
onlyBefore time.Time // do not use directories later than this
|
||||
onlyAfter time.Time // only interested in directories after this
|
||||
// directories from before onlyAfter come from oldIndex
|
||||
oldIndex *Index
|
||||
newIndex *Index
|
||||
cacheDir Abspath
|
||||
}
|
||||
|
||||
func (w *work) buildIndex() error {
|
||||
// The effective date of the new index should be at least
|
||||
// slightly earlier than when the directories are scanned
|
||||
// so set it now.
|
||||
w.newIndex = &Index{Changed: time.Now(), Cachedir: w.cacheDir}
|
||||
dirs := findDirs(string(w.cacheDir), w.onlyAfter, w.onlyBefore)
|
||||
if len(dirs) == 0 {
|
||||
return nil
|
||||
}
|
||||
newdirs, err := byImportPath(dirs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// for each import path it might occur only in newdirs,
|
||||
// only in w.oldIndex, or in both.
|
||||
// If it occurs in both, use the semantically later one
|
||||
if w.oldIndex != nil {
|
||||
for _, e := range w.oldIndex.Entries {
|
||||
found, ok := newdirs[e.ImportPath]
|
||||
if !ok {
|
||||
w.newIndex.Entries = append(w.newIndex.Entries, e)
|
||||
continue // use this one, there is no new one
|
||||
}
|
||||
if semver.Compare(found[0].version, e.Version) > 0 {
|
||||
// use the new one
|
||||
} else {
|
||||
// use the old one, forget the new one
|
||||
w.newIndex.Entries = append(w.newIndex.Entries, e)
|
||||
delete(newdirs, e.ImportPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
// get symbol information for all the new diredtories
|
||||
getSymbols(w.cacheDir, newdirs)
|
||||
// assemble the new index entries
|
||||
for k, v := range newdirs {
|
||||
d := v[0]
|
||||
pkg, names := processSyms(d.syms)
|
||||
if pkg == "" {
|
||||
continue // PJW: does this ever happen?
|
||||
}
|
||||
entry := Entry{
|
||||
PkgName: pkg,
|
||||
Dir: d.path,
|
||||
ImportPath: k,
|
||||
Version: d.version,
|
||||
Names: names,
|
||||
}
|
||||
w.newIndex.Entries = append(w.newIndex.Entries, entry)
|
||||
}
|
||||
// sort the entries in the new index
|
||||
slices.SortFunc(w.newIndex.Entries, func(l, r Entry) int {
|
||||
if n := strings.Compare(l.PkgName, r.PkgName); n != 0 {
|
||||
return n
|
||||
}
|
||||
return strings.Compare(l.ImportPath, r.ImportPath)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *work) writeIndex() error {
|
||||
return writeIndex(w.cacheDir, w.newIndex)
|
||||
}
|
218
vendor/golang.org/x/tools/internal/modindex/symbols.go
generated
vendored
Normal file
218
vendor/golang.org/x/tools/internal/modindex/symbols.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
// 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"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// The name of a symbol contains information about the symbol:
|
||||
// <name> T for types, TD if the type is deprecated
|
||||
// <name> C for consts, CD if the const is deprecated
|
||||
// <name> V for vars, VD if the var is deprecated
|
||||
// and for funcs: <name> F <num of return values> (<arg-name> <arg-type>)*
|
||||
// any spaces in <arg-type> are replaced by $s so that the fields
|
||||
// of the name are space separated. F is replaced by FD if the func
|
||||
// is deprecated.
|
||||
type symbol struct {
|
||||
pkg string // name of the symbols's package
|
||||
name string // declared name
|
||||
kind string // T, C, V, or F, follwed by D if deprecated
|
||||
sig string // signature information, for F
|
||||
}
|
||||
|
||||
// find the symbols for the best directories
|
||||
func getSymbols(cd Abspath, dirs map[string][]*directory) {
|
||||
var g errgroup.Group
|
||||
g.SetLimit(max(2, runtime.GOMAXPROCS(0)/2))
|
||||
for _, vv := range dirs {
|
||||
// throttling some day?
|
||||
d := vv[0]
|
||||
g.Go(func() error {
|
||||
thedir := filepath.Join(string(cd), string(d.path))
|
||||
mode := parser.SkipObjectResolution | parser.ParseComments
|
||||
|
||||
fi, err := os.ReadDir(thedir)
|
||||
if err != nil {
|
||||
return nil // log this someday?
|
||||
}
|
||||
for _, fx := range fi {
|
||||
if !strings.HasSuffix(fx.Name(), ".go") || strings.HasSuffix(fx.Name(), "_test.go") {
|
||||
continue
|
||||
}
|
||||
fname := filepath.Join(thedir, fx.Name())
|
||||
tr, err := parser.ParseFile(token.NewFileSet(), fname, nil, mode)
|
||||
if err != nil {
|
||||
continue // ignore errors, someday log them?
|
||||
}
|
||||
d.syms = append(d.syms, getFileExports(tr)...)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
g.Wait()
|
||||
}
|
||||
|
||||
func getFileExports(f *ast.File) []symbol {
|
||||
pkg := f.Name.Name
|
||||
if pkg == "main" {
|
||||
return nil
|
||||
}
|
||||
var ans []symbol
|
||||
// should we look for //go:build ignore?
|
||||
for _, decl := range f.Decls {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if decl.Recv != nil {
|
||||
// ignore methods, as we are completing package selections
|
||||
continue
|
||||
}
|
||||
name := decl.Name.Name
|
||||
dtype := decl.Type
|
||||
// not looking at dtype.TypeParams. That is, treating
|
||||
// generic functions just like non-generic ones.
|
||||
sig := dtype.Params
|
||||
kind := "F"
|
||||
if isDeprecated(decl.Doc) {
|
||||
kind += "D"
|
||||
}
|
||||
result := []string{fmt.Sprintf("%d", dtype.Results.NumFields())}
|
||||
for _, x := range sig.List {
|
||||
// This code creates a string representing the type.
|
||||
// TODO(pjw): it may be fragile:
|
||||
// 1. x.Type could be nil, perhaps in ill-formed code
|
||||
// 2. ExprString might someday change incompatibly to
|
||||
// include struct tags, which can be arbitrary strings
|
||||
if x.Type == nil {
|
||||
// Can this happen without a parse error? (Files with parse
|
||||
// errors are ignored in getSymbols)
|
||||
continue // maybe report this someday
|
||||
}
|
||||
tp := types.ExprString(x.Type)
|
||||
if len(tp) == 0 {
|
||||
// Can this happen?
|
||||
continue // maybe report this someday
|
||||
}
|
||||
// This is only safe if ExprString never returns anything with a $
|
||||
// The only place a $ can occur seems to be in a struct tag, which
|
||||
// can be an arbitrary string literal, and ExprString does not presently
|
||||
// print struct tags. So for this to happen the type of a formal parameter
|
||||
// has to be a explict struct, e.g. foo(x struct{a int "$"}) and ExprString
|
||||
// would have to show the struct tag. Even testing for this case seems
|
||||
// a waste of effort, but let's remember the possibility
|
||||
if strings.Contains(tp, "$") {
|
||||
continue
|
||||
}
|
||||
tp = strings.Replace(tp, " ", "$", -1)
|
||||
if len(x.Names) == 0 {
|
||||
result = append(result, "_")
|
||||
result = append(result, tp)
|
||||
} else {
|
||||
for _, y := range x.Names {
|
||||
result = append(result, y.Name)
|
||||
result = append(result, tp)
|
||||
}
|
||||
}
|
||||
}
|
||||
sigs := strings.Join(result, " ")
|
||||
if s := newsym(pkg, name, kind, sigs); s != nil {
|
||||
ans = append(ans, *s)
|
||||
}
|
||||
case *ast.GenDecl:
|
||||
depr := isDeprecated(decl.Doc)
|
||||
switch decl.Tok {
|
||||
case token.CONST, token.VAR:
|
||||
tp := "V"
|
||||
if decl.Tok == token.CONST {
|
||||
tp = "C"
|
||||
}
|
||||
if depr {
|
||||
tp += "D"
|
||||
}
|
||||
for _, sp := range decl.Specs {
|
||||
for _, x := range sp.(*ast.ValueSpec).Names {
|
||||
if s := newsym(pkg, x.Name, tp, ""); s != nil {
|
||||
ans = append(ans, *s)
|
||||
}
|
||||
}
|
||||
}
|
||||
case token.TYPE:
|
||||
tp := "T"
|
||||
if depr {
|
||||
tp += "D"
|
||||
}
|
||||
for _, sp := range decl.Specs {
|
||||
if s := newsym(pkg, sp.(*ast.TypeSpec).Name.Name, tp, ""); s != nil {
|
||||
ans = append(ans, *s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func newsym(pkg, name, kind, sig string) *symbol {
|
||||
if len(name) == 0 || !ast.IsExported(name) {
|
||||
return nil
|
||||
}
|
||||
sym := symbol{pkg: pkg, name: name, kind: kind, sig: sig}
|
||||
return &sym
|
||||
}
|
||||
|
||||
func isDeprecated(doc *ast.CommentGroup) bool {
|
||||
if doc == nil {
|
||||
return false
|
||||
}
|
||||
// go.dev/wiki/Deprecated Paragraph starting 'Deprecated:'
|
||||
// This code fails for /* Deprecated: */, but it's the code from
|
||||
// gopls/internal/analysis/deprecated
|
||||
lines := strings.Split(doc.Text(), "\n\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "Deprecated:") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// return the package name and the value for the symbols.
|
||||
// if there are multiple packages, choose one arbitrarily
|
||||
// the returned slice is sorted lexicographically
|
||||
func processSyms(syms []symbol) (string, []string) {
|
||||
if len(syms) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
slices.SortFunc(syms, func(l, r symbol) int {
|
||||
return strings.Compare(l.name, r.name)
|
||||
})
|
||||
pkg := syms[0].pkg
|
||||
var names []string
|
||||
for _, s := range syms {
|
||||
var nx string
|
||||
if s.pkg == pkg {
|
||||
if s.sig != "" {
|
||||
nx = fmt.Sprintf("%s %s %s", s.name, s.kind, s.sig)
|
||||
} else {
|
||||
nx = fmt.Sprintf("%s %s", s.name, s.kind)
|
||||
}
|
||||
names = append(names, nx)
|
||||
} else {
|
||||
continue // PJW: do we want to keep track of these?
|
||||
}
|
||||
}
|
||||
return pkg, names
|
||||
}
|
25
vendor/golang.org/x/tools/internal/modindex/types.go
generated
vendored
Normal file
25
vendor/golang.org/x/tools/internal/modindex/types.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// 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 (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// some special types to avoid confusions
|
||||
|
||||
// distinguish various types of directory names. It's easy to get confused.
|
||||
type Abspath string // absolute paths
|
||||
type Relpath string // paths with GOMODCACHE prefix removed
|
||||
|
||||
func toRelpath(cachedir Abspath, s string) Relpath {
|
||||
if strings.HasPrefix(s, string(cachedir)) {
|
||||
if s == string(cachedir) {
|
||||
return Relpath("")
|
||||
}
|
||||
return Relpath(s[len(cachedir)+1:])
|
||||
}
|
||||
return Relpath(s)
|
||||
}
|
Reference in New Issue
Block a user