212 lines
8.2 KiB
Diff
212 lines
8.2 KiB
Diff
From 3593bfc89de341818aefadf365ca615b78a8c958 Mon Sep 17 00:00:00 2001
|
|
From: Vorapol Rinsatitnon <vorapol.r@pm.me>
|
|
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
|
|
|