github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/get/get.go (about)

     1  // Copyright 2011 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 get implements the ``go get'' command.
     6  package get
     7  
     8  import (
     9  	"fmt"
    10  	"go/build"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  	"strings"
    15  
    16  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/base"
    17  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg"
    18  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/load"
    19  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/search"
    20  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/str"
    21  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/web"
    22  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/work"
    23  )
    24  
    25  var CmdGet = &base.Command{
    26  	UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages]",
    27  	Short:     "download and install packages and dependencies",
    28  	Long: `
    29  Get downloads the packages named by the import paths, along with their
    30  dependencies. It then installs the named packages, like 'go install'.
    31  
    32  The -d flag instructs get to stop after downloading the packages; that is,
    33  it instructs get not to install the packages.
    34  
    35  The -f flag, valid only when -u is set, forces get -u not to verify that
    36  each package has been checked out from the source control repository
    37  implied by its import path. This can be useful if the source is a local fork
    38  of the original.
    39  
    40  The -fix flag instructs get to run the fix tool on the downloaded packages
    41  before resolving dependencies or building the code.
    42  
    43  The -insecure flag permits fetching from repositories and resolving
    44  custom domains using insecure schemes such as HTTP. Use with caution.
    45  
    46  The -t flag instructs get to also download the packages required to build
    47  the tests for the specified packages.
    48  
    49  The -u flag instructs get to use the network to update the named packages
    50  and their dependencies. By default, get uses the network to check out
    51  missing packages but does not use it to look for updates to existing packages.
    52  
    53  The -v flag enables verbose progress and debug output.
    54  
    55  Get also accepts build flags to control the installation. See 'go help build'.
    56  
    57  When checking out a new package, get creates the target directory
    58  GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
    59  get uses the first one. For more details see: 'go help gopath'.
    60  
    61  When checking out or updating a package, get looks for a branch or tag
    62  that matches the locally installed version of Go. The most important
    63  rule is that if the local installation is running version "go1", get
    64  searches for a branch or tag named "go1". If no such version exists
    65  it retrieves the default branch of the package.
    66  
    67  When go get checks out or updates a Git repository,
    68  it also updates any git submodules referenced by the repository.
    69  
    70  Get never checks out or updates code stored in vendor directories.
    71  
    72  For more about specifying packages, see 'go help packages'.
    73  
    74  For more about how 'go get' finds source code to
    75  download, see 'go help importpath'.
    76  
    77  This text describes the behavior of get when using GOPATH
    78  to manage source code and dependencies.
    79  If instead the go command is running in module-aware mode,
    80  the details of get's flags and effects change, as does 'go help get'.
    81  See 'go help modules' and 'go help module-get'.
    82  
    83  See also: go build, go install, go clean.
    84  	`,
    85  }
    86  
    87  var HelpGopathGet = &base.Command{
    88  	UsageLine: "gopath-get",
    89  	Short:     "legacy GOPATH go get",
    90  	Long: `
    91  The 'go get' command changes behavior depending on whether the
    92  go command is running in module-aware mode or legacy GOPATH mode.
    93  This help text, accessible as 'go help gopath-get' even in module-aware mode,
    94  describes 'go get' as it operates in legacy GOPATH mode.
    95  
    96  Usage: ` + CmdGet.UsageLine + `
    97  ` + CmdGet.Long,
    98  }
    99  
   100  var (
   101  	getD   = CmdGet.Flag.Bool("d", false, "")
   102  	getF   = CmdGet.Flag.Bool("f", false, "")
   103  	getT   = CmdGet.Flag.Bool("t", false, "")
   104  	getU   = CmdGet.Flag.Bool("u", false, "")
   105  	getFix = CmdGet.Flag.Bool("fix", false, "")
   106  
   107  	Insecure bool
   108  )
   109  
   110  func init() {
   111  	work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags)
   112  	CmdGet.Run = runGet // break init loop
   113  	CmdGet.Flag.BoolVar(&Insecure, "insecure", Insecure, "")
   114  }
   115  
   116  func runGet(cmd *base.Command, args []string) {
   117  	if cfg.ModulesEnabled {
   118  		// Should not happen: main.go should install the separate module-enabled get code.
   119  		base.Fatalf("go get: modules not implemented")
   120  	}
   121  
   122  	work.BuildInit()
   123  
   124  	if *getF && !*getU {
   125  		base.Fatalf("go get: cannot use -f flag without -u")
   126  	}
   127  
   128  	// Disable any prompting for passwords by Git.
   129  	// Only has an effect for 2.3.0 or later, but avoiding
   130  	// the prompt in earlier versions is just too hard.
   131  	// If user has explicitly set GIT_TERMINAL_PROMPT=1, keep
   132  	// prompting.
   133  	// See golang.org/issue/9341 and golang.org/issue/12706.
   134  	if os.Getenv("GIT_TERMINAL_PROMPT") == "" {
   135  		os.Setenv("GIT_TERMINAL_PROMPT", "0")
   136  	}
   137  
   138  	// Disable any ssh connection pooling by Git.
   139  	// If a Git subprocess forks a child into the background to cache a new connection,
   140  	// that child keeps stdout/stderr open. After the Git subprocess exits,
   141  	// os /exec expects to be able to read from the stdout/stderr pipe
   142  	// until EOF to get all the data that the Git subprocess wrote before exiting.
   143  	// The EOF doesn't come until the child exits too, because the child
   144  	// is holding the write end of the pipe.
   145  	// This is unfortunate, but it has come up at least twice
   146  	// (see golang.org/issue/13453 and golang.org/issue/16104)
   147  	// and confuses users when it does.
   148  	// If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
   149  	// assume they know what they are doing and don't step on it.
   150  	// But default to turning off ControlMaster.
   151  	if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
   152  		os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
   153  	}
   154  
   155  	// Phase 1. Download/update.
   156  	var stk load.ImportStack
   157  	mode := 0
   158  	if *getT {
   159  		mode |= load.GetTestDeps
   160  	}
   161  	for _, pkg := range downloadPaths(args) {
   162  		download(pkg, nil, &stk, mode)
   163  	}
   164  	base.ExitIfErrors()
   165  
   166  	// Phase 2. Rescan packages and re-evaluate args list.
   167  
   168  	// Code we downloaded and all code that depends on it
   169  	// needs to be evicted from the package cache so that
   170  	// the information will be recomputed. Instead of keeping
   171  	// track of the reverse dependency information, evict
   172  	// everything.
   173  	load.ClearPackageCache()
   174  
   175  	pkgs := load.PackagesForBuild(args)
   176  
   177  	// Phase 3. Install.
   178  	if *getD {
   179  		// Download only.
   180  		// Check delayed until now so that importPaths
   181  		// and packagesForBuild have a chance to print errors.
   182  		return
   183  	}
   184  
   185  	work.InstallPackages(args, pkgs)
   186  }
   187  
   188  // downloadPaths prepares the list of paths to pass to download.
   189  // It expands ... patterns that can be expanded. If there is no match
   190  // for a particular pattern, downloadPaths leaves it in the result list,
   191  // in the hope that we can figure out the repository from the
   192  // initial ...-free prefix.
   193  func downloadPaths(patterns []string) []string {
   194  	for _, arg := range patterns {
   195  		if strings.Contains(arg, "@") {
   196  			base.Fatalf("go: cannot use path@version syntax in GOPATH mode")
   197  		}
   198  	}
   199  	var pkgs []string
   200  	for _, m := range search.ImportPathsQuiet(patterns) {
   201  		if len(m.Pkgs) == 0 && strings.Contains(m.Pattern, "...") {
   202  			pkgs = append(pkgs, m.Pattern)
   203  		} else {
   204  			pkgs = append(pkgs, m.Pkgs...)
   205  		}
   206  	}
   207  	return pkgs
   208  }
   209  
   210  // downloadCache records the import paths we have already
   211  // considered during the download, to avoid duplicate work when
   212  // there is more than one dependency sequence leading to
   213  // a particular package.
   214  var downloadCache = map[string]bool{}
   215  
   216  // downloadRootCache records the version control repository
   217  // root directories we have already considered during the download.
   218  // For example, all the packages in the github.com/google/codesearch repo
   219  // share the same root (the directory for that path), and we only need
   220  // to run the hg commands to consider each repository once.
   221  var downloadRootCache = map[string]bool{}
   222  
   223  // download runs the download half of the get command
   224  // for the package or pattern named by the argument.
   225  func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
   226  	if mode&load.ResolveImport != 0 {
   227  		// Caller is responsible for expanding vendor paths.
   228  		panic("internal error: download mode has useVendor set")
   229  	}
   230  	load1 := func(path string, mode int) *load.Package {
   231  		if parent == nil {
   232  			mode := 0 // don't do module or vendor resolution
   233  			return load.LoadImport(path, base.Cwd, nil, stk, nil, mode)
   234  		}
   235  		return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
   236  	}
   237  
   238  	p := load1(arg, mode)
   239  	if p.Error != nil && p.Error.Hard {
   240  		base.Errorf("%s", p.Error)
   241  		return
   242  	}
   243  
   244  	// loadPackage inferred the canonical ImportPath from arg.
   245  	// Use that in the following to prevent hysteresis effects
   246  	// in e.g. downloadCache and packageCache.
   247  	// This allows invocations such as:
   248  	//   mkdir -p $GOPATH/src/github.com/user
   249  	//   cd $GOPATH/src/github.com/user
   250  	//   go get ./foo
   251  	// see: golang.org/issue/9767
   252  	arg = p.ImportPath
   253  
   254  	// There's nothing to do if this is a package in the standard library.
   255  	if p.Standard {
   256  		return
   257  	}
   258  
   259  	// Only process each package once.
   260  	// (Unless we're fetching test dependencies for this package,
   261  	// in which case we want to process it again.)
   262  	if downloadCache[arg] && mode&load.GetTestDeps == 0 {
   263  		return
   264  	}
   265  	downloadCache[arg] = true
   266  
   267  	pkgs := []*load.Package{p}
   268  	wildcardOkay := len(*stk) == 0
   269  	isWildcard := false
   270  
   271  	// Download if the package is missing, or update if we're using -u.
   272  	if p.Dir == "" || *getU {
   273  		// The actual download.
   274  		stk.Push(arg)
   275  		err := downloadPackage(p)
   276  		if err != nil {
   277  			base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err})
   278  			stk.Pop()
   279  			return
   280  		}
   281  		stk.Pop()
   282  
   283  		args := []string{arg}
   284  		// If the argument has a wildcard in it, re-evaluate the wildcard.
   285  		// We delay this until after reloadPackage so that the old entry
   286  		// for p has been replaced in the package cache.
   287  		if wildcardOkay && strings.Contains(arg, "...") {
   288  			if build.IsLocalImport(arg) {
   289  				args = search.MatchPackagesInFS(arg).Pkgs
   290  			} else {
   291  				args = search.MatchPackages(arg).Pkgs
   292  			}
   293  			isWildcard = true
   294  		}
   295  
   296  		// Clear all relevant package cache entries before
   297  		// doing any new loads.
   298  		load.ClearPackageCachePartial(args)
   299  
   300  		pkgs = pkgs[:0]
   301  		for _, arg := range args {
   302  			// Note: load calls loadPackage or loadImport,
   303  			// which push arg onto stk already.
   304  			// Do not push here too, or else stk will say arg imports arg.
   305  			p := load1(arg, mode)
   306  			if p.Error != nil {
   307  				base.Errorf("%s", p.Error)
   308  				continue
   309  			}
   310  			pkgs = append(pkgs, p)
   311  		}
   312  	}
   313  
   314  	// Process package, which might now be multiple packages
   315  	// due to wildcard expansion.
   316  	for _, p := range pkgs {
   317  		if *getFix {
   318  			files := base.RelPaths(p.InternalAllGoFiles())
   319  			base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files))
   320  
   321  			// The imports might have changed, so reload again.
   322  			p = load.ReloadPackageNoFlags(arg, stk)
   323  			if p.Error != nil {
   324  				base.Errorf("%s", p.Error)
   325  				return
   326  			}
   327  		}
   328  
   329  		if isWildcard {
   330  			// Report both the real package and the
   331  			// wildcard in any error message.
   332  			stk.Push(p.ImportPath)
   333  		}
   334  
   335  		// Process dependencies, now that we know what they are.
   336  		imports := p.Imports
   337  		if mode&load.GetTestDeps != 0 {
   338  			// Process test dependencies when -t is specified.
   339  			// (But don't get test dependencies for test dependencies:
   340  			// we always pass mode 0 to the recursive calls below.)
   341  			imports = str.StringList(imports, p.TestImports, p.XTestImports)
   342  		}
   343  		for i, path := range imports {
   344  			if path == "C" {
   345  				continue
   346  			}
   347  			// Fail fast on import naming full vendor path.
   348  			// Otherwise expand path as needed for test imports.
   349  			// Note that p.Imports can have additional entries beyond p.Internal.Build.Imports.
   350  			orig := path
   351  			if i < len(p.Internal.Build.Imports) {
   352  				orig = p.Internal.Build.Imports[i]
   353  			}
   354  			if j, ok := load.FindVendor(orig); ok {
   355  				stk.Push(path)
   356  				err := &load.PackageError{
   357  					ImportStack: stk.Copy(),
   358  					Err:         load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]),
   359  				}
   360  				stk.Pop()
   361  				base.Errorf("%s", err)
   362  				continue
   363  			}
   364  			// If this is a test import, apply module and vendor lookup now.
   365  			// We cannot pass ResolveImport to download, because
   366  			// download does caching based on the value of path,
   367  			// so it must be the fully qualified path already.
   368  			if i >= len(p.Imports) {
   369  				path = load.ResolveImportPath(p, path)
   370  			}
   371  			download(path, p, stk, 0)
   372  		}
   373  
   374  		if isWildcard {
   375  			stk.Pop()
   376  		}
   377  	}
   378  }
   379  
   380  // downloadPackage runs the create or download command
   381  // to make the first copy of or update a copy of the given package.
   382  func downloadPackage(p *load.Package) error {
   383  	var (
   384  		vcs            *vcsCmd
   385  		repo, rootPath string
   386  		err            error
   387  		blindRepo      bool // set if the repo has unusual configuration
   388  	)
   389  
   390  	security := web.SecureOnly
   391  	if Insecure {
   392  		security = web.Insecure
   393  	}
   394  
   395  	// p can be either a real package, or a pseudo-package whose “import path” is
   396  	// actually a wildcard pattern.
   397  	// Trim the path at the element containing the first wildcard,
   398  	// and hope that it applies to the wildcarded parts too.
   399  	// This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH.
   400  	importPrefix := p.ImportPath
   401  	if i := strings.Index(importPrefix, "..."); i >= 0 {
   402  		slash := strings.LastIndexByte(importPrefix[:i], '/')
   403  		if slash < 0 {
   404  			return fmt.Errorf("cannot expand ... in %q", p.ImportPath)
   405  		}
   406  		importPrefix = importPrefix[:slash]
   407  	}
   408  	if err := CheckImportPath(importPrefix); err != nil {
   409  		return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
   410  	}
   411  
   412  	if p.Internal.Build.SrcRoot != "" {
   413  		// Directory exists. Look for checkout along path to src.
   414  		vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
   415  		if err != nil {
   416  			return err
   417  		}
   418  		repo = "<local>" // should be unused; make distinctive
   419  
   420  		// Double-check where it came from.
   421  		if *getU && vcs.remoteRepo != nil {
   422  			dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
   423  			remote, err := vcs.remoteRepo(vcs, dir)
   424  			if err != nil {
   425  				// Proceed anyway. The package is present; we likely just don't understand
   426  				// the repo configuration (e.g. unusual remote protocol).
   427  				blindRepo = true
   428  			}
   429  			repo = remote
   430  			if !*getF && err == nil {
   431  				if rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security); err == nil {
   432  					repo := rr.Repo
   433  					if rr.vcs.resolveRepo != nil {
   434  						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
   435  						if err == nil {
   436  							repo = resolved
   437  						}
   438  					}
   439  					if remote != repo && rr.IsCustom {
   440  						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote)
   441  					}
   442  				}
   443  			}
   444  		}
   445  	} else {
   446  		// Analyze the import path to determine the version control system,
   447  		// repository, and the import path for the root of the repository.
   448  		rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security)
   449  		if err != nil {
   450  			return err
   451  		}
   452  		vcs, repo, rootPath = rr.vcs, rr.Repo, rr.Root
   453  	}
   454  	if !blindRepo && !vcs.isSecure(repo) && !Insecure {
   455  		return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
   456  	}
   457  
   458  	if p.Internal.Build.SrcRoot == "" {
   459  		// Package not found. Put in first directory of $GOPATH.
   460  		list := filepath.SplitList(cfg.BuildContext.GOPATH)
   461  		if len(list) == 0 {
   462  			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
   463  		}
   464  		// Guard against people setting GOPATH=$GOROOT.
   465  		if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) {
   466  			return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
   467  		}
   468  		if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
   469  			return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
   470  		}
   471  		p.Internal.Build.Root = list[0]
   472  		p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
   473  		p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
   474  	}
   475  	root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
   476  
   477  	if err := checkNestedVCS(vcs, root, p.Internal.Build.SrcRoot); err != nil {
   478  		return err
   479  	}
   480  
   481  	// If we've considered this repository already, don't do it again.
   482  	if downloadRootCache[root] {
   483  		return nil
   484  	}
   485  	downloadRootCache[root] = true
   486  
   487  	if cfg.BuildV {
   488  		fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
   489  	}
   490  
   491  	// Check that this is an appropriate place for the repo to be checked out.
   492  	// The target directory must either not exist or have a repo checked out already.
   493  	meta := filepath.Join(root, "."+vcs.cmd)
   494  	if _, err := os.Stat(meta); err != nil {
   495  		// Metadata file or directory does not exist. Prepare to checkout new copy.
   496  		// Some version control tools require the target directory not to exist.
   497  		// We require that too, just to avoid stepping on existing work.
   498  		if _, err := os.Stat(root); err == nil {
   499  			return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
   500  		}
   501  
   502  		_, err := os.Stat(p.Internal.Build.Root)
   503  		gopathExisted := err == nil
   504  
   505  		// Some version control tools require the parent of the target to exist.
   506  		parent, _ := filepath.Split(root)
   507  		if err = os.MkdirAll(parent, 0777); err != nil {
   508  			return err
   509  		}
   510  		if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
   511  			fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
   512  		}
   513  
   514  		if err = vcs.create(root, repo); err != nil {
   515  			return err
   516  		}
   517  	} else {
   518  		// Metadata directory does exist; download incremental updates.
   519  		if err = vcs.download(root); err != nil {
   520  			return err
   521  		}
   522  	}
   523  
   524  	if cfg.BuildN {
   525  		// Do not show tag sync in -n; it's noise more than anything,
   526  		// and since we're not running commands, no tag will be found.
   527  		// But avoid printing nothing.
   528  		fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
   529  		return nil
   530  	}
   531  
   532  	// Select and sync to appropriate version of the repository.
   533  	tags, err := vcs.tags(root)
   534  	if err != nil {
   535  		return err
   536  	}
   537  	vers := runtime.Version()
   538  	if i := strings.Index(vers, " "); i >= 0 {
   539  		vers = vers[:i]
   540  	}
   541  	if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
   542  		return err
   543  	}
   544  
   545  	return nil
   546  }
   547  
   548  // selectTag returns the closest matching tag for a given version.
   549  // Closest means the latest one that is not after the current release.
   550  // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
   551  // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
   552  // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
   553  //
   554  // NOTE(rsc): Eventually we will need to decide on some logic here.
   555  // For now, there is only "go1". This matches the docs in go help get.
   556  func selectTag(goVersion string, tags []string) (match string) {
   557  	for _, t := range tags {
   558  		if t == "go1" {
   559  			return "go1"
   560  		}
   561  	}
   562  	return ""
   563  }