From: Russ Cox Date: Mon, 20 Apr 2015 04:37:37 +0000 (-0400) Subject: cmd/go: clean up after 'go build' during 'go install' X-Git-Tag: go1.5beta1~369 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=227fb116bede3b09ba7399303ebac36eec43ff8a;p=gostls13.git cmd/go: clean up after 'go build' during 'go install' If 'go install' (with no arguments, meaning the current directory) succeeds, remove the executable written by 'go build', if present. This avoids leaving a stale binary behind during a sequence like: go build go install Before this CL, the current directory still has the stale binary from 'go build'. If $PATH contains dot, running the name of the program will find this stale binary instead of the new, installed one. Remove the 'go build' target during 'go install', both to clean up the directory and to avoid accidentally running the stale binary. Another way to view this CL is that it makes the go command behave as if 'go install' is implemented by 'go build' followed by moving the resulting binary to the install location. See #9645 for discussion and objections. Fixes #9645. Change-Id: Ide109572f96bbb5a35be45dda17738317462a7d4 Reviewed-on: https://go-review.googlesource.com/10682 Reviewed-by: Rob Pike --- diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 2f88a1f883..ec74ea4133 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -540,6 +540,30 @@ func runInstall(cmd *Command, args []string) { } } b.do(a) + exitIfErrors() + + // Success. If this command is 'go install' with no arguments + // and the current directory (the implicit argument) is a command, + // remove any leftover command binary from a previous 'go build'. + // The binary is installed; it's not needed here anymore. + // And worse it might be a stale copy, which you don't want to find + // instead of the installed one if $PATH contains dot. + // One way to view this behavior is that it is as if 'go install' first + // runs 'go build' and the moves the generated file to the install dir. + // See issue 9645. + if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" { + // Compute file 'go build' would have created. + // If it exists and is an executable file, remove it. + _, targ := filepath.Split(pkgs[0].ImportPath) + targ += exeSuffix + fi, err := os.Stat(targ) + if err == nil { + m := fi.Mode() + if m.IsRegular() && m&0111 != 0 { + os.Remove(targ) + } + } + } } // Global build parameters (used during package load) diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 6d4213c738..4f36584de3 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -96,6 +96,55 @@ elif grep -q runtime $d/err.out; then fi rm -r $d +TEST 'go install cleans up after go build' +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +export GOPATH=$d +mkdir -p $d/src/mycmd +echo 'package main; func main(){}' >$d/src/mycmd/main.go +old=$(pwd) +cd $d/src/mycmd +"$old/testgo" build +if [ ! -x mycmd ]; then + echo "testgo build did not write command binary" + ok=false +fi +"$old/testgo" install +if [ -e mycmd ]; then + echo "testgo install did not remove command binary" + ok=false +fi +"$old/testgo" build +if [ ! -x mycmd ]; then + echo "testgo build did not write command binary (second time)" + ok=false +fi +# install with arguments does not remove the target, +# even in the same directory +"$old/testgo" install mycmd +if [ ! -e mycmd ]; then + echo "testgo install mycmd removed command binary when run in mycmd" + ok=false +fi +"$old/testgo" build +if [ ! -x mycmd ]; then + echo "testgo build did not write command binary (third time)" + ok=false +fi +# and especially not outside the directory +cd $d +cp src/mycmd/mycmd . +"$old/testgo" install mycmd +if [ ! -e $d/src/mycmd/mycmd ]; then + echo "testgo install mycmd removed command binary from its source dir when run outside mycmd" + ok=false +fi +if [ ! -e $d/mycmd ]; then + echo "testgo install mycmd removed command binary from current dir when run outside mycmd" + ok=false +fi +cd "$old" +rm -r $d + TEST 'go install rebuilds stale packages in other GOPATH' d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) export GOPATH=$d/d1:$d/d2