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