Restore related GOPATH-mode go get functions

This commit is contained in:
Vorapol Rinsatitnon
2024-09-22 00:34:20 +10:00
parent d02338f60a
commit 3593bfc89d
3 changed files with 132 additions and 4 deletions

View File

@@ -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)

View File

@@ -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
})
}

View File

@@ -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
}