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