summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/internal/get/vcs.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/internal/get/vcs.go')
-rw-r--r--libgo/go/cmd/go/internal/get/vcs.go144
1 files changed, 70 insertions, 74 deletions
diff --git a/libgo/go/cmd/go/internal/get/vcs.go b/libgo/go/cmd/go/internal/get/vcs.go
index 0b2a04e04f8..5cd164f2ff3 100644
--- a/libgo/go/cmd/go/internal/get/vcs.go
+++ b/libgo/go/cmd/go/internal/get/vcs.go
@@ -5,7 +5,6 @@
package get
import (
- "bytes"
"encoding/json"
"errors"
"fmt"
@@ -428,19 +427,18 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
fmt.Printf("cd %s\n", dir)
fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
}
- var buf bytes.Buffer
- cmd.Stdout = &buf
- cmd.Stderr = &buf
- err = cmd.Run()
- out := buf.Bytes()
+ out, err := cmd.Output()
if err != nil {
if verbose || cfg.BuildV {
fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
- os.Stderr.Write(out)
+ if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
+ os.Stderr.Write(ee.Stderr)
+ } else {
+ fmt.Fprintf(os.Stderr, err.Error())
+ }
}
- return out, err
}
- return out, nil
+ return out, err
}
// ping pings to determine scheme to use.
@@ -624,27 +622,29 @@ func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {
return nil
}
-// repoRoot represents a version control system, a repo, and a root of
-// where to put it on disk.
-type repoRoot struct {
- vcs *vcsCmd
-
- // repo is the repository URL, including scheme
- repo string
+// RepoRoot describes the repository root for a tree of source code.
+type RepoRoot struct {
+ Repo string // repository URL, including scheme
+ Root string // import path corresponding to root of repo
+ IsCustom bool // defined by served <meta> tags (as opposed to hard-coded pattern)
+ VCS string // vcs type ("mod", "git", ...)
- // root is the import path corresponding to the root of the
- // repository
- root string
-
- // isCustom is true for custom import paths (those defined by HTML meta tags)
- isCustom bool
+ vcs *vcsCmd // internal: vcs command access
}
var httpPrefixRE = regexp.MustCompile(`^https?:`)
-// repoRootForImportPath analyzes importPath to determine the
+// ModuleMode specifies whether to prefer modules when looking up code sources.
+type ModuleMode int
+
+const (
+ IgnoreMod ModuleMode = iota
+ PreferMod
+)
+
+// RepoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
-func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) {
+func RepoRootForImportPath(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
if err == errUnknownSite {
// If there are wildcards, look up the thing before the wildcard,
@@ -654,7 +654,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR
if i := strings.Index(lookup, "/.../"); i >= 0 {
lookup = lookup[:i]
}
- rr, err = repoRootForImportDynamic(lookup, security)
+ rr, err = repoRootForImportDynamic(lookup, mod, security)
if err != nil {
err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err)
}
@@ -667,7 +667,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR
}
}
- if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
+ 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)
@@ -680,7 +680,7 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping")
// repoRootFromVCSPaths attempts to map importPath to a repoRoot
// using the mappings defined in vcsPaths.
// If scheme is non-empty, that scheme is forced.
-func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
+func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) {
// A common error is to use https://packagepath because that's what
// hg and git require. Diagnose this helpfully.
if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
@@ -733,28 +733,32 @@ func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode,
if security == web.Secure && !vcs.isSecureScheme(scheme) {
continue
}
- if vcs.ping(scheme, match["repo"]) == nil {
+ if vcs.pingCmd != "" && vcs.ping(scheme, match["repo"]) == nil {
match["repo"] = scheme + "://" + match["repo"]
- break
+ goto Found
}
}
+ // No scheme found. Fall back to the first one.
+ match["repo"] = vcs.scheme[0] + "://" + match["repo"]
+ Found:
}
}
- rr := &repoRoot{
+ rr := &RepoRoot{
+ Repo: match["repo"],
+ Root: match["root"],
+ VCS: vcs.cmd,
vcs: vcs,
- repo: match["repo"],
- root: match["root"],
}
return rr, nil
}
return nil, errUnknownSite
}
-// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
+// repoRootForImportDynamic finds a *RepoRoot for a custom domain that's not
// statically known by repoRootForImportPathStatic.
//
// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
-func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*repoRoot, error) {
+func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) {
slash := strings.Index(importPath, "/")
if slash < 0 {
slash = len(importPath)
@@ -772,7 +776,7 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
return nil, fmt.Errorf(msg, err)
}
defer body.Close()
- imports, err := parseMetaGoImports(body)
+ imports, err := parseMetaGoImports(body, mod)
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", importPath, err)
}
@@ -799,7 +803,7 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
}
urlStr0 := urlStr
var imports []metaImport
- urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security)
+ urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, mod, security)
if err != nil {
return nil, err
}
@@ -809,48 +813,34 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re
}
}
- if err := validateRepoRootScheme(mmi.RepoRoot); err != nil {
+ if err := validateRepoRoot(mmi.RepoRoot); err != nil {
return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err)
}
- rr := &repoRoot{
- vcs: vcsByCmd(mmi.VCS),
- repo: mmi.RepoRoot,
- root: mmi.Prefix,
- isCustom: true,
- }
- if rr.vcs == nil {
+ vcs := vcsByCmd(mmi.VCS)
+ if vcs == nil && mmi.VCS != "mod" {
return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
}
+
+ rr := &RepoRoot{
+ Repo: mmi.RepoRoot,
+ Root: mmi.Prefix,
+ IsCustom: true,
+ VCS: mmi.VCS,
+ vcs: vcs,
+ }
return rr, nil
}
-// validateRepoRootScheme returns an error if repoRoot does not seem
-// to have a valid URL scheme. At this point we permit things that
-// aren't valid URLs, although later, if not using -insecure, we will
-// restrict repoRoots to be valid URLs. This is only because we've
-// historically permitted them, and people may depend on that.
-func validateRepoRootScheme(repoRoot string) error {
- end := strings.Index(repoRoot, "://")
- if end <= 0 {
- return errors.New("no scheme")
+// validateRepoRoot returns an error if repoRoot does not seem to be
+// a valid URL with scheme.
+func validateRepoRoot(repoRoot string) error {
+ url, err := url.Parse(repoRoot)
+ if err != nil {
+ return err
}
-
- // RFC 3986 section 3.1.
- for i := 0; i < end; i++ {
- c := repoRoot[i]
- switch {
- case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
- // OK.
- case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.':
- // OK except at start.
- if i == 0 {
- return errors.New("invalid scheme")
- }
- default:
- return errors.New("invalid scheme")
- }
+ if url.Scheme == "" {
+ return errors.New("no scheme")
}
-
return nil
}
@@ -868,7 +858,7 @@ var (
// It is an error if no imports are found.
// urlStr will still be valid if err != nil.
// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
-func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
+func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
setCache := func(res fetchResult) (fetchResult, error) {
fetchCacheMu.Lock()
defer fetchCacheMu.Unlock()
@@ -888,7 +878,7 @@ func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlSt
if err != nil {
return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
}
- imports, err := parseMetaGoImports(body)
+ imports, err := parseMetaGoImports(body, mod)
if err != nil {
return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
}
@@ -956,7 +946,13 @@ func matchGoImport(imports []metaImport, importPath string) (metaImport, error)
continue
}
- if match != -1 {
+ if match >= 0 {
+ if imports[match].VCS == "mod" && im.VCS != "mod" {
+ // All the mod entries precede all the non-mod entries.
+ // We have a mod entry and don't care about the rest,
+ // matching or not.
+ break
+ }
return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath)
}
match = i
@@ -1001,7 +997,7 @@ var vcsPaths = []*vcsPath{
// IBM DevOps Services (JazzHub)
{
prefix: "hub.jazz.net/git/",
- re: `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
+ re: `^(?P<root>hub\.jazz\.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
check: noVCSSuffix,
@@ -1010,7 +1006,7 @@ var vcsPaths = []*vcsPath{
// Git at Apache
{
prefix: "git.apache.org/",
- re: `^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
+ re: `^(?P<root>git\.apache\.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
},