diff options
Diffstat (limited to 'src/cmd/go/get.go')
-rw-r--r-- | src/cmd/go/get.go | 132 |
1 files changed, 101 insertions, 31 deletions
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index 0ad22adb0..abaf5ffa0 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -8,6 +8,7 @@ package main import ( "fmt" + "go/build" "os" "path/filepath" "runtime" @@ -23,7 +24,7 @@ Get downloads and installs the packages named by the import paths, along with their dependencies. The -a, -n, -v, -x, and -p flags have the same meaning as in 'go build' -and 'go install'. See 'go help install'. +and 'go install'. See 'go help build'. The -d flag instructs get to stop after downloading the packages; that is, it instructs get not to install the packages. @@ -57,19 +58,13 @@ func init() { func runGet(cmd *Command, args []string) { // Phase 1. Download/update. - args = importPaths(args) var stk importStack - for _, arg := range args { + for _, arg := range downloadPaths(args) { download(arg, &stk) } exitIfErrors() - if *getD { - // download only - return - } - - // Phase 2. Install. + // Phase 2. Rescan packages and reevaluate args list. // Code we downloaded and all code that depends on it // needs to be evicted from the package cache so that @@ -80,9 +75,48 @@ func runGet(cmd *Command, args []string) { delete(packageCache, name) } + args = importPaths(args) + + // Phase 3. Install. + if *getD { + // Download only. + // Check delayed until now so that importPaths + // has a chance to print errors. + return + } + runInstall(cmd, args) } +// downloadPath prepares the list of paths to pass to download. +// It expands ... patterns that can be expanded. If there is no match +// for a particular pattern, downloadPaths leaves it in the result list, +// in the hope that we can figure out the repository from the +// initial ...-free prefix. +func downloadPaths(args []string) []string { + args = importPathsNoDotExpansion(args) + var out []string + for _, a := range args { + if strings.Contains(a, "...") { + var expand []string + // Use matchPackagesInFS to avoid printing + // warnings. They will be printed by the + // eventual call to importPaths instead. + if build.IsLocalImport(a) { + expand = matchPackagesInFS(a) + } else { + expand = matchPackages(a) + } + if len(expand) > 0 { + out = append(out, expand...) + continue + } + } + out = append(out, a) + } + return out +} + // downloadCache records the import paths we have already // considered during the download, to avoid duplicate work when // there is more than one dependency sequence leading to @@ -112,38 +146,73 @@ func download(arg string, stk *importStack) { } downloadCache[arg] = true + pkgs := []*Package{p} + wildcardOkay := len(*stk) == 0 + // Download if the package is missing, or update if we're using -u. if p.Dir == "" || *getU { // The actual download. stk.push(p.ImportPath) - defer stk.pop() - if err := downloadPackage(p); err != nil { + err := downloadPackage(p) + if err != nil { errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()}) + stk.pop() return } - // Reread the package information from the updated files. - p = reloadPackage(arg, stk) - if p.Error != nil { - errorf("%s", p.Error) - return + args := []string{arg} + // If the argument has a wildcard in it, re-evaluate the wildcard. + // We delay this until after reloadPackage so that the old entry + // for p has been replaced in the package cache. + if wildcardOkay && strings.Contains(arg, "...") { + if build.IsLocalImport(arg) { + args = matchPackagesInFS(arg) + } else { + args = matchPackages(arg) + } } - } - if *getFix { - run(stringList(tool("fix"), relPaths(p.gofiles))) + // Clear all relevant package cache entries before + // doing any new loads. + for _, arg := range args { + p := packageCache[arg] + if p != nil { + delete(packageCache, p.Dir) + delete(packageCache, p.ImportPath) + } + } - // The imports might have changed, so reload again. - p = reloadPackage(arg, stk) - if p.Error != nil { - errorf("%s", p.Error) - return + pkgs = pkgs[:0] + for _, arg := range args { + stk.push(arg) + p := loadPackage(arg, stk) + stk.pop() + if p.Error != nil { + errorf("%s", p.Error) + continue + } + pkgs = append(pkgs, p) } } - // Process dependencies, now that we know what they are. - for _, dep := range p.deps { - download(dep.ImportPath, stk) + // Process package, which might now be multiple packages + // due to wildcard expansion. + for _, p := range pkgs { + if *getFix { + run(stringList(tool("fix"), relPaths(p.gofiles))) + + // The imports might have changed, so reload again. + p = reloadPackage(arg, stk) + if p.Error != nil { + errorf("%s", p.Error) + return + } + } + + // Process dependencies, now that we know what they are. + for _, dep := range p.deps { + download(dep.ImportPath, stk) + } } } @@ -162,10 +231,11 @@ func downloadPackage(p *Package) error { } else { // Analyze the import path to determine the version control system, // repository, and the import path for the root of the repository. - vcs, repo, rootPath, err = vcsForImportPath(p.ImportPath) - } - if err != nil { - return err + rr, err := repoRootForImportPath(p.ImportPath) + if err != nil { + return err + } + vcs, repo, rootPath = rr.vcs, rr.repo, rr.root } if p.build.SrcRoot == "" { |