github.com/gernest/nezuko@v0.1.2/internal/modload/load.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package modload
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"go/build"
    12  	"io/ioutil"
    13  	"os"
    14  	"path"
    15  	"path/filepath"
    16  	"sort"
    17  	"strings"
    18  	"sync"
    19  
    20  	"github.com/gernest/nezuko/internal/base"
    21  	"github.com/gernest/nezuko/internal/cfg"
    22  	"github.com/gernest/nezuko/internal/imports"
    23  	"github.com/gernest/nezuko/internal/modfetch"
    24  	"github.com/gernest/nezuko/internal/modfile"
    25  	"github.com/gernest/nezuko/internal/module"
    26  	"github.com/gernest/nezuko/internal/mvs"
    27  	"github.com/gernest/nezuko/internal/par"
    28  	"github.com/gernest/nezuko/internal/search"
    29  	"github.com/gernest/nezuko/internal/semver"
    30  	"github.com/gernest/nezuko/internal/str"
    31  )
    32  
    33  // buildList is the list of modules to use for building packages.
    34  // It is initialized by calling ImportPaths, ImportFromFiles,
    35  // LoadALL, or LoadBuildList, each of which uses loaded.load.
    36  //
    37  // Ideally, exactly ONE of those functions would be called,
    38  // and exactly once. Most of the time, that's true.
    39  // During "go get" it may not be. TODO(rsc): Figure out if
    40  // that restriction can be established, or else document why not.
    41  //
    42  var buildList []module.Version
    43  
    44  // loaded is the most recently-used package loader.
    45  // It holds details about individual packages.
    46  //
    47  // Note that loaded.buildList is only valid during a load operation;
    48  // afterward, it is copied back into the global buildList,
    49  // which should be used instead.
    50  var loaded *loader
    51  
    52  // ImportPaths returns the set of packages matching the args (patterns),
    53  // adding modules to the build list as needed to satisfy new imports.
    54  func ImportPaths(patterns []string) []*search.Match {
    55  	InitMod()
    56  
    57  	var matches []*search.Match
    58  	for _, pattern := range search.CleanPatterns(patterns) {
    59  		m := &search.Match{
    60  			Pattern: pattern,
    61  			Literal: !strings.Contains(pattern, "...") && !search.IsMetaPackage(pattern),
    62  		}
    63  		if m.Literal {
    64  			m.Pkgs = []string{pattern}
    65  		}
    66  		matches = append(matches, m)
    67  	}
    68  
    69  	fsDirs := make([][]string, len(matches))
    70  	loaded = newLoader()
    71  	updateMatches := func(iterating bool) {
    72  		for i, m := range matches {
    73  			switch {
    74  			case build.IsLocalImport(m.Pattern) || filepath.IsAbs(m.Pattern):
    75  				// Evaluate list of file system directories on first iteration.
    76  				if fsDirs[i] == nil {
    77  					var dirs []string
    78  					if m.Literal {
    79  						dirs = []string{m.Pattern}
    80  					} else {
    81  						dirs = search.MatchPackagesInFS(m.Pattern).Pkgs
    82  					}
    83  					fsDirs[i] = dirs
    84  				}
    85  
    86  				// Make a copy of the directory list and translate to import paths.
    87  				// Note that whether a directory corresponds to an import path
    88  				// changes as the build list is updated, and a directory can change
    89  				// from not being in the build list to being in it and back as
    90  				// the exact version of a particular module increases during
    91  				// the loader iterations.
    92  				m.Pkgs = str.StringList(fsDirs[i])
    93  				for j, pkg := range m.Pkgs {
    94  					dir := pkg
    95  					if !filepath.IsAbs(dir) {
    96  						dir = filepath.Join(cwd, pkg)
    97  					} else {
    98  						dir = filepath.Clean(dir)
    99  					}
   100  
   101  					// Note: The checks for @ here are just to avoid misinterpreting
   102  					// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
   103  					// It's not strictly necessary but helpful to keep the checks.
   104  					if modRoot != "" && dir == modRoot {
   105  						pkg = Target.Path
   106  					} else if modRoot != "" && strings.HasPrefix(dir, modRoot+string(filepath.Separator)) && !strings.Contains(dir[len(modRoot):], "@") {
   107  						suffix := filepath.ToSlash(dir[len(modRoot):])
   108  						if strings.HasPrefix(suffix, "/vendor/") {
   109  							// TODO getmode vendor check
   110  							pkg = strings.TrimPrefix(suffix, "/vendor/")
   111  						} else {
   112  							pkg = Target.Path + suffix
   113  						}
   114  					} else if path := pathInModuleCache(dir); path != "" {
   115  						pkg = path
   116  					} else {
   117  						pkg = ""
   118  						if !iterating {
   119  							ModRoot()
   120  							base.Errorf("z: directory %s outside available modules", base.ShortPath(dir))
   121  						}
   122  					}
   123  					info, err := os.Stat(dir)
   124  					if err != nil || !info.IsDir() {
   125  						// If the directory is local but does not exist, don't return it
   126  						// while loader is iterating, since this would trigger a fetch.
   127  						// After loader is done iterating, we still need to return the
   128  						// path, so that "go list -e" produces valid output.
   129  						if iterating {
   130  							pkg = ""
   131  						}
   132  					}
   133  					m.Pkgs[j] = pkg
   134  				}
   135  
   136  			case strings.Contains(m.Pattern, "..."):
   137  				m.Pkgs = matchPackages(m.Pattern, loaded.tags, true, buildList)
   138  
   139  			case m.Pattern == "all":
   140  				loaded.testAll = true
   141  				if iterating {
   142  					// Enumerate the packages in the main module.
   143  					// We'll load the dependencies as we find them.
   144  					m.Pkgs = matchPackages("...", loaded.tags, false, []module.Version{Target})
   145  				} else {
   146  					// Starting with the packages in the main module,
   147  					// enumerate the full list of "all".
   148  					m.Pkgs = loaded.computePatternAll(m.Pkgs)
   149  				}
   150  
   151  			case search.IsMetaPackage(m.Pattern): // std, cmd
   152  				if len(m.Pkgs) == 0 {
   153  					m.Pkgs = search.MatchPackages(m.Pattern).Pkgs
   154  				}
   155  			}
   156  		}
   157  	}
   158  
   159  	loaded.load(func() []string {
   160  		var roots []string
   161  		updateMatches(true)
   162  		for _, m := range matches {
   163  			for _, pkg := range m.Pkgs {
   164  				if pkg != "" {
   165  					roots = append(roots, pkg)
   166  				}
   167  			}
   168  		}
   169  		return roots
   170  	})
   171  
   172  	// One last pass to finalize wildcards.
   173  	updateMatches(false)
   174  
   175  	// A given module path may be used as itself or as a replacement for another
   176  	// module, but not both at the same time. Otherwise, the aliasing behavior is
   177  	// too subtle (see https://golang.org/issue/26607), and we don't want to
   178  	// commit to a specific behavior at this point.
   179  	firstPath := make(map[module.Version]string, len(buildList))
   180  	for _, mod := range buildList {
   181  		src := mod
   182  		if rep := Replacement(mod); rep.Path != "" {
   183  			src = rep
   184  		}
   185  		if prev, ok := firstPath[src]; !ok {
   186  			firstPath[src] = mod.Path
   187  		} else if prev != mod.Path {
   188  			base.Errorf("z: %s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path)
   189  		}
   190  	}
   191  	base.ExitIfErrors()
   192  	WriteGoMod()
   193  
   194  	search.WarnUnmatched(matches)
   195  	return matches
   196  }
   197  
   198  // pathInModuleCache returns the import path of the directory dir,
   199  // if dir is in the module cache copy of a module in our build list.
   200  func pathInModuleCache(dir string) string {
   201  	for _, m := range buildList[1:] {
   202  		root, err := modfetch.DownloadDir(m)
   203  		if err != nil {
   204  			continue
   205  		}
   206  		if sub := search.InDir(dir, root); sub != "" {
   207  			sub = filepath.ToSlash(sub)
   208  			if !strings.Contains(sub, "/vendor/") && !strings.HasPrefix(sub, "vendor/") && !strings.Contains(sub, "@") {
   209  				return path.Join(m.Path, filepath.ToSlash(sub))
   210  			}
   211  		}
   212  	}
   213  	return ""
   214  }
   215  
   216  // warnPattern returns list, the result of matching pattern,
   217  // but if list is empty then first it prints a warning about
   218  // the pattern not matching any packages.
   219  func warnPattern(pattern string, list []string) []string {
   220  	if len(list) == 0 {
   221  		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
   222  	}
   223  	return list
   224  }
   225  
   226  // ImportFromFiles adds modules to the build list as needed
   227  // to satisfy the imports in the named Go source files.
   228  func ImportFromFiles(gofiles []string) {
   229  	InitMod()
   230  	imports, testImports, err := imports.ScanFiles(gofiles, imports.Tags())
   231  	if err != nil {
   232  		base.Fatalf("z: %v", err)
   233  	}
   234  
   235  	loaded = newLoader()
   236  	loaded.load(func() []string {
   237  		var roots []string
   238  		roots = append(roots, imports...)
   239  		roots = append(roots, testImports...)
   240  		return roots
   241  	})
   242  	WriteGoMod()
   243  }
   244  
   245  // DirImportPath returns the effective import path for dir,
   246  // provided it is within the main module, or else returns ".".
   247  func DirImportPath(dir string) string {
   248  	if modRoot == "" {
   249  		return "."
   250  	}
   251  
   252  	if !filepath.IsAbs(dir) {
   253  		dir = filepath.Join(cwd, dir)
   254  	} else {
   255  		dir = filepath.Clean(dir)
   256  	}
   257  
   258  	if dir == modRoot {
   259  		return Target.Path
   260  	}
   261  	if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
   262  		suffix := filepath.ToSlash(dir[len(modRoot):])
   263  		if strings.HasPrefix(suffix, "/vendor/") {
   264  			return strings.TrimPrefix(suffix, "/vendor/")
   265  		}
   266  		return Target.Path + suffix
   267  	}
   268  	return "."
   269  }
   270  
   271  // LoadBuildList loads and returns the build list from z.mod.
   272  // The loading of the build list happens automatically in ImportPaths:
   273  // LoadBuildList need only be called if ImportPaths is not
   274  // (typically in commands that care about the module but
   275  // no particular package).
   276  func LoadBuildList() []module.Version {
   277  	InitMod()
   278  	ReloadBuildList()
   279  	WriteGoMod()
   280  	return buildList
   281  }
   282  
   283  func ReloadBuildList() []module.Version {
   284  	loaded = newLoader()
   285  	loaded.load(func() []string { return nil })
   286  	return buildList
   287  }
   288  
   289  // LoadALL returns the set of all packages in the current module
   290  // and their dependencies in any other modules, without filtering
   291  // due to build tags, except "+build ignore".
   292  // It adds modules to the build list as needed to satisfy new imports.
   293  // This set is useful for deciding whether a particular import is needed
   294  // anywhere in a module.
   295  func LoadALL() []string {
   296  	return loadAll(true)
   297  }
   298  
   299  // LoadVendor is like LoadALL but only follows test dependencies
   300  // for tests in the main module. Tests in dependency modules are
   301  // ignored completely.
   302  // This set is useful for identifying the which packages to include in a vendor directory.
   303  func LoadVendor() []string {
   304  	return loadAll(false)
   305  }
   306  
   307  func loadAll(testAll bool) []string {
   308  	InitMod()
   309  
   310  	loaded = newLoader()
   311  	loaded.isALL = true
   312  	loaded.tags = anyTags
   313  	loaded.testAll = testAll
   314  	if !testAll {
   315  		loaded.testRoots = true
   316  	}
   317  	all := []string{Target.Path}
   318  	loaded.load(func() []string { return all })
   319  	WriteGoMod()
   320  
   321  	var paths []string
   322  	for _, pkg := range loaded.pkgs {
   323  		if e, ok := pkg.err.(*ImportMissingError); ok && e.Module.Path == "" {
   324  			continue // Package doesn't actually exist.
   325  		}
   326  		paths = append(paths, pkg.path)
   327  	}
   328  	return paths
   329  }
   330  
   331  // anyTags is a special tags map that satisfies nearly all build tag expressions.
   332  // Only "ignore" and malformed build tag requirements are considered false.
   333  var anyTags = map[string]bool{"*": true}
   334  
   335  // TargetPackages returns the list of packages in the target (top-level) module,
   336  // under all build tag settings.
   337  func TargetPackages() []string {
   338  	return matchPackages("...", anyTags, false, []module.Version{Target})
   339  }
   340  
   341  // BuildList returns the module build list,
   342  // typically constructed by a previous call to
   343  // LoadBuildList or ImportPaths.
   344  // The caller must not modify the returned list.
   345  func BuildList() []module.Version {
   346  	return buildList
   347  }
   348  
   349  // SetBuildList sets the module build list.
   350  // The caller is responsible for ensuring that the list is valid.
   351  // SetBuildList does not retain a reference to the original list.
   352  func SetBuildList(list []module.Version) {
   353  	buildList = append([]module.Version{}, list...)
   354  }
   355  
   356  // ImportMap returns the actual package import path
   357  // for an import path found in source code.
   358  // If the given import path does not appear in the source code
   359  // for the packages that have been loaded, ImportMap returns the empty string.
   360  func ImportMap(path string) string {
   361  	pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
   362  	if !ok {
   363  		return ""
   364  	}
   365  	return pkg.path
   366  }
   367  
   368  // PackageDir returns the directory containing the source code
   369  // for the package named by the import path.
   370  func PackageDir(path string) string {
   371  	pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
   372  	if !ok {
   373  		return ""
   374  	}
   375  	return pkg.dir
   376  }
   377  
   378  // PackageModule returns the module providing the package named by the import path.
   379  func PackageModule(path string) module.Version {
   380  	pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
   381  	if !ok {
   382  		return module.Version{}
   383  	}
   384  	return pkg.mod
   385  }
   386  
   387  // ModuleUsedDirectly reports whether the main module directly imports
   388  // some package in the module with the given path.
   389  func ModuleUsedDirectly(path string) bool {
   390  	return loaded.direct[path]
   391  }
   392  
   393  // Lookup returns the source directory, import path, and any loading error for
   394  // the package at path.
   395  // Lookup requires that one of the Load functions in this package has already
   396  // been called.
   397  func Lookup(path string) (dir, realPath string, err error) {
   398  	if path == "" {
   399  		panic("Lookup called with empty package path")
   400  	}
   401  	pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
   402  	if !ok {
   403  		// The loader should have found all the relevant paths.
   404  		// There are a few exceptions, though:
   405  		//	- during go list without -test, the p.Resolve calls to process p.TestImports and p.XTestImports
   406  		//	  end up here to canonicalize the import paths.
   407  		//	- during any load, non-loaded packages like "unsafe" end up here.
   408  		//	- during any load, build-injected dependencies like "runtime/cgo" end up here.
   409  		//	- because we ignore appengine/* in the module loader,
   410  		//	  the dependencies of any actual appengine/* library end up here.
   411  		dir := findStandardImportPath(path)
   412  		if dir != "" {
   413  			return dir, path, nil
   414  		}
   415  		return "", "", errMissing
   416  	}
   417  	return pkg.dir, pkg.path, pkg.err
   418  }
   419  
   420  // A loader manages the process of loading information about
   421  // the required packages for a particular build,
   422  // checking that the packages are available in the module set,
   423  // and updating the module set if needed.
   424  // Loading is an iterative process: try to load all the needed packages,
   425  // but if imports are missing, try to resolve those imports, and repeat.
   426  //
   427  // Although most of the loading state is maintained in the loader struct,
   428  // one key piece - the build list - is a global, so that it can be modified
   429  // separate from the loading operation, such as during "go get"
   430  // upgrades/downgrades or in "z mod" operations.
   431  // TODO(rsc): It might be nice to make the loader take and return
   432  // a buildList rather than hard-coding use of the global.
   433  type loader struct {
   434  	tags      map[string]bool // tags for scanDir
   435  	testRoots bool            // include tests for roots
   436  	isALL     bool            // created with LoadALL
   437  	testAll   bool            // include tests for all packages
   438  
   439  	// reset on each iteration
   440  	roots    []*loadPkg
   441  	pkgs     []*loadPkg
   442  	work     *par.Work  // current work queue
   443  	pkgCache *par.Cache // map from string to *loadPkg
   444  
   445  	// computed at end of iterations
   446  	direct  map[string]bool // imported directly by main module
   447  	exports map[string]string
   448  }
   449  
   450  // LoadTests controls whether the loaders load tests of the root packages.
   451  var LoadTests bool
   452  
   453  func newLoader() *loader {
   454  	ld := new(loader)
   455  	ld.tags = imports.Tags()
   456  	ld.testRoots = LoadTests
   457  	return ld
   458  }
   459  
   460  func (ld *loader) reset() {
   461  	ld.roots = nil
   462  	ld.pkgs = nil
   463  	ld.work = new(par.Work)
   464  	ld.pkgCache = new(par.Cache)
   465  }
   466  
   467  // A loadPkg records information about a single loaded package.
   468  type loadPkg struct {
   469  	path        string         // import path
   470  	mod         module.Version // module providing package
   471  	modFile     *modfile.File
   472  	entryFile   string
   473  	exports     string
   474  	dir         string     // directory containing source code
   475  	imports     []*loadPkg // packages imported by this one
   476  	err         error      // error loading package
   477  	stack       *loadPkg   // package importing this one in minimal import stack for this pkg
   478  	test        *loadPkg   // package with test imports, if we need test
   479  	testOf      *loadPkg
   480  	testImports []string // test-only imports, saved for use by pkg.test.
   481  }
   482  
   483  var errMissing = errors.New("cannot find package")
   484  
   485  // load attempts to load the build graph needed to process a set of root packages.
   486  // The set of root packages is defined by the addRoots function,
   487  // which must call add(path) with the import path of each root package.
   488  func (ld *loader) load(roots func() []string) {
   489  	var err error
   490  	reqs := Reqs()
   491  	buildList, err = mvs.BuildList(Target, reqs)
   492  	if err != nil {
   493  		base.Fatalf("z: %v", err)
   494  	}
   495  
   496  	added := make(map[string]bool)
   497  	for {
   498  		ld.reset()
   499  		if roots != nil {
   500  			// Note: the returned roots can change on each iteration,
   501  			// since the expansion of package patterns depends on the
   502  			// build list we're using.
   503  			for _, path := range roots() {
   504  				ld.work.Add(ld.pkg(path, true))
   505  			}
   506  		}
   507  		ld.work.Do(10, ld.doPkg)
   508  		ld.buildStacks()
   509  		numAdded := 0
   510  		haveMod := make(map[module.Version]bool)
   511  		for _, m := range buildList {
   512  			haveMod[m] = true
   513  		}
   514  		for _, pkg := range ld.pkgs {
   515  			if err, ok := pkg.err.(*ImportMissingError); ok && err.Module.Path != "" {
   516  				if added[pkg.path] {
   517  					base.Fatalf("z: %s: looping trying to add package", pkg.stackText())
   518  				}
   519  				added[pkg.path] = true
   520  				numAdded++
   521  				if !haveMod[err.Module] {
   522  					haveMod[err.Module] = true
   523  					buildList = append(buildList, err.Module)
   524  				}
   525  				continue
   526  			}
   527  			// Leave other errors for Import or load.Packages to report.
   528  		}
   529  		base.ExitIfErrors()
   530  		if numAdded == 0 {
   531  			break
   532  		}
   533  
   534  		// Recompute buildList with all our additions.
   535  		reqs = Reqs()
   536  		buildList, err = mvs.BuildList(Target, reqs)
   537  		if err != nil {
   538  			base.Fatalf("z: %v", err)
   539  		}
   540  	}
   541  	base.ExitIfErrors()
   542  
   543  	// Compute directly referenced dependency modules.
   544  	ld.direct = make(map[string]bool)
   545  	for _, pkg := range ld.pkgs {
   546  		if pkg.mod == Target {
   547  			for _, dep := range pkg.imports {
   548  				if dep.mod.Path != "" {
   549  					ld.direct[dep.mod.Path] = true
   550  				}
   551  			}
   552  		}
   553  	}
   554  
   555  	// Add Go versions, computed during walk.
   556  	ld.exports = make(map[string]string)
   557  	for _, m := range buildList {
   558  		v, _ := reqs.(*mvsReqs).exports.Load(m)
   559  		ld.exports[m.Path], _ = v.(string)
   560  	}
   561  
   562  	// Mix in direct markings (really, lack of indirect markings)
   563  	// from z.mod, unless we scanned the whole module
   564  	// and can therefore be sure we know better than z.mod.
   565  	if !ld.isALL && modFile != nil {
   566  		for _, r := range modFile.Require {
   567  			if !r.Indirect {
   568  				ld.direct[r.Mod.Path] = true
   569  			}
   570  		}
   571  	}
   572  }
   573  
   574  // pkg returns the *loadPkg for path, creating and queuing it if needed.
   575  // If the package should be tested, its test is created but not queued
   576  // (the test is queued after processing pkg).
   577  // If isRoot is true, the pkg is being queued as one of the roots of the work graph.
   578  func (ld *loader) pkg(path string, isRoot bool) *loadPkg {
   579  	return ld.pkgCache.Do(path, func() interface{} {
   580  		pkg := &loadPkg{
   581  			path: path,
   582  		}
   583  		if ld.testRoots && isRoot || ld.testAll {
   584  			test := &loadPkg{
   585  				path:   path,
   586  				testOf: pkg,
   587  			}
   588  			pkg.test = test
   589  		}
   590  		if isRoot {
   591  			ld.roots = append(ld.roots, pkg)
   592  		}
   593  		ld.work.Add(pkg)
   594  		return pkg
   595  	}).(*loadPkg)
   596  }
   597  
   598  // doPkg processes a package on the work queue.
   599  func (ld *loader) doPkg(item interface{}) {
   600  	// TODO: what about replacements?
   601  	pkg := item.(*loadPkg)
   602  	if strings.Contains(pkg.path, "@") {
   603  		// Leave for error during load.
   604  		return
   605  	}
   606  	if build.IsLocalImport(pkg.path) {
   607  		// Leave for error during load.
   608  		// (Module mode does not allow local imports.)
   609  		return
   610  	}
   611  
   612  	pkg.mod, pkg.dir, pkg.err = Import(pkg.path)
   613  	if pkg.dir == "" {
   614  		return
   615  	}
   616  	var err error
   617  	gomod := filepath.Join(pkg.dir, "z.mod")
   618  	data, err := ioutil.ReadFile(gomod)
   619  	if err != nil {
   620  		pkg.err = err
   621  		return
   622  	}
   623  
   624  	f, err := modfile.Parse(gomod, data, fixVersion)
   625  	if err != nil {
   626  		pkg.err = err
   627  		return
   628  	}
   629  	pkg.modFile = f
   630  	var entries []string
   631  	if f.Exports == nil {
   632  		pkg.err = errors.New("missing exports on package z.mod file")
   633  		return
   634  	}
   635  	if f.Exports != nil {
   636  		entries = append(entries, f.Exports.Name+".zig")
   637  		pkg.exports = f.Exports.Name
   638  	}
   639  	entries = append(entries, "lib.zig", "main.zig")
   640  	for _, entry := range entries {
   641  		n := cfg.BuildContext.JoinPath(pkg.dir, "src", entry)
   642  		if cfg.BuildContext.IsFile(n) {
   643  			pkg.entryFile = n
   644  			break
   645  		}
   646  	}
   647  	for _, r := range f.Require {
   648  		pkg.imports = append(pkg.imports, ld.pkg(r.Mod.Path, false))
   649  	}
   650  }
   651  
   652  // computePatternAll returns the list of packages matching pattern "all",
   653  // starting with a list of the import paths for the packages in the main module.
   654  func (ld *loader) computePatternAll(paths []string) []string {
   655  	seen := make(map[*loadPkg]bool)
   656  	var all []string
   657  	var walk func(*loadPkg)
   658  	walk = func(pkg *loadPkg) {
   659  		if seen[pkg] {
   660  			return
   661  		}
   662  		seen[pkg] = true
   663  		if pkg.testOf == nil {
   664  			all = append(all, pkg.path)
   665  		}
   666  		for _, p := range pkg.imports {
   667  			walk(p)
   668  		}
   669  		if p := pkg.test; p != nil {
   670  			walk(p)
   671  		}
   672  	}
   673  	for _, path := range paths {
   674  		walk(ld.pkg(path, false))
   675  	}
   676  	sort.Strings(all)
   677  
   678  	return all
   679  }
   680  
   681  // scanDir is like imports.ScanDir but elides known magic imports from the list,
   682  // so that we do not go looking for packages that don't really exist.
   683  //
   684  // The standard magic import is "C", for cgo.
   685  //
   686  // The only other known magic imports are appengine and appengine/*.
   687  // These are so old that they predate "go get" and did not use URL-like paths.
   688  // Most code today now uses google.golang.org/appengine instead,
   689  // but not all code has been so updated. When we mostly ignore build tags
   690  // during "go vendor", we look into "// +build appengine" files and
   691  // may see these legacy imports. We drop them so that the module
   692  // search does not look for modules to try to satisfy them.
   693  func scanDir(dir string, tags map[string]bool) (imports_, testImports []string, err error) {
   694  	imports_, testImports, err = imports.ScanDir(dir, tags)
   695  
   696  	filter := func(x []string) []string {
   697  		w := 0
   698  		for _, pkg := range x {
   699  			if pkg != "C" && pkg != "appengine" && !strings.HasPrefix(pkg, "appengine/") &&
   700  				pkg != "appengine_internal" && !strings.HasPrefix(pkg, "appengine_internal/") {
   701  				x[w] = pkg
   702  				w++
   703  			}
   704  		}
   705  		return x[:w]
   706  	}
   707  
   708  	return filter(imports_), filter(testImports), err
   709  }
   710  
   711  // buildStacks computes minimal import stacks for each package,
   712  // for use in error messages. When it completes, packages that
   713  // are part of the original root set have pkg.stack == nil,
   714  // and other packages have pkg.stack pointing at the next
   715  // package up the import stack in their minimal chain.
   716  // As a side effect, buildStacks also constructs ld.pkgs,
   717  // the list of all packages loaded.
   718  func (ld *loader) buildStacks() {
   719  	if len(ld.pkgs) > 0 {
   720  		panic("buildStacks")
   721  	}
   722  	for _, pkg := range ld.roots {
   723  		pkg.stack = pkg // sentinel to avoid processing in next loop
   724  		ld.pkgs = append(ld.pkgs, pkg)
   725  	}
   726  	for i := 0; i < len(ld.pkgs); i++ { // not range: appending to ld.pkgs in loop
   727  		pkg := ld.pkgs[i]
   728  		for _, next := range pkg.imports {
   729  			if next.stack == nil {
   730  				next.stack = pkg
   731  				ld.pkgs = append(ld.pkgs, next)
   732  			}
   733  		}
   734  		if next := pkg.test; next != nil && next.stack == nil {
   735  			next.stack = pkg
   736  			ld.pkgs = append(ld.pkgs, next)
   737  		}
   738  	}
   739  	for _, pkg := range ld.roots {
   740  		pkg.stack = nil
   741  	}
   742  }
   743  
   744  // stackText builds the import stack text to use when
   745  // reporting an error in pkg. It has the general form
   746  //
   747  //	import root ->
   748  //		import other ->
   749  //		import other2 ->
   750  //		import pkg
   751  //
   752  func (pkg *loadPkg) stackText() string {
   753  	var stack []*loadPkg
   754  	for p := pkg.stack; p != nil; p = p.stack {
   755  		stack = append(stack, p)
   756  	}
   757  
   758  	var buf bytes.Buffer
   759  	for i := len(stack) - 1; i >= 0; i-- {
   760  		p := stack[i]
   761  		if p.testOf != nil {
   762  			fmt.Fprintf(&buf, "test ->\n\t")
   763  		} else {
   764  			fmt.Fprintf(&buf, "import %q ->\n\t", p.path)
   765  		}
   766  	}
   767  	fmt.Fprintf(&buf, "import %q", pkg.path)
   768  	return buf.String()
   769  }
   770  
   771  // why returns the text to use in "z mod why" output about the given package.
   772  // It is less ornate than the stackText but contains the same information.
   773  func (pkg *loadPkg) why() string {
   774  	var buf strings.Builder
   775  	var stack []*loadPkg
   776  	for p := pkg; p != nil; p = p.stack {
   777  		stack = append(stack, p)
   778  	}
   779  
   780  	for i := len(stack) - 1; i >= 0; i-- {
   781  		p := stack[i]
   782  		if p.testOf != nil {
   783  			fmt.Fprintf(&buf, "%s.test\n", p.testOf.path)
   784  		} else {
   785  			fmt.Fprintf(&buf, "%s\n", p.path)
   786  		}
   787  	}
   788  	return buf.String()
   789  }
   790  
   791  // Why returns the "z mod why" output stanza for the given package,
   792  // without the leading # comment.
   793  // The package graph must have been loaded already, usually by LoadALL.
   794  // If there is no reason for the package to be in the current build,
   795  // Why returns an empty string.
   796  func Why(path string) string {
   797  	pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
   798  	if !ok {
   799  		return ""
   800  	}
   801  	return pkg.why()
   802  }
   803  
   804  // WhyDepth returns the number of steps in the Why listing.
   805  // If there is no reason for the package to be in the current build,
   806  // WhyDepth returns 0.
   807  func WhyDepth(path string) int {
   808  	n := 0
   809  	pkg, _ := loaded.pkgCache.Get(path).(*loadPkg)
   810  	for p := pkg; p != nil; p = p.stack {
   811  		n++
   812  	}
   813  	return n
   814  }
   815  
   816  // Replacement returns the replacement for mod, if any, from z.mod.
   817  // If there is no replacement for mod, Replacement returns
   818  // a module.Version with Path == "".
   819  func Replacement(mod module.Version) module.Version {
   820  	if modFile == nil {
   821  		// Happens during testing and if invoking 'go get' or 'go list' outside a module.
   822  		return module.Version{}
   823  	}
   824  
   825  	var found *modfile.Replace
   826  	for _, r := range modFile.Replace {
   827  		if r.Old.Path == mod.Path && (r.Old.Version == "" || r.Old.Version == mod.Version) {
   828  			found = r // keep going
   829  		}
   830  	}
   831  	if found == nil {
   832  		return module.Version{}
   833  	}
   834  	return found.New
   835  }
   836  
   837  // mvsReqs implements mvs.Reqs for module semantic versions,
   838  // with any exclusions or replacements applied internally.
   839  type mvsReqs struct {
   840  	buildList []module.Version
   841  	cache     par.Cache
   842  	exports   sync.Map
   843  }
   844  
   845  // Reqs returns the current module requirement graph.
   846  // Future calls to SetBuildList do not affect the operation
   847  // of the returned Reqs.
   848  func Reqs() mvs.Reqs {
   849  	r := &mvsReqs{
   850  		buildList: buildList,
   851  	}
   852  	return r
   853  }
   854  
   855  func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
   856  	type cached struct {
   857  		list []module.Version
   858  		err  error
   859  	}
   860  
   861  	c := r.cache.Do(mod, func() interface{} {
   862  		list, err := r.required(mod)
   863  		if err != nil {
   864  			return cached{nil, err}
   865  		}
   866  		for i, mv := range list {
   867  			for excluded[mv] {
   868  				mv1, err := r.next(mv)
   869  				if err != nil {
   870  					return cached{nil, err}
   871  				}
   872  				if mv1.Version == "none" {
   873  					return cached{nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version)}
   874  				}
   875  				mv = mv1
   876  			}
   877  			list[i] = mv
   878  		}
   879  
   880  		return cached{list, nil}
   881  	}).(cached)
   882  
   883  	return c.list, c.err
   884  }
   885  
   886  var vendorOnce sync.Once
   887  
   888  var (
   889  	vendorList []module.Version
   890  	vendorMap  map[string]module.Version
   891  )
   892  
   893  // readVendorList reads the list of vendored modules from vendor/modules.txt.
   894  func readVendorList() {
   895  	vendorOnce.Do(func() {
   896  		vendorList = nil
   897  		vendorMap = make(map[string]module.Version)
   898  		data, _ := ioutil.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt"))
   899  		var m module.Version
   900  		for _, line := range strings.Split(string(data), "\n") {
   901  			if strings.HasPrefix(line, "# ") {
   902  				f := strings.Fields(line)
   903  				m = module.Version{}
   904  				if len(f) == 3 && semver.IsValid(f[2]) {
   905  					m = module.Version{Path: f[1], Version: f[2]}
   906  					vendorList = append(vendorList, m)
   907  				}
   908  			} else if m.Path != "" {
   909  				f := strings.Fields(line)
   910  				if len(f) == 1 {
   911  					vendorMap[f[0]] = m
   912  				}
   913  			}
   914  		}
   915  	})
   916  }
   917  
   918  func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version {
   919  	var list []module.Version
   920  	for _, r := range f.Require {
   921  		list = append(list, r.Mod)
   922  	}
   923  	return list
   924  }
   925  
   926  func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
   927  	if mod == Target {
   928  		if modFile != nil && modFile.Exports != nil {
   929  			r.exports.LoadOrStore(mod, modFile.Exports.Name)
   930  		}
   931  		var list []module.Version
   932  		return append(list, r.buildList[1:]...), nil
   933  	}
   934  
   935  	if cfg.BuildMod == "vendor" {
   936  		// For every module other than the target,
   937  		// return the full list of modules from modules.txt.
   938  		readVendorList()
   939  		return vendorList, nil
   940  	}
   941  
   942  	origPath := mod.Path
   943  	if repl := Replacement(mod); repl.Path != "" {
   944  		if repl.Version == "" {
   945  			// TODO: need to slip the new version into the tags list etc.
   946  			dir := repl.Path
   947  			if !filepath.IsAbs(dir) {
   948  				dir = filepath.Join(ModRoot(), dir)
   949  			}
   950  			gomod := filepath.Join(dir, "z.mod")
   951  			data, err := ioutil.ReadFile(gomod)
   952  			if err != nil {
   953  				base.Errorf("z: parsing %s: %v", base.ShortPath(gomod), err)
   954  				return nil, ErrRequire
   955  			}
   956  			f, err := modfile.ParseLax(gomod, data, nil)
   957  			if err != nil {
   958  				base.Errorf("z: parsing %s: %v", base.ShortPath(gomod), err)
   959  				return nil, ErrRequire
   960  			}
   961  			if f.Exports != nil {
   962  				r.exports.LoadOrStore(mod, f.Exports.Name)
   963  			}
   964  			return r.modFileToList(f), nil
   965  		}
   966  		mod = repl
   967  	}
   968  
   969  	if mod.Version == "none" {
   970  		return nil, nil
   971  	}
   972  
   973  	if !semver.IsValid(mod.Version) {
   974  		// Disallow the broader queries supported by fetch.Lookup.
   975  		base.Fatalf("z: internal error: %s@%s: unexpected invalid semantic version", mod.Path, mod.Version)
   976  	}
   977  
   978  	data, err := modfetch.GoMod(mod.Path, mod.Version)
   979  	if err != nil {
   980  		base.Errorf("z: %s@%s: %v\n", mod.Path, mod.Version, err)
   981  		return nil, ErrRequire
   982  	}
   983  	f, err := modfile.ParseLax("z.mod", data, nil)
   984  	if err != nil {
   985  		base.Errorf("z: %s@%s: parsing z.mod: %v", mod.Path, mod.Version, err)
   986  		return nil, ErrRequire
   987  	}
   988  
   989  	if f.Module == nil {
   990  		base.Errorf("z: %s@%s: parsing z.mod: missing module line", mod.Path, mod.Version)
   991  		return nil, ErrRequire
   992  	}
   993  	if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path {
   994  		base.Errorf("z: %s@%s: parsing z.mod: unexpected module path %q", mod.Path, mod.Version, mpath)
   995  		return nil, ErrRequire
   996  	}
   997  	if f.Exports != nil {
   998  		r.exports.LoadOrStore(mod, f.Exports.Name)
   999  	}
  1000  
  1001  	return r.modFileToList(f), nil
  1002  }
  1003  
  1004  // ErrRequire is the sentinel error returned when Require encounters problems.
  1005  // It prints the problems directly to standard error, so that multiple errors
  1006  // can be displayed easily.
  1007  var ErrRequire = errors.New("error loading module requirements")
  1008  
  1009  func (*mvsReqs) Max(v1, v2 string) string {
  1010  	if v1 != "" && semver.Compare(v1, v2) == -1 {
  1011  		return v2
  1012  	}
  1013  	return v1
  1014  }
  1015  
  1016  // Upgrade is a no-op, here to implement mvs.Reqs.
  1017  // The upgrade logic for go get -u is in ../modget/get.go.
  1018  func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) {
  1019  	return m, nil
  1020  }
  1021  
  1022  func versions(path string) ([]string, error) {
  1023  	// Note: modfetch.Lookup and repo.Versions are cached,
  1024  	// so there's no need for us to add extra caching here.
  1025  	repo, err := modfetch.Lookup(path)
  1026  	if err != nil {
  1027  		return nil, err
  1028  	}
  1029  	return repo.Versions("")
  1030  }
  1031  
  1032  // Previous returns the tagged version of m.Path immediately prior to
  1033  // m.Version, or version "none" if no prior version is tagged.
  1034  func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
  1035  	list, err := versions(m.Path)
  1036  	if err != nil {
  1037  		return module.Version{}, err
  1038  	}
  1039  	i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 })
  1040  	if i > 0 {
  1041  		return module.Version{Path: m.Path, Version: list[i-1]}, nil
  1042  	}
  1043  	return module.Version{Path: m.Path, Version: "none"}, nil
  1044  }
  1045  
  1046  // next returns the next version of m.Path after m.Version.
  1047  // It is only used by the exclusion processing in the Required method,
  1048  // not called directly by MVS.
  1049  func (*mvsReqs) next(m module.Version) (module.Version, error) {
  1050  	list, err := versions(m.Path)
  1051  	if err != nil {
  1052  		return module.Version{}, err
  1053  	}
  1054  	i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 })
  1055  	if i < len(list) {
  1056  		return module.Version{Path: m.Path, Version: list[i]}, nil
  1057  	}
  1058  	return module.Version{Path: m.Path, Version: "none"}, nil
  1059  }
  1060  
  1061  func fetch(mod module.Version) (dir string, isLocal bool, err error) {
  1062  	if mod == Target {
  1063  		return ModRoot(), true, nil
  1064  	}
  1065  	if r := Replacement(mod); r.Path != "" {
  1066  		if r.Version == "" {
  1067  			dir = r.Path
  1068  			if !filepath.IsAbs(dir) {
  1069  				dir = filepath.Join(ModRoot(), dir)
  1070  			}
  1071  			return dir, true, nil
  1072  		}
  1073  		mod = r
  1074  	}
  1075  
  1076  	dir, err = modfetch.Download(mod)
  1077  	return dir, false, err
  1078  }