summaryrefslogtreecommitdiff
path: root/libgo/go/os/exec/exec.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/os/exec/exec.go')
-rw-r--r--libgo/go/os/exec/exec.go56
1 files changed, 50 insertions, 6 deletions
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index 4680036fddc..a70ed0d20cb 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -13,7 +13,9 @@ import (
"io"
"os"
"path/filepath"
+ "runtime"
"strconv"
+ "strings"
"sync"
"syscall"
)
@@ -237,13 +239,51 @@ func (c *Cmd) Run() error {
return c.Wait()
}
+// lookExtensions finds windows executable by its dir and path.
+// It uses LookPath to try appropriate extensions.
+// lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
+func lookExtensions(path, dir string) (string, error) {
+ if filepath.Base(path) == path {
+ path = filepath.Join(".", path)
+ }
+ if dir == "" {
+ return LookPath(path)
+ }
+ if filepath.VolumeName(path) != "" {
+ return LookPath(path)
+ }
+ if len(path) > 1 && os.IsPathSeparator(path[0]) {
+ return LookPath(path)
+ }
+ dirandpath := filepath.Join(dir, path)
+ // We assume that LookPath will only add file extension.
+ lp, err := LookPath(dirandpath)
+ if err != nil {
+ return "", err
+ }
+ ext := strings.TrimPrefix(lp, dirandpath)
+ return path + ext, nil
+}
+
// Start starts the specified command but does not wait for it to complete.
+//
+// The Wait method will return the exit code and release associated resources
+// once the command exits.
func (c *Cmd) Start() error {
if c.lookPathErr != nil {
c.closeDescriptors(c.closeAfterStart)
c.closeDescriptors(c.closeAfterWait)
return c.lookPathErr
}
+ if runtime.GOOS == "windows" {
+ lp, err := lookExtensions(c.Path, c.Dir)
+ if err != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
+ return err
+ }
+ c.Path = lp
+ }
if c.Process != nil {
return errors.New("exec: already started")
}
@@ -304,6 +344,8 @@ func (e *ExitError) Error() string {
// If the command fails to run or doesn't complete successfully, the
// error is of type *ExitError. Other error types may be
// returned for I/O problems.
+//
+// Wait releases any resources associated with the Cmd.
func (c *Cmd) Wait() error {
if c.Process == nil {
return errors.New("exec: not started")
@@ -387,15 +429,17 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
type closeOnce struct {
*os.File
- close sync.Once
- closeErr error
+ once sync.Once
+ err error
}
func (c *closeOnce) Close() error {
- c.close.Do(func() {
- c.closeErr = c.File.Close()
- })
- return c.closeErr
+ c.once.Do(c.close)
+ return c.err
+}
+
+func (c *closeOnce) close() {
+ c.err = c.File.Close()
}
// StdoutPipe returns a pipe that will be connected to the command's