Commit 9e0e6981 authored by Russ Cox's avatar Russ Cox

cmd/go: fix go list .Stale computation

If X depends on Y and X was installed but Y is only present in the cache
(as happens when you "go install X") then we should report X as up-to-date,
not as stale.

This applies whether X is a package or a main binary.

Fixes #24558.
Fixes #23818.

Change-Id: I26a0b375b1f7f7ac909cc0db68e92f4e04529208
Reviewed-on: https://go-review.googlesource.com/107957
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
parent 7500b299
...@@ -790,6 +790,7 @@ func TestRebuilding(t *testing.T) { ...@@ -790,6 +790,7 @@ func TestRebuilding(t *testing.T) {
// If the .a file is newer than the .so, the .so is rebuilt (but not the .a) // If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
t.Run("newarchive", func(t *testing.T) { t.Run("newarchive", func(t *testing.T) {
resetFileStamps() resetFileStamps()
AssertNotRebuilt(t, "new .a file before build", filepath.Join(gopathInstallDir, "depBase.a"))
goCmd(t, "list", "-linkshared", "-f={{.ImportPath}} {{.Stale}} {{.StaleReason}} {{.Target}}", "depBase") goCmd(t, "list", "-linkshared", "-f={{.ImportPath}} {{.Stale}} {{.StaleReason}} {{.Target}}", "depBase")
AssertNotRebuilt(t, "new .a file before build", filepath.Join(gopathInstallDir, "depBase.a")) AssertNotRebuilt(t, "new .a file before build", filepath.Join(gopathInstallDir, "depBase.a"))
cleanup := touch(t, filepath.Join(gopathInstallDir, "depBase.a")) cleanup := touch(t, filepath.Join(gopathInstallDir, "depBase.a"))
......
...@@ -5121,6 +5121,28 @@ func TestCacheOutput(t *testing.T) { ...@@ -5121,6 +5121,28 @@ func TestCacheOutput(t *testing.T) {
} }
} }
func TestCacheListStale(t *testing.T) {
tooSlow(t)
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
t.Skip("GODEBUG gocacheverify")
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.makeTempdir()
tg.setenv("GOCACHE", tg.path("cache"))
tg.tempFile("gopath/src/p/p.go", "package p; import _ \"q\"; func F(){}\n")
tg.tempFile("gopath/src/q/q.go", "package q; func F(){}\n")
tg.tempFile("gopath/src/m/m.go", "package main; import _ \"q\"; func main(){}\n")
tg.setenv("GOPATH", tg.path("gopath"))
tg.run("install", "p", "m")
tg.run("list", "-f={{.ImportPath}} {{.Stale}}", "m", "q", "p")
tg.grepStdout("^m false", "m should not be stale")
tg.grepStdout("^q true", "q should be stale")
tg.grepStdout("^p false", "p should not be stale")
}
func TestCacheCoverage(t *testing.T) { func TestCacheCoverage(t *testing.T) {
tooSlow(t) tooSlow(t)
......
...@@ -397,15 +397,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID ...@@ -397,15 +397,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
// If so, it's up to date and we can reuse it instead of rebuilding it. // If so, it's up to date and we can reuse it instead of rebuilding it.
var buildID string var buildID string
if target != "" && !cfg.BuildA { if target != "" && !cfg.BuildA {
var err error buildID, _ = buildid.ReadFile(target)
buildID, err = buildid.ReadFile(target)
if err != nil && b.ComputeStaleOnly {
if p != nil && !p.Stale {
p.Stale = true
p.StaleReason = "target missing"
}
return true
}
if strings.HasPrefix(buildID, actionID+buildIDSeparator) { if strings.HasPrefix(buildID, actionID+buildIDSeparator) {
a.buildID = buildID a.buildID = buildID
a.built = target a.built = target
...@@ -482,7 +474,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID ...@@ -482,7 +474,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
} }
} }
} }
return true
// Fall through to update a.buildID from the build artifact cache,
// which will affect the computation of buildIDs for targets
// higher up in the dependency graph.
} }
// Check the build artifact cache. // Check the build artifact cache.
...@@ -510,6 +505,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID ...@@ -510,6 +505,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
a.built = file a.built = file
a.Target = "DO NOT USE - using cache" a.Target = "DO NOT USE - using cache"
a.buildID = buildID a.buildID = buildID
if p := a.Package; p != nil {
// Clearer than explaining that something else is stale.
p.StaleReason = "not installed but available in build cache"
}
return true return true
} }
} }
...@@ -520,6 +519,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID ...@@ -520,6 +519,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
a.output = []byte{} a.output = []byte{}
} }
if b.ComputeStaleOnly {
return true
}
return false return false
} }
......
...@@ -1124,7 +1124,7 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) { ...@@ -1124,7 +1124,7 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) {
// We want to hide that awful detail as much as possible, so don't // We want to hide that awful detail as much as possible, so don't
// advertise it by touching the mtimes (usually the libraries are up // advertise it by touching the mtimes (usually the libraries are up
// to date). // to date).
if !a.buggyInstall { if !a.buggyInstall && !b.ComputeStaleOnly {
now := time.Now() now := time.Now()
os.Chtimes(a.Target, now, now) os.Chtimes(a.Target, now, now)
} }
......
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