]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: clean up after 'go build' during 'go install'
authorRuss Cox <rsc@golang.org>
Mon, 20 Apr 2015 04:37:37 +0000 (00:37 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 4 Jun 2015 04:12:32 +0000 (04:12 +0000)
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
<test, mostly works, make small change>
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 <r@golang.org>
src/cmd/go/build.go
src/cmd/go/test.bash

index 2f88a1f883648d7e3e31c42e49f464bdf4c4f873..ec74ea41330c310371f20f6a1f32b44e69dbb3b9 100644 (file)
@@ -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)
index 6d4213c7380a122dc3600606520f0bfef999fb47..4f36584de38216ab05f69a085df5beaaf1102e6c 100755 (executable)
@@ -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