v.io/x/lib/gosh: have BuildGoPkg respect -o <file>
Change-Id: I68a065c4031dad8426d8ae7191279a2ad2d76852
diff --git a/gosh/shell.go b/gosh/shell.go
index 637c7ce..69fd4fc 100644
--- a/gosh/shell.go
+++ b/gosh/shell.go
@@ -15,6 +15,7 @@
import (
"errors"
"fmt"
+ "io"
"io/ioutil"
"log"
"math/rand"
@@ -135,7 +136,8 @@
}
// BuildGoPkg compiles a Go package using the "go build" command and writes the
-// resulting binary to sh.Opts.BinDir. Returns the absolute path to the binary.
+// resulting binary to sh.Opts.BinDir unless the -o flag was specified.
+// Returns the absolute path to the binary.
// Included in Shell for convenience, but could have just as easily been
// provided as a utility function.
func (sh *Shell) BuildGoPkg(pkg string, flags ...string) string {
@@ -357,8 +359,49 @@
return nil
}
+func copyfile(from, to string) error {
+ fi, err := os.Stat(from)
+ if err != nil {
+ return err
+ }
+ mode := fi.Mode()
+ in, err := os.Open(from)
+ if err != nil {
+ return err
+ }
+ defer in.Close()
+ out, err := os.OpenFile(to, os.O_CREATE|os.O_RDWR|os.O_TRUNC, mode)
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+ _, err = io.Copy(out, in)
+ cerr := out.Close()
+ if err != nil {
+ return err
+ }
+ return cerr
+}
+
+func extractOutputFlag(flags ...string) (string, []string) {
+ for i, f := range flags {
+ if f == "-o" && len(flags) > i {
+ return flags[i+1], append(flags[:i], flags[i+2:]...)
+ }
+ }
+ return "", flags
+}
+
func (sh *Shell) buildGoPkg(pkg string, flags ...string) (string, error) {
+ outputFlag, flags := extractOutputFlag(flags...)
binPath := filepath.Join(sh.Opts.BinDir, path.Base(pkg))
+ if outputFlag != "" {
+ if filepath.IsAbs(outputFlag) {
+ binPath = outputFlag
+ } else {
+ binPath = filepath.Join(sh.Opts.BinDir, outputFlag)
+ }
+ }
// If this binary has already been built, don't rebuild it.
if _, err := os.Stat(binPath); err == nil {
return binPath, nil
@@ -372,6 +415,9 @@
}
defer os.RemoveAll(tempDir)
tempBinPath := filepath.Join(tempDir, path.Base(pkg))
+ if outputFlag != "" {
+ tempBinPath = filepath.Join(tempDir, filepath.Base(binPath))
+ }
args := []string{"build", "-o", tempBinPath}
args = append(args, flags...)
args = append(args, pkg)
@@ -383,6 +429,9 @@
return "", err
}
if err := sh.rename(tempBinPath, binPath); err != nil {
+ if _, ok := err.(*os.LinkError); ok {
+ return "", copyfile(tempBinPath, binPath)
+ }
return "", err
}
return binPath, nil
diff --git a/gosh/shell_test.go b/gosh/shell_test.go
index 29d4f09..66a01a9 100644
--- a/gosh/shell_test.go
+++ b/gosh/shell_test.go
@@ -28,7 +28,7 @@
"time"
"v.io/x/lib/gosh"
- "v.io/x/lib/gosh/internal/gosh_example_lib"
+ lib "v.io/x/lib/gosh/internal/gosh_example_lib"
)
var fakeError = errors.New("fake error")
@@ -219,6 +219,23 @@
binPath = sh.BuildGoPkg("v.io/x/lib/gosh/internal/gosh_example_client")
c = sh.Cmd(binPath, "-addr="+addr)
eq(t, c.Stdout(), "Hello, world!\n")
+
+ // Run client built using -o with absolute and relative names
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ absName := filepath.Join(cwd, "x")
+ binPath = sh.BuildGoPkg("v.io/x/lib/gosh/internal/gosh_example_client", "-o", absName)
+ defer os.Remove(absName)
+ c = sh.Cmd(absName, "-addr="+addr)
+ eq(t, c.Stdout(), "Hello, world!\n")
+
+ binPath = sh.BuildGoPkg("v.io/x/lib/gosh/internal/gosh_example_client", "-o", "y")
+ relname := filepath.Join(sh.Opts.BinDir, "y")
+ defer os.Remove(relname)
+ c = sh.Cmd(relname, "-addr="+addr)
+ eq(t, c.Stdout(), "Hello, world!\n")
}
var (