rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/cmd/go/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 main
     6  
     7  import (
     8  	"fmt"
     9  	"go/build"
    10  	"os"
    11  	"path/filepath"
    12  	"regexp"
    13  	"runtime"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  var cmdGet = &Command{
    19  	UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]",
    20  	Short:     "download and install packages and dependencies",
    21  	Long: `
    22  Get downloads and installs the packages named by the import paths,
    23  along with their dependencies.
    24  
    25  The -d flag instructs get to stop after downloading the packages; that is,
    26  it instructs get not to install the packages.
    27  
    28  The -f flag, valid only when -u is set, forces get -u not to verify that
    29  each package has been checked out from the source control repository
    30  implied by its import path. This can be useful if the source is a local fork
    31  of the original.
    32  
    33  The -fix flag instructs get to run the fix tool on the downloaded packages
    34  before resolving dependencies or building the code.
    35  
    36  The -t flag instructs get to also download the packages required to build
    37  the tests for the specified packages.
    38  
    39  The -u flag instructs get to use the network to update the named packages
    40  and their dependencies.  By default, get uses the network to check out
    41  missing packages but does not use it to look for updates to existing packages.
    42  
    43  Get also accepts build flags to control the installation. See 'go help build'.
    44  
    45  When checking out or updating a package, get looks for a branch or tag
    46  that matches the locally installed version of Go. The most important
    47  rule is that if the local installation is running version "go1", get
    48  searches for a branch or tag named "go1". If no such version exists it
    49  retrieves the most recent version of the package.
    50  
    51  For more about specifying packages, see 'go help packages'.
    52  
    53  For more about how 'go get' finds source code to
    54  download, see 'go help importpath'.
    55  
    56  See also: go build, go install, go clean.
    57  	`,
    58  }
    59  
    60  var getD = cmdGet.Flag.Bool("d", false, "")
    61  var getF = cmdGet.Flag.Bool("f", false, "")
    62  var getT = cmdGet.Flag.Bool("t", false, "")
    63  var getU = cmdGet.Flag.Bool("u", false, "")
    64  var getFix = cmdGet.Flag.Bool("fix", false, "")
    65  
    66  func init() {
    67  	addBuildFlags(cmdGet)
    68  	cmdGet.Run = runGet // break init loop
    69  }
    70  
    71  func runGet(cmd *Command, args []string) {
    72  	if *getF && !*getU {
    73  		fatalf("go get: cannot use -f flag without -u")
    74  	}
    75  
    76  	// Phase 1.  Download/update.
    77  	var stk importStack
    78  	for _, arg := range downloadPaths(args) {
    79  		download(arg, &stk, *getT)
    80  	}
    81  	exitIfErrors()
    82  
    83  	// Phase 2. Rescan packages and re-evaluate args list.
    84  
    85  	// Code we downloaded and all code that depends on it
    86  	// needs to be evicted from the package cache so that
    87  	// the information will be recomputed.  Instead of keeping
    88  	// track of the reverse dependency information, evict
    89  	// everything.
    90  	for name := range packageCache {
    91  		delete(packageCache, name)
    92  	}
    93  
    94  	args = importPaths(args)
    95  
    96  	// Phase 3.  Install.
    97  	if *getD {
    98  		// Download only.
    99  		// Check delayed until now so that importPaths
   100  		// has a chance to print errors.
   101  		return
   102  	}
   103  
   104  	runInstall(cmd, args)
   105  }
   106  
   107  // downloadPaths prepares the list of paths to pass to download.
   108  // It expands ... patterns that can be expanded.  If there is no match
   109  // for a particular pattern, downloadPaths leaves it in the result list,
   110  // in the hope that we can figure out the repository from the
   111  // initial ...-free prefix.
   112  func downloadPaths(args []string) []string {
   113  	args = importPathsNoDotExpansion(args)
   114  	var out []string
   115  	for _, a := range args {
   116  		if strings.Contains(a, "...") {
   117  			var expand []string
   118  			// Use matchPackagesInFS to avoid printing
   119  			// warnings.  They will be printed by the
   120  			// eventual call to importPaths instead.
   121  			if build.IsLocalImport(a) {
   122  				expand = matchPackagesInFS(a)
   123  			} else {
   124  				expand = matchPackages(a)
   125  			}
   126  			if len(expand) > 0 {
   127  				out = append(out, expand...)
   128  				continue
   129  			}
   130  		}
   131  		out = append(out, a)
   132  	}
   133  	return out
   134  }
   135  
   136  // downloadCache records the import paths we have already
   137  // considered during the download, to avoid duplicate work when
   138  // there is more than one dependency sequence leading to
   139  // a particular package.
   140  var downloadCache = map[string]bool{}
   141  
   142  // downloadRootCache records the version control repository
   143  // root directories we have already considered during the download.
   144  // For example, all the packages in the code.google.com/p/codesearch repo
   145  // share the same root (the directory for that path), and we only need
   146  // to run the hg commands to consider each repository once.
   147  var downloadRootCache = map[string]bool{}
   148  
   149  // download runs the download half of the get command
   150  // for the package named by the argument.
   151  func download(arg string, stk *importStack, getTestDeps bool) {
   152  	p := loadPackage(arg, stk)
   153  	if p.Error != nil && p.Error.hard {
   154  		errorf("%s", p.Error)
   155  		return
   156  	}
   157  
   158  	// loadPackage inferred the canonical ImportPath from arg.
   159  	// Use that in the following to prevent hysteresis effects
   160  	// in e.g. downloadCache and packageCache.
   161  	// This allows invocations such as:
   162  	//   mkdir -p $GOPATH/src/github.com/user
   163  	//   cd $GOPATH/src/github.com/user
   164  	//   go get ./foo
   165  	// see: golang.org/issue/9767
   166  	arg = p.ImportPath
   167  
   168  	// There's nothing to do if this is a package in the standard library.
   169  	if p.Standard {
   170  		return
   171  	}
   172  
   173  	// Only process each package once.
   174  	// (Unless we're fetching test dependencies for this package,
   175  	// in which case we want to process it again.)
   176  	if downloadCache[arg] && !getTestDeps {
   177  		return
   178  	}
   179  	downloadCache[arg] = true
   180  
   181  	pkgs := []*Package{p}
   182  	wildcardOkay := len(*stk) == 0
   183  	isWildcard := false
   184  
   185  	// Download if the package is missing, or update if we're using -u.
   186  	if p.Dir == "" || *getU {
   187  		// The actual download.
   188  		stk.push(p.ImportPath)
   189  		err := downloadPackage(p)
   190  		if err != nil {
   191  			errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
   192  			stk.pop()
   193  			return
   194  		}
   195  
   196  		args := []string{arg}
   197  		// If the argument has a wildcard in it, re-evaluate the wildcard.
   198  		// We delay this until after reloadPackage so that the old entry
   199  		// for p has been replaced in the package cache.
   200  		if wildcardOkay && strings.Contains(arg, "...") {
   201  			if build.IsLocalImport(arg) {
   202  				args = matchPackagesInFS(arg)
   203  			} else {
   204  				args = matchPackages(arg)
   205  			}
   206  			isWildcard = true
   207  		}
   208  
   209  		// Clear all relevant package cache entries before
   210  		// doing any new loads.
   211  		for _, arg := range args {
   212  			p := packageCache[arg]
   213  			if p != nil {
   214  				delete(packageCache, p.Dir)
   215  				delete(packageCache, p.ImportPath)
   216  			}
   217  		}
   218  
   219  		pkgs = pkgs[:0]
   220  		for _, arg := range args {
   221  			stk.push(arg)
   222  			p := loadPackage(arg, stk)
   223  			stk.pop()
   224  			if p.Error != nil {
   225  				errorf("%s", p.Error)
   226  				continue
   227  			}
   228  			pkgs = append(pkgs, p)
   229  		}
   230  	}
   231  
   232  	// Process package, which might now be multiple packages
   233  	// due to wildcard expansion.
   234  	for _, p := range pkgs {
   235  		if *getFix {
   236  			run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles)))
   237  
   238  			// The imports might have changed, so reload again.
   239  			p = reloadPackage(arg, stk)
   240  			if p.Error != nil {
   241  				errorf("%s", p.Error)
   242  				return
   243  			}
   244  		}
   245  
   246  		if isWildcard {
   247  			// Report both the real package and the
   248  			// wildcard in any error message.
   249  			stk.push(p.ImportPath)
   250  		}
   251  
   252  		// Process dependencies, now that we know what they are.
   253  		for _, dep := range p.deps {
   254  			// Don't get test dependencies recursively.
   255  			download(dep.ImportPath, stk, false)
   256  		}
   257  		if getTestDeps {
   258  			// Process test dependencies when -t is specified.
   259  			// (Don't get test dependencies for test dependencies.)
   260  			for _, path := range p.TestImports {
   261  				download(path, stk, false)
   262  			}
   263  			for _, path := range p.XTestImports {
   264  				download(path, stk, false)
   265  			}
   266  		}
   267  
   268  		if isWildcard {
   269  			stk.pop()
   270  		}
   271  	}
   272  }
   273  
   274  // downloadPackage runs the create or download command
   275  // to make the first copy of or update a copy of the given package.
   276  func downloadPackage(p *Package) error {
   277  	var (
   278  		vcs            *vcsCmd
   279  		repo, rootPath string
   280  		err            error
   281  	)
   282  	if p.build.SrcRoot != "" {
   283  		// Directory exists.  Look for checkout along path to src.
   284  		vcs, rootPath, err = vcsForDir(p)
   285  		if err != nil {
   286  			return err
   287  		}
   288  		repo = "<local>" // should be unused; make distinctive
   289  
   290  		// Double-check where it came from.
   291  		if *getU && vcs.remoteRepo != nil && !*getF {
   292  			dir := filepath.Join(p.build.SrcRoot, rootPath)
   293  			if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
   294  				if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
   295  					repo := rr.repo
   296  					if rr.vcs.resolveRepo != nil {
   297  						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
   298  						if err == nil {
   299  							repo = resolved
   300  						}
   301  					}
   302  					if remote != repo {
   303  						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
   304  					}
   305  				}
   306  			}
   307  		}
   308  	} else {
   309  		// Analyze the import path to determine the version control system,
   310  		// repository, and the import path for the root of the repository.
   311  		rr, err := repoRootForImportPath(p.ImportPath)
   312  		if err != nil {
   313  			return err
   314  		}
   315  		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
   316  	}
   317  
   318  	if p.build.SrcRoot == "" {
   319  		// Package not found.  Put in first directory of $GOPATH.
   320  		list := filepath.SplitList(buildContext.GOPATH)
   321  		if len(list) == 0 {
   322  			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
   323  		}
   324  		// Guard against people setting GOPATH=$GOROOT.
   325  		if list[0] == goroot {
   326  			return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
   327  		}
   328  		p.build.SrcRoot = filepath.Join(list[0], "src")
   329  		p.build.PkgRoot = filepath.Join(list[0], "pkg")
   330  	}
   331  	root := filepath.Join(p.build.SrcRoot, rootPath)
   332  	// If we've considered this repository already, don't do it again.
   333  	if downloadRootCache[root] {
   334  		return nil
   335  	}
   336  	downloadRootCache[root] = true
   337  
   338  	if buildV {
   339  		fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
   340  	}
   341  
   342  	// Check that this is an appropriate place for the repo to be checked out.
   343  	// The target directory must either not exist or have a repo checked out already.
   344  	meta := filepath.Join(root, "."+vcs.cmd)
   345  	st, err := os.Stat(meta)
   346  	if err == nil && !st.IsDir() {
   347  		return fmt.Errorf("%s exists but is not a directory", meta)
   348  	}
   349  	if err != nil {
   350  		// Metadata directory does not exist.  Prepare to checkout new copy.
   351  		// Some version control tools require the target directory not to exist.
   352  		// We require that too, just to avoid stepping on existing work.
   353  		if _, err := os.Stat(root); err == nil {
   354  			return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
   355  		}
   356  		// Some version control tools require the parent of the target to exist.
   357  		parent, _ := filepath.Split(root)
   358  		if err = os.MkdirAll(parent, 0777); err != nil {
   359  			return err
   360  		}
   361  		if err = vcs.create(root, repo); err != nil {
   362  			return err
   363  		}
   364  	} else {
   365  		// Metadata directory does exist; download incremental updates.
   366  		if err = vcs.download(root); err != nil {
   367  			return err
   368  		}
   369  	}
   370  
   371  	if buildN {
   372  		// Do not show tag sync in -n; it's noise more than anything,
   373  		// and since we're not running commands, no tag will be found.
   374  		// But avoid printing nothing.
   375  		fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
   376  		return nil
   377  	}
   378  
   379  	// Select and sync to appropriate version of the repository.
   380  	tags, err := vcs.tags(root)
   381  	if err != nil {
   382  		return err
   383  	}
   384  	vers := runtime.Version()
   385  	if i := strings.Index(vers, " "); i >= 0 {
   386  		vers = vers[:i]
   387  	}
   388  	if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
   389  		return err
   390  	}
   391  
   392  	return nil
   393  }
   394  
   395  // goTag matches go release tags such as go1 and go1.2.3.
   396  // The numbers involved must be small (at most 4 digits),
   397  // have no unnecessary leading zeros, and the version cannot
   398  // end in .0 - it is go1, not go1.0 or go1.0.0.
   399  var goTag = regexp.MustCompile(
   400  	`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
   401  )
   402  
   403  // selectTag returns the closest matching tag for a given version.
   404  // Closest means the latest one that is not after the current release.
   405  // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
   406  // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
   407  // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
   408  //
   409  // NOTE(rsc): Eventually we will need to decide on some logic here.
   410  // For now, there is only "go1".  This matches the docs in go help get.
   411  func selectTag(goVersion string, tags []string) (match string) {
   412  	for _, t := range tags {
   413  		if t == "go1" {
   414  			return "go1"
   415  		}
   416  	}
   417  	return ""
   418  
   419  	/*
   420  		if goTag.MatchString(goVersion) {
   421  			v := goVersion
   422  			for _, t := range tags {
   423  				if !goTag.MatchString(t) {
   424  					continue
   425  				}
   426  				if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
   427  					match = t
   428  				}
   429  			}
   430  		}
   431  
   432  		return match
   433  	*/
   434  }
   435  
   436  // cmpGoVersion returns -1, 0, +1 reporting whether
   437  // x < y, x == y, or x > y.
   438  func cmpGoVersion(x, y string) int {
   439  	// Malformed strings compare less than well-formed strings.
   440  	if !goTag.MatchString(x) {
   441  		return -1
   442  	}
   443  	if !goTag.MatchString(y) {
   444  		return +1
   445  	}
   446  
   447  	// Compare numbers in sequence.
   448  	xx := strings.Split(x[len("go"):], ".")
   449  	yy := strings.Split(y[len("go"):], ".")
   450  
   451  	for i := 0; i < len(xx) && i < len(yy); i++ {
   452  		// The Atoi are guaranteed to succeed
   453  		// because the versions match goTag.
   454  		xi, _ := strconv.Atoi(xx[i])
   455  		yi, _ := strconv.Atoi(yy[i])
   456  		if xi < yi {
   457  			return -1
   458  		} else if xi > yi {
   459  			return +1
   460  		}
   461  	}
   462  
   463  	if len(xx) < len(yy) {
   464  		return -1
   465  	}
   466  	if len(xx) > len(yy) {
   467  		return +1
   468  	}
   469  	return 0
   470  }