Commit 4e18bfb9 authored by Russ Cox's avatar Russ Cox

cmd/go: make go get new.code/... work

Fixes #2909.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5796072
parent b70925d6
......@@ -8,6 +8,7 @@ package main
import (
"fmt"
"go/build"
"os"
"path/filepath"
"runtime"
......@@ -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)
}
}
}
......
......@@ -76,7 +76,6 @@ func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err erro
}
if err != nil {
closeBody(res)
log.Printf("http fetch failed")
return "", nil, err
}
// Note: accepting a non-200 OK here, so people can serve a
......
......@@ -323,6 +323,23 @@ func repoRootForImportPath(importPath string) (*repoRoot, error) {
rr, err := repoRootForImportPathStatic(importPath, "")
if err == errUnknownSite {
rr, err = repoRootForImportDynamic(importPath)
// repoRootForImportDynamic returns error detail
// that is irrelevant if the user didn't intend to use a
// dynamic import in the first place.
// Squelch it.
if err != nil {
if buildV {
log.Printf("import %q: %v", importPath, err)
}
err = fmt.Errorf("unrecognized import path %q", importPath)
}
}
if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
// Do not allow wildcards in the repo root.
rr = nil
err = fmt.Errorf("cannot expand ... in %q", importPath)
}
return rr, err
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment