diff options
author | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-07-30 21:29:29 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-07-30 21:29:29 +0000 |
commit | 8e2ab05dd39cdf8eea2546b220cc5f48afd39c97 (patch) | |
tree | 90c5e955bd302b44d7b9466f864caf9e2d4d00cc /src/cmd/go | |
parent | 52e970b1c86f18806232adb0e1f42636645d21ff (diff) | |
parent | 47cdfa95ae85919c6f050a87b54c69f64c2666fc (diff) | |
download | go-8e2ab05dd39cdf8eea2546b220cc5f48afd39c97.tar.gz go-8e2ab05dd39cdf8eea2546b220cc5f48afd39c97.zip |
Merge "[dev.cmdgo] all: merge master (9eee0ed) into dev.cmdgo" into dev.cmdgo
Diffstat (limited to 'src/cmd/go')
21 files changed, 226 insertions, 139 deletions
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index fb99dccb46..af1ee39684 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1087,7 +1087,7 @@ // // Usage: // -// go mod edit [editing flags] [go.mod] +// go mod edit [editing flags] [-fmt|-print|-json] [go.mod] // // Edit provides a command-line interface for editing go.mod, // for use primarily by tools or scripts. It reads only go.mod; @@ -1202,7 +1202,7 @@ // and one of its requirements. Each module is identified as a string of the form // path@version, except for the main module, which has no @version suffix. // -// The -go flag causes graph to report the module graph as loaded by by the +// The -go flag causes graph to report the module graph as loaded by the // given Go version, instead of the version indicated by the 'go' directive // in the go.mod file. // @@ -1213,7 +1213,7 @@ // // Usage: // -// go mod init [module] +// go mod init [module-path] // // Init initializes and writes a new go.mod file in the current directory, in // effect creating a new module rooted at the current directory. The go.mod file diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index c0c86ab9f5..6ce276537b 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2848,3 +2848,35 @@ func TestExecInDeletedDir(t *testing.T) { // `go version` should not fail tg.run("version") } + +// A missing C compiler should not force the net package to be stale. +// Issue 47215. +func TestMissingCC(t *testing.T) { + if !canCgo { + t.Skip("test is only meaningful on systems with cgo") + } + cc := os.Getenv("CC") + if cc == "" { + cc = "gcc" + } + if filepath.IsAbs(cc) { + t.Skipf(`"CC" (%s) is an absolute path`, cc) + } + _, err := exec.LookPath(cc) + if err != nil { + t.Skipf(`"CC" (%s) not on PATH`, cc) + } + + tg := testgo(t) + defer tg.cleanup() + netStale, _ := tg.isStale("net") + if netStale { + t.Skip(`skipping test because "net" package is currently stale`) + } + + tg.setenv("PATH", "") // No C compiler on PATH. + netStale, _ = tg.isStale("net") + if netStale { + t.Error(`clearing "PATH" causes "net" to be stale`) + } +} diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go index 729df5c681..e4923f6876 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go @@ -11,7 +11,6 @@ import ( "io/fs" "os" - "cmd/go/internal/fsys" "cmd/go/internal/lockedfile/internal/filelock" ) @@ -21,7 +20,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // calls for Linux and Windows anyway, so it's simpler to use that approach // consistently. - f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm) + f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm) if err != nil { return nil, err } diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go index 3d4b97d78e..979118b10a 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go @@ -13,8 +13,6 @@ import ( "os" "strings" "time" - - "cmd/go/internal/fsys" ) // Opening an exclusive-use file returns an error. @@ -59,7 +57,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // If the file was unpacked or created by some other program, it might not // have the ModeExclusive bit set. Set it before we call OpenFile, so that we // can be confident that a successful OpenFile implies exclusive use. - if fi, err := fsys.Stat(name); err == nil { + if fi, err := os.Stat(name); err == nil { if fi.Mode()&fs.ModeExclusive == 0 { if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil { return nil, err @@ -72,7 +70,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { nextSleep := 1 * time.Millisecond const maxSleep = 500 * time.Millisecond for { - f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive) + f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive) if err == nil { return f, nil } diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go index e856e7c630..bb3d521092 100644 --- a/src/cmd/go/internal/modcmd/edit.go +++ b/src/cmd/go/internal/modcmd/edit.go @@ -25,7 +25,7 @@ import ( ) var cmdEdit = &base.Command{ - UsageLine: "go mod edit [editing flags] [go.mod]", + UsageLine: "go mod edit [editing flags] [-fmt|-print|-json] [go.mod]", Short: "edit go.mod from tools or scripts", Long: ` Edit provides a command-line interface for editing go.mod, diff --git a/src/cmd/go/internal/modcmd/graph.go b/src/cmd/go/internal/modcmd/graph.go index 5ef1d4ed04..2cbabae044 100644 --- a/src/cmd/go/internal/modcmd/graph.go +++ b/src/cmd/go/internal/modcmd/graph.go @@ -26,7 +26,7 @@ in text form. Each line in the output has two space-separated fields: a module and one of its requirements. Each module is identified as a string of the form path@version, except for the main module, which has no @version suffix. -The -go flag causes graph to report the module graph as loaded by by the +The -go flag causes graph to report the module graph as loaded by the given Go version, instead of the version indicated by the 'go' directive in the go.mod file. diff --git a/src/cmd/go/internal/modcmd/init.go b/src/cmd/go/internal/modcmd/init.go index 73cc282d81..958c3066ac 100644 --- a/src/cmd/go/internal/modcmd/init.go +++ b/src/cmd/go/internal/modcmd/init.go @@ -13,7 +13,7 @@ import ( ) var cmdInit = &base.Command{ - UsageLine: "go mod init [module]", + UsageLine: "go mod init [module-path]", Short: "initialize new module in current directory", Long: ` Init initializes and writes a new go.mod file in the current directory, in diff --git a/src/cmd/go/internal/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go index 89a73baad9..a684fa1a9b 100644 --- a/src/cmd/go/internal/modfetch/codehost/git_test.go +++ b/src/cmd/go/internal/modfetch/codehost/git_test.go @@ -8,7 +8,6 @@ import ( "archive/zip" "bytes" "flag" - "fmt" "internal/testenv" "io" "io/fs" @@ -47,12 +46,6 @@ var altRepos = []string{ var localGitRepo string func testMain(m *testing.M) int { - if _, err := exec.LookPath("git"); err != nil { - fmt.Fprintln(os.Stderr, "skipping because git binary not found") - fmt.Println("PASS") - return 0 - } - dir, err := os.MkdirTemp("", "gitrepo-test-") if err != nil { log.Fatal(err) @@ -60,23 +53,25 @@ func testMain(m *testing.M) int { defer os.RemoveAll(dir) if testenv.HasExternalNetwork() && testenv.HasExec() { - // Clone gitrepo1 into a local directory. - // If we use a file:// URL to access the local directory, - // then git starts up all the usual protocol machinery, - // which will let us test remote git archive invocations. - localGitRepo = filepath.Join(dir, "gitrepo2") - if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { - log.Fatal(err) - } - if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { - log.Fatal(err) + if _, err := exec.LookPath("git"); err == nil { + // Clone gitrepo1 into a local directory. + // If we use a file:// URL to access the local directory, + // then git starts up all the usual protocol machinery, + // which will let us test remote git archive invocations. + localGitRepo = filepath.Join(dir, "gitrepo2") + if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { + log.Fatal(err) + } + if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { + log.Fatal(err) + } } } return m.Run() } -func testRepo(remote string) (Repo, error) { +func testRepo(t *testing.T, remote string) (Repo, error) { if remote == "localGitRepo" { // Convert absolute path to file URL. LocalGitRepo will not accept // Windows absolute paths because they look like a host:path remote. @@ -87,15 +82,17 @@ func testRepo(remote string) (Repo, error) { } else { url = "file:///" + filepath.ToSlash(localGitRepo) } + testenv.MustHaveExecPath(t, "git") return LocalGitRepo(url) } - kind := "git" + vcs := "git" for _, k := range []string{"hg"} { if strings.Contains(remote, "/"+k+"/") { - kind = k + vcs = k } } - return NewRepo(kind, remote) + testenv.MustHaveExecPath(t, vcs) + return NewRepo(vcs, remote) } var tagsTests = []struct { @@ -116,7 +113,7 @@ func TestTags(t *testing.T) { for _, tt := range tagsTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -168,7 +165,7 @@ func TestLatest(t *testing.T) { for _, tt := range latestTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -221,7 +218,7 @@ func TestReadFile(t *testing.T) { for _, tt := range readFileTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -412,7 +409,7 @@ func TestReadZip(t *testing.T) { for _, tt := range readZipTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -581,7 +578,7 @@ func TestStat(t *testing.T) { for _, tt := range statTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go index f817a04583..dfef9f73c2 100644 --- a/src/cmd/go/internal/modfetch/coderepo.go +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -864,22 +864,25 @@ func (r *codeRepo) GoMod(version string) (data []byte, err error) { data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod) if err != nil { if os.IsNotExist(err) { - return r.legacyGoMod(rev, dir), nil + return LegacyGoMod(r.modPath), nil } return nil, err } return data, nil } -func (r *codeRepo) legacyGoMod(rev, dir string) []byte { - // We used to try to build a go.mod reflecting pre-existing - // package management metadata files, but the conversion - // was inherently imperfect (because those files don't have - // exactly the same semantics as go.mod) and, when done - // for dependencies in the middle of a build, impossible to - // correct. So we stopped. - // Return a fake go.mod that simply declares the module path. - return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(r.modPath))) +// LegacyGoMod generates a fake go.mod file for a module that doesn't have one. +// The go.mod file contains a module directive and nothing else: no go version, +// no requirements. +// +// We used to try to build a go.mod reflecting pre-existing +// package management metadata files, but the conversion +// was inherently imperfect (because those files don't have +// exactly the same semantics as go.mod) and, when done +// for dependencies in the middle of a build, impossible to +// correct. So we stopped. +func LegacyGoMod(modPath string) []byte { + return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(modPath))) } func (r *codeRepo) modPrefix(rev string) string { diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 7b3525e914..408b2860ad 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -22,6 +22,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" + "cmd/go/internal/fsys" "cmd/go/internal/lockedfile" "cmd/go/internal/par" "cmd/go/internal/robustio" @@ -416,7 +417,18 @@ func initGoSum() (bool, error) { goSum.m = make(map[module.Version][]string) goSum.status = make(map[modSum]modSumStatus) - data, err := lockedfile.Read(GoSumFile) + var ( + data []byte + err error + ) + if actualSumFile, ok := fsys.OverlayPath(GoSumFile); ok { + // Don't lock go.sum if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(actualSumFile) + } else { + data, err = lockedfile.Read(GoSumFile) + } if err != nil && !os.IsNotExist(err) { return false, err } @@ -718,6 +730,9 @@ Outer: if readonly { return ErrGoSumDirty } + if _, ok := fsys.OverlayPath(GoSumFile); ok { + base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay") + } // Make a best-effort attempt to acquire the side lock, only to exclude // previous versions of the 'go' command from making simultaneous edits. diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 00dfc8b2dc..a3337d6d23 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -191,7 +191,7 @@ type Root int const ( // AutoRoot is the default for most commands. modload.Init will look for // a go.mod file in the current directory or any parent. If none is found, - // modules may be disabled (GO111MODULE=on) or commands may run in a + // modules may be disabled (GO111MODULE=auto) or commands may run in a // limited module mode. AutoRoot Root = iota @@ -1364,6 +1364,13 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements) } return } + gomod := ModFilePath() + if _, ok := fsys.OverlayPath(gomod); ok { + if dirty { + base.Fatalf("go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay") + } + return + } new, err := modFile.Format() if err != nil { diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index a643cca0a9..67d7ec65da 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -715,20 +715,6 @@ func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path s return ".", module.Version{} } -// TargetPackages returns the list of packages in the target (top-level) module -// matching pattern, which may be relative to the working directory, under all -// build tag settings. -func TargetPackages(ctx context.Context, pattern string) *search.Match { - // TargetPackages is relative to the main module, so ensure that the main - // module is a thing that can contain packages. - LoadModFile(ctx) // Sets Target. - ModRoot() // Emits an error if Target cannot contain packages. - - m := search.NewMatch(pattern) - matchPackages(ctx, m, imports.AnyTags(), omitStd, MainModules.Versions()) - return m -} - // ImportMap returns the actual package import path // for an import path found in source code. // If the given import path does not appear in the source code @@ -760,29 +746,6 @@ func PackageModule(path string) module.Version { return pkg.mod } -// PackageImports returns the imports for the package named by the import path. -// Test imports will be returned as well if tests were loaded for the package -// (i.e., if "all" was loaded or if LoadTests was set and the path was matched -// by a command line argument). PackageImports will return nil for -// unknown package paths. -func PackageImports(path string) (imports, testImports []string) { - pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) - if !ok { - return nil, nil - } - imports = make([]string, len(pkg.imports)) - for i, p := range pkg.imports { - imports[i] = p.path - } - if pkg.test != nil { - testImports = make([]string, len(pkg.test.imports)) - for i, p := range pkg.test.imports { - testImports[i] = p.path - } - } - return imports, testImports -} - // Lookup returns the source directory, import path, and any loading error for // the package at path as imported from the package in parentDir. // Lookup requires that one of the Load functions in this package has already @@ -1883,7 +1846,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements) fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", ld.TidyCompatibleVersion, goFlag, ld.GoVersion) // TODO(#46141): Populate the linked wiki page. - fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/wiki/PruningModules\n") + fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/doc/modules/pruning\n") } mg, err := rs.Graph(ctx) diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 79126a46b5..31e79a3646 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "os" "path/filepath" "strings" "sync" @@ -15,6 +16,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" + "cmd/go/internal/fsys" "cmd/go/internal/lockedfile" "cmd/go/internal/modfetch" "cmd/go/internal/par" @@ -614,39 +616,14 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { } c := rawGoModSummaryCache.Do(m, func() interface{} { summary := new(modFileSummary) - var f *modfile.File - if m.Version == "" { - // m is a replacement module with only a file path. - dir := m.Path - if !filepath.IsAbs(dir) { - dir = filepath.Join(ModRoot(), dir) - } - gomod := filepath.Join(dir, "go.mod") - - data, err := lockedfile.Read(gomod) - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))} - } - f, err = modfile.ParseLax(gomod, data, nil) - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err))} - } - } else { - if !semver.IsValid(m.Version) { - // Disallow the broader queries supported by fetch.Lookup. - base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) - } - - data, err := modfetch.GoMod(m.Path, m.Version) - if err != nil { - return cached{nil, err} - } - f, err = modfile.ParseLax("go.mod", data, nil) - if err != nil { - return cached{nil, module.VersionError(m, fmt.Errorf("parsing go.mod: %v", err))} - } + name, data, err := rawGoModData(m) + if err != nil { + return cached{nil, err} + } + f, err := modfile.ParseLax(name, data, nil) + if err != nil { + return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(name), err))} } - if f.Module != nil { summary.module = f.Module.Mod summary.deprecated = f.Module.Deprecated @@ -682,6 +659,43 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result +// rawGoModData returns the content of the go.mod file for module m, ignoring +// all replacements that may apply to m. +// +// rawGoModData cannot be used on the Target module. +// +// Unlike rawGoModSummary, rawGoModData does not cache its results in memory. +// Use rawGoModSummary instead unless you specifically need these bytes. +func rawGoModData(m module.Version) (name string, data []byte, err error) { + if m.Version == "" { + // m is a replacement module with only a file path. + dir := m.Path + if !filepath.IsAbs(dir) { + dir = filepath.Join(ModRoot(), dir) + } + name = filepath.Join(dir, "go.mod") + if gomodActual, ok := fsys.OverlayPath(name); ok { + // Don't lock go.mod if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(gomodActual) + } else { + data, err = lockedfile.Read(gomodActual) + } + if err != nil { + return "", nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(name), err)) + } + } else { + if !semver.IsValid(m.Version) { + // Disallow the broader queries supported by fetch.Lookup. + base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version) + } + name = "go.mod" + data, err = modfetch.GoMod(m.Path, m.Version) + } + return name, data, err +} + // queryLatestVersionIgnoringRetractions looks up the latest version of the // module with the given path without considering retracted or excluded // versions. diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index ba137eda1d..a7031856ae 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -5,13 +5,13 @@ package modload import ( + "bytes" "context" "errors" "fmt" "io/fs" "os" pathpkg "path" - "path/filepath" "sort" "strings" "sync" @@ -933,8 +933,8 @@ func (e *PackageNotInModuleError) ImportPath() string { return "" } -// ModuleHasRootPackage returns whether module m contains a package m.Path. -func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { +// moduleHasRootPackage returns whether module m contains a package m.Path. +func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { needSum := false root, isLocal, err := fetch(ctx, m, needSum) if err != nil { @@ -944,14 +944,32 @@ func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { return ok, err } -func versionHasGoMod(ctx context.Context, m module.Version) (bool, error) { - needSum := false - root, _, err := fetch(ctx, m, needSum) +// versionHasGoMod returns whether a version has a go.mod file. +// +// versionHasGoMod fetches the go.mod file (possibly a fake) and true if it +// contains anything other than a module directive with the same path. When a +// module does not have a real go.mod file, the go command acts as if it had one +// that only contained a module directive. Normal go.mod files created after +// 1.12 at least have a go directive. +// +// This function is a heuristic, since it's possible to commit a file that would +// pass this test. However, we only need a heurstic for determining whether +// +incompatible versions may be "latest", which is what this function is used +// for. +// +// This heuristic is useful for two reasons: first, when using a proxy, +// this lets us fetch from the .mod endpoint which is much faster than the .zip +// endpoint. The .mod file is used anyway, even if the .zip file contains a +// go.mod with different content. Second, if we don't fetch the .zip, then +// we don't need to verify it in go.sum. This makes 'go list -m -u' faster +// and simpler. +func versionHasGoMod(_ context.Context, m module.Version) (bool, error) { + _, data, err := rawGoModData(m) if err != nil { return false, err } - fi, err := os.Stat(filepath.Join(root, "go.mod")) - return err == nil && !fi.IsDir(), nil + isFake := bytes.Equal(data, modfetch.LegacyGoMod(m.Path)) + return !isFake, nil } // A versionRepo is a subset of modfetch.Repo that can report information about diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 6c646ebf28..f7fae9fdd9 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -252,8 +252,15 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { ccExe := b.ccExe() fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags) - if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil { - fmt.Fprintf(h, "CC ID=%q\n", ccID) + // Include the C compiler tool ID so that if the C + // compiler changes we rebuild the package. + // But don't do that for standard library packages like net, + // so that the prebuilt .a files from a Go binary install + // don't need to be rebuilt with the local compiler. + if !p.Standard { + if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil { + fmt.Fprintf(h, "CC ID=%q\n", ccID) + } } if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 { cxxExe := b.cxxExe() diff --git a/src/cmd/go/testdata/script/mod_overlay.txt b/src/cmd/go/testdata/script/mod_overlay.txt index 92e79c725a..86ab04bd3c 100644 --- a/src/cmd/go/testdata/script/mod_overlay.txt +++ b/src/cmd/go/testdata/script/mod_overlay.txt @@ -21,7 +21,7 @@ go list -deps -overlay overlay.json . cd $WORK/gopath/src/get-doesnt-add-dep cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod ! go get -d -overlay overlay.json . -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod # Content of overlaid go.sum is used. @@ -41,10 +41,10 @@ go mod verify -overlay overlay.json # attempting to update the file cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums ! go get -d -overlay overlay.json . -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums ! go mod tidy -overlay overlay.json -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums # -overlay works with -modfile. @@ -56,7 +56,7 @@ go list -modfile=alternate.mod -overlay overlay.json . stdout 'found.the/module' # Even with -modfile, overlaid files can't be opened for write. ! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' # Carving out a module by adding an overlaid go.mod file cd $WORK/gopath/src/carve @@ -78,7 +78,7 @@ go list -overlay overlay.json all stdout ^carve2/nomod$ # Editing go.mod file fails because overlay is read only ! go get -overlay overlay.json -d rsc.io/quote -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' ! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod # Editing go.mod file succeeds because we use -modfile to redirect to same file go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt index ed1dd53eff..c544cb7413 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_ambiguous.txt @@ -23,7 +23,7 @@ cp go.mod go.mod.orig stderr '^example\.com/m imports\n\texample\.net/indirect imports\n\texample\.net/ambiguous/nested/pkg loaded from example\.net/ambiguous/nested@v0\.1\.0,\n\tbut go 1.16 would fail to locate it:\n\tambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0.1.0 \(.*\)\n\texample\.net/ambiguous/nested v0.1.0 \(.*\)\n\n' -stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' cmp go.mod go.mod.orig diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt index 3aacde2025..dcf13e2049 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_deleted.txt @@ -19,7 +19,7 @@ cp go.mod go.mod.orig stderr '^example\.com/m imports\n\texample\.net/deleted loaded from example\.net/deleted@v0\.1\.0,\n\tbut go 1\.16 would fail to locate it in example\.net/deleted@v0\.2\.0\n\n' -stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' # The suggested 'go mod tidy -e' command should proceed anyway. diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt index e00aea930e..186a3f8e67 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_implicit.txt @@ -33,7 +33,7 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' cp go.mod go.mod.orig ! go mod tidy stderr '^example\.com/m imports\n\texample\.net/lazy tested by\n\texample\.net/lazy.test imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' -stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' cmp go.mod go.mod.orig diff --git a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt index 2d8726544a..ea9e42e87e 100644 --- a/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt +++ b/src/cmd/go/testdata/script/mod_tidy_compat_incompatible.txt @@ -33,7 +33,7 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}' cp go.mod go.mod.orig ! go mod tidy stderr '^example\.com/m imports\n\texample\.net/lazy imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' -stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' +stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n' cmp go.mod go.mod.orig diff --git a/src/cmd/go/testdata/script/mod_update_sum_readonly.txt b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt new file mode 100644 index 0000000000..41f12e4084 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_update_sum_readonly.txt @@ -0,0 +1,34 @@ +# When finding the latest version of a module, we should not download version +# contents. Previously, we downloaded .zip files to determine whether a real +# .mod file was present in order to decide whether +incompatible versions +# could be "latest". +# +# Verifies #47377. + +# rsc.io/breaker has two versions, neither of which has a .mod file. +go list -m -versions rsc.io/breaker +stdout '^rsc.io/breaker v1.0.0 v2.0.0\+incompatible$' +go mod download rsc.io/breaker@v1.0.0 +! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.mod +go mod download rsc.io/breaker@v2.0.0+incompatible +! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.mod + +# Delete downloaded .zip files. +go clean -modcache + +# Check for updates. +go list -m -u rsc.io/breaker +stdout '^rsc.io/breaker v1.0.0 \[v2.0.0\+incompatible\]$' + +# We should not have downloaded zips. +! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.zip +! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.zip + +-- go.mod -- +module m + +go 1.16 + +require rsc.io/breaker v1.0.0 +-- go.sum -- +rsc.io/breaker v1.0.0/go.mod h1:s5yxDXvD88U1/ESC23I2FK3Lkv4YIKaB1ij/Hbm805g= |