From 3593bfc89de341818aefadf365ca615b78a8c958 Mon Sep 17 00:00:00 2001 From: Vorapol Rinsatitnon Date: Sun, 22 Sep 2024 00:34:20 +1000 Subject: [PATCH] Restore related GOPATH-mode go get functions --- src/cmd/go/internal/load/pkg.go | 59 +++++++++++++++++++++++++++++++++ src/cmd/go/internal/par/work.go | 38 +++++++++++++++++++++ src/cmd/go/internal/vcs/vcs.go | 39 +++++++++++++++++++--- 3 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 7c402b4..cb38b53 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -604,6 +604,51 @@ func (sp *ImportStack) shorterThan(t []string) bool { // we return the same pointer each time. var packageCache = map[string]*Package{} +// ClearPackageCache clears the in-memory package cache and the preload caches. +// It is only for use by GOPATH-based "go get". +// TODO(jayconrod): When GOPATH-based "go get" is removed, delete this function. +func ClearPackageCache() { + clear(packageCache) + resolvedImportCache.Clear() + packageDataCache.Clear() +} + +// ClearPackageCachePartial clears packages with the given import paths from the +// in-memory package cache and the preload caches. It is only for use by +// GOPATH-based "go get". +// TODO(jayconrod): When GOPATH-based "go get" is removed, delete this function. +func ClearPackageCachePartial(args []string) { + shouldDelete := make(map[string]bool) + for _, arg := range args { + shouldDelete[arg] = true + if p := packageCache[arg]; p != nil { + delete(packageCache, arg) + } + } + resolvedImportCache.DeleteIf(func(key importSpec) bool { + return shouldDelete[key.path] + }) + packageDataCache.DeleteIf(func(key string) bool { + return shouldDelete[key] + }) +} + +// ReloadPackageNoFlags is like LoadImport but makes sure +// not to use the package cache. +// It is only for use by GOPATH-based "go get". +// TODO(rsc): When GOPATH-based "go get" is removed, delete this function. +func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package { + p := packageCache[arg] + if p != nil { + delete(packageCache, arg) + resolvedImportCache.DeleteIf(func(key importSpec) bool { + return key.path == p.ImportPath + }) + packageDataCache.Delete(p.ImportPath) + } + return LoadPackage(context.TODO(), PackageOpts{}, arg, base.Cwd(), stk, nil, 0) +} + // dirToImportPath returns the pseudo-import path we use for a package // outside the Go path. It begins with _/ and then contains the full path // to the directory. If the package lives in c:\home\gopher\my\pkg then @@ -655,6 +700,20 @@ const ( cmdlinePkgLiteral ) +// LoadImport scans the directory named by path, which must be an import path, +// but possibly a local import path (an absolute file system path or one beginning +// with ./ or ../). A local relative path is interpreted relative to srcDir. +// It returns a *Package describing the package found in that directory. +// LoadImport does not set tool flags and should only be used by +// this package, as part of a bigger load operation, and by GOPATH-based "go get". +// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function. +// The returned PackageError, if any, describes why parent is not allowed +// to import the named package, with the error referring to importPos. +// The PackageError can only be non-nil when parent is not nil. +func LoadImport(ctx context.Context, opts PackageOpts, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) { + return loadImport(ctx, opts, nil, path, srcDir, parent, stk, importPos, mode) +} + // LoadPackage does Load import, but without a parent package load contezt func LoadPackage(ctx context.Context, opts PackageOpts, path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package { p, err := loadImport(ctx, opts, nil, path, srcDir, nil, stk, importPos, mode) diff --git a/src/cmd/go/internal/par/work.go b/src/cmd/go/internal/par/work.go index 881b51b..3f1e69a 100644 --- a/src/cmd/go/internal/par/work.go +++ b/src/cmd/go/internal/par/work.go @@ -180,3 +180,41 @@ func (c *Cache[K, V]) Get(key K) (V, bool) { } return e.result, true } + +// Clear removes all entries in the cache. +// +// Concurrent calls to Get may return old values. Concurrent calls to Do +// may return old values or store results in entries that have been deleted. +// +// TODO(jayconrod): Delete this after the package cache clearing functions +// in internal/load have been removed. +func (c *Cache[K, V]) Clear() { + c.m.Clear() +} + +// Delete removes an entry from the map. It is safe to call Delete for an +// entry that does not exist. Delete will return quickly, even if the result +// for a key is still being computed; the computation will finish, but the +// result won't be accessible through the cache. +// +// TODO(jayconrod): Delete this after the package cache clearing functions +// in internal/load have been removed. +func (c *Cache[K, V]) Delete(key K) { + c.m.Delete(key) +} + +// DeleteIf calls pred for each key in the map. If pred returns true for a key, +// DeleteIf removes the corresponding entry. If the result for a key is +// still being computed, DeleteIf will remove the entry without waiting for +// the computation to finish. The result won't be accessible through the cache. +// +// TODO(jayconrod): Delete this after the package cache clearing functions +// in internal/load have been removed. +func (c *Cache[K, V]) DeleteIf(pred func(key K) bool) { + c.m.Range(func(key, _ any) bool { + if key := key.(K); pred(key) { + c.Delete(key) + } + return true + }) +} diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go index 19a6a5e..044d02e 100644 --- a/src/cmd/go/internal/vcs/vcs.go +++ b/src/cmd/go/internal/vcs/vcs.go @@ -1013,11 +1013,11 @@ var defaultGOVCS = govcsConfig{ {"public", []string{"git", "hg"}}, } -// checkGOVCS checks whether the policy defined by the environment variable +// CheckGOVCS checks whether the policy defined by the environment variable // GOVCS allows the given vcs command to be used with the given repository // root path. Note that root may not be a real package or module path; it's // the same as the root path in the go-import meta tag. -func checkGOVCS(vcs *Cmd, root string) error { +func CheckGOVCS(vcs *Cmd, root string) error { if vcs == vcsMod { // Direct module (proxy protocol) fetches don't // involve an external version control system @@ -1045,6 +1045,37 @@ func checkGOVCS(vcs *Cmd, root string) error { return nil } +// CheckNested checks for an incorrectly-nested VCS-inside-VCS +// situation for dir, checking parents up until srcRoot. +func CheckNested(vcs *Cmd, dir, srcRoot string) error { + if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { + return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) + } + + otherDir := dir + for len(otherDir) > len(srcRoot) { + for _, otherVCS := range vcsList { + if isVCSRoot(otherDir, otherVCS.RootNames) { + // Allow expected vcs in original dir. + if otherDir == dir && otherVCS == vcs { + continue + } + // Otherwise, we have one VCS inside a different VCS. + return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.Cmd, otherDir, otherVCS.Cmd) + } + } + // Move to parent. + newDir := filepath.Dir(otherDir) + if len(newDir) >= len(otherDir) { + // Shouldn't happen, but just in case, stop. + break + } + otherDir = newDir + } + + return nil +} + // RepoRoot describes the repository root for a tree of source code. type RepoRoot struct { Repo string // repository URL, including scheme @@ -1160,7 +1191,7 @@ func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths if vcs == nil { return nil, fmt.Errorf("unknown version control system %q", match["vcs"]) } - if err := checkGOVCS(vcs, match["root"]); err != nil { + if err := CheckGOVCS(vcs, match["root"]); err != nil { return nil, err } var repoURL string @@ -1349,7 +1380,7 @@ func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.Se } } - if err := checkGOVCS(vcs, mmi.Prefix); err != nil { + if err := CheckGOVCS(vcs, mmi.Prefix); err != nil { return nil, err } -- 2.47.0