github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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  	// There's nothing to do if this is a package in the standard library.
   159  	if p.Standard {
   160  		return
   161  	}
   162  
   163  	// Only process each package once.
   164  	// (Unless we're fetching test dependencies for this package,
   165  	// in which case we want to process it again.)
   166  	if downloadCache[arg] && !getTestDeps {
   167  		return
   168  	}
   169  	downloadCache[arg] = true
   170  
   171  	pkgs := []*Package{p}
   172  	wildcardOkay := len(*stk) == 0
   173  	isWildcard := false
   174  
   175  	// Download if the package is missing, or update if we're using -u.
   176  	if p.Dir == "" || *getU {
   177  		// The actual download.
   178  		stk.push(p.ImportPath)
   179  		err := downloadPackage(p)
   180  		if err != nil {
   181  			errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
   182  			stk.pop()
   183  			return
   184  		}
   185  
   186  		args := []string{arg}
   187  		// If the argument has a wildcard in it, re-evaluate the wildcard.
   188  		// We delay this until after reloadPackage so that the old entry
   189  		// for p has been replaced in the package cache.
   190  		if wildcardOkay && strings.Contains(arg, "...") {
   191  			if build.IsLocalImport(arg) {
   192  				args = matchPackagesInFS(arg)
   193  			} else {
   194  				args = matchPackages(arg)
   195  			}
   196  			isWildcard = true
   197  		}
   198  
   199  		// Clear all relevant package cache entries before
   200  		// doing any new loads.
   201  		for _, arg := range args {
   202  			p := packageCache[arg]
   203  			if p != nil {
   204  				delete(packageCache, p.Dir)
   205  				delete(packageCache, p.ImportPath)
   206  			}
   207  		}
   208  
   209  		pkgs = pkgs[:0]
   210  		for _, arg := range args {
   211  			stk.push(arg)
   212  			p := loadPackage(arg, stk)
   213  			stk.pop()
   214  			if p.Error != nil {
   215  				errorf("%s", p.Error)
   216  				continue
   217  			}
   218  			pkgs = append(pkgs, p)
   219  		}
   220  	}
   221  
   222  	// Process package, which might now be multiple packages
   223  	// due to wildcard expansion.
   224  	for _, p := range pkgs {
   225  		if *getFix {
   226  			run(stringList(tool("fix"), relPaths(p.allgofiles)))
   227  
   228  			// The imports might have changed, so reload again.
   229  			p = reloadPackage(arg, stk)
   230  			if p.Error != nil {
   231  				errorf("%s", p.Error)
   232  				return
   233  			}
   234  		}
   235  
   236  		if isWildcard {
   237  			// Report both the real package and the
   238  			// wildcard in any error message.
   239  			stk.push(p.ImportPath)
   240  		}
   241  
   242  		// Process dependencies, now that we know what they are.
   243  		for _, dep := range p.deps {
   244  			// Don't get test dependencies recursively.
   245  			download(dep.ImportPath, stk, false)
   246  		}
   247  		if getTestDeps {
   248  			// Process test dependencies when -t is specified.
   249  			// (Don't get test dependencies for test dependencies.)
   250  			for _, path := range p.TestImports {
   251  				download(path, stk, false)
   252  			}
   253  			for _, path := range p.XTestImports {
   254  				download(path, stk, false)
   255  			}
   256  		}
   257  
   258  		if isWildcard {
   259  			stk.pop()
   260  		}
   261  	}
   262  }
   263  
   264  // downloadPackage runs the create or download command
   265  // to make the first copy of or update a copy of the given package.
   266  func downloadPackage(p *Package) error {
   267  	var (
   268  		vcs            *vcsCmd
   269  		repo, rootPath string
   270  		err            error
   271  	)
   272  	if p.build.SrcRoot != "" {
   273  		// Directory exists.  Look for checkout along path to src.
   274  		vcs, rootPath, err = vcsForDir(p)
   275  		if err != nil {
   276  			return err
   277  		}
   278  		repo = "<local>" // should be unused; make distinctive
   279  
   280  		// Double-check where it came from.
   281  		if *getU && vcs.remoteRepo != nil && !*getF {
   282  			dir := filepath.Join(p.build.SrcRoot, rootPath)
   283  			if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
   284  				if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
   285  					repo := rr.repo
   286  					if rr.vcs.resolveRepo != nil {
   287  						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
   288  						if err == nil {
   289  							repo = resolved
   290  						}
   291  					}
   292  					if remote != repo {
   293  						return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo)
   294  					}
   295  				}
   296  			}
   297  		}
   298  	} else {
   299  		// Analyze the import path to determine the version control system,
   300  		// repository, and the import path for the root of the repository.
   301  		rr, err := repoRootForImportPath(p.ImportPath)
   302  		if err != nil {
   303  			return err
   304  		}
   305  		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
   306  	}
   307  
   308  	if p.build.SrcRoot == "" {
   309  		// Package not found.  Put in first directory of $GOPATH.
   310  		list := filepath.SplitList(buildContext.GOPATH)
   311  		if len(list) == 0 {
   312  			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
   313  		}
   314  		// Guard against people setting GOPATH=$GOROOT.
   315  		if list[0] == goroot {
   316  			return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
   317  		}
   318  		p.build.SrcRoot = filepath.Join(list[0], "src")
   319  		p.build.PkgRoot = filepath.Join(list[0], "pkg")
   320  	}
   321  	root := filepath.Join(p.build.SrcRoot, rootPath)
   322  	// If we've considered this repository already, don't do it again.
   323  	if downloadRootCache[root] {
   324  		return nil
   325  	}
   326  	downloadRootCache[root] = true
   327  
   328  	if buildV {
   329  		fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
   330  	}
   331  
   332  	// Check that this is an appropriate place for the repo to be checked out.
   333  	// The target directory must either not exist or have a repo checked out already.
   334  	meta := filepath.Join(root, "."+vcs.cmd)
   335  	st, err := os.Stat(meta)
   336  	if err == nil && !st.IsDir() {
   337  		return fmt.Errorf("%s exists but is not a directory", meta)
   338  	}
   339  	if err != nil {
   340  		// Metadata directory does not exist.  Prepare to checkout new copy.
   341  		// Some version control tools require the target directory not to exist.
   342  		// We require that too, just to avoid stepping on existing work.
   343  		if _, err := os.Stat(root); err == nil {
   344  			return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
   345  		}
   346  		// Some version control tools require the parent of the target to exist.
   347  		parent, _ := filepath.Split(root)
   348  		if err = os.MkdirAll(parent, 0777); err != nil {
   349  			return err
   350  		}
   351  		if err = vcs.create(root, repo); err != nil {
   352  			return err
   353  		}
   354  	} else {
   355  		// Metadata directory does exist; download incremental updates.
   356  		if err = vcs.download(root); err != nil {
   357  			return err
   358  		}
   359  	}
   360  
   361  	if buildN {
   362  		// Do not show tag sync in -n; it's noise more than anything,
   363  		// and since we're not running commands, no tag will be found.
   364  		// But avoid printing nothing.
   365  		fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
   366  		return nil
   367  	}
   368  
   369  	// Select and sync to appropriate version of the repository.
   370  	tags, err := vcs.tags(root)
   371  	if err != nil {
   372  		return err
   373  	}
   374  	vers := runtime.Version()
   375  	if i := strings.Index(vers, " "); i >= 0 {
   376  		vers = vers[:i]
   377  	}
   378  	if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
   379  		return err
   380  	}
   381  
   382  	return nil
   383  }
   384  
   385  // goTag matches go release tags such as go1 and go1.2.3.
   386  // The numbers involved must be small (at most 4 digits),
   387  // have no unnecessary leading zeros, and the version cannot
   388  // end in .0 - it is go1, not go1.0 or go1.0.0.
   389  var goTag = regexp.MustCompile(
   390  	`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
   391  )
   392  
   393  // selectTag returns the closest matching tag for a given version.
   394  // Closest means the latest one that is not after the current release.
   395  // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
   396  // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
   397  // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
   398  //
   399  // NOTE(rsc): Eventually we will need to decide on some logic here.
   400  // For now, there is only "go1".  This matches the docs in go help get.
   401  func selectTag(goVersion string, tags []string) (match string) {
   402  	for _, t := range tags {
   403  		if t == "go1" {
   404  			return "go1"
   405  		}
   406  	}
   407  	return ""
   408  
   409  	/*
   410  		if goTag.MatchString(goVersion) {
   411  			v := goVersion
   412  			for _, t := range tags {
   413  				if !goTag.MatchString(t) {
   414  					continue
   415  				}
   416  				if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
   417  					match = t
   418  				}
   419  			}
   420  		}
   421  
   422  		return match
   423  	*/
   424  }
   425  
   426  // cmpGoVersion returns -1, 0, +1 reporting whether
   427  // x < y, x == y, or x > y.
   428  func cmpGoVersion(x, y string) int {
   429  	// Malformed strings compare less than well-formed strings.
   430  	if !goTag.MatchString(x) {
   431  		return -1
   432  	}
   433  	if !goTag.MatchString(y) {
   434  		return +1
   435  	}
   436  
   437  	// Compare numbers in sequence.
   438  	xx := strings.Split(x[len("go"):], ".")
   439  	yy := strings.Split(y[len("go"):], ".")
   440  
   441  	for i := 0; i < len(xx) && i < len(yy); i++ {
   442  		// The Atoi are guaranteed to succeed
   443  		// because the versions match goTag.
   444  		xi, _ := strconv.Atoi(xx[i])
   445  		yi, _ := strconv.Atoi(yy[i])
   446  		if xi < yi {
   447  			return -1
   448  		} else if xi > yi {
   449  			return +1
   450  		}
   451  	}
   452  
   453  	if len(xx) < len(yy) {
   454  		return -1
   455  	}
   456  	if len(xx) > len(yy) {
   457  		return +1
   458  	}
   459  	return 0
   460  }