summaryrefslogtreecommitdiff
path: root/src/pkg/exec
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/exec')
-rw-r--r--src/pkg/exec/Makefile16
-rw-r--r--src/pkg/exec/exec.go46
-rw-r--r--src/pkg/exec/exec_test.go46
-rw-r--r--src/pkg/exec/lp_unix.go45
-rw-r--r--src/pkg/exec/lp_windows.go66
5 files changed, 170 insertions, 49 deletions
diff --git a/src/pkg/exec/Makefile b/src/pkg/exec/Makefile
index 9d88b8d8a..262ecac85 100644
--- a/src/pkg/exec/Makefile
+++ b/src/pkg/exec/Makefile
@@ -2,10 +2,24 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=exec
GOFILES=\
exec.go\
+GOFILES_freebsd=\
+ lp_unix.go\
+
+GOFILES_darwin=\
+ lp_unix.go\
+
+GOFILES_linux=\
+ lp_unix.go\
+
+GOFILES_windows=\
+ lp_windows.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
include ../../Make.pkg
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go
index ee3cec686..ba9bd2472 100644
--- a/src/pkg/exec/exec.go
+++ b/src/pkg/exec/exec.go
@@ -7,7 +7,6 @@ package exec
import (
"os"
- "strings"
)
// Arguments to Run.
@@ -39,7 +38,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
if fd == 0 {
rw = os.O_RDONLY
}
- f, err := os.Open("/dev/null", rw, 0)
+ f, err := os.Open(os.DevNull, rw, 0)
return f, nil, err
case PassThrough:
switch fd {
@@ -63,7 +62,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
return nil, nil, os.EINVAL
}
-// Run starts the binary prog running with
+// Run starts the named binary running with
// arguments argv and environment envv.
// It returns a pointer to a new Cmd representing
// the command or an error.
@@ -78,7 +77,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
// of the returned Cmd is the other end of the pipe.
// Otherwise the field in Cmd is nil.
-func Run(argv0 string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
+func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
p = new(Cmd)
var fd [3]*os.File
@@ -95,7 +94,7 @@ func Run(argv0 string, argv, envv []string, dir string, stdin, stdout, stderr in
}
// Run command.
- p.Pid, err = os.ForkExec(argv0, argv, envv, dir, fd[0:])
+ p.Pid, err = os.ForkExec(name, argv, envv, dir, fd[0:])
if err != nil {
goto Error
}
@@ -182,40 +181,3 @@ func (p *Cmd) Close() os.Error {
}
return err
}
-
-func canExec(file string) bool {
- d, err := os.Stat(file)
- if err != nil {
- return false
- }
- return d.IsRegular() && d.Permission()&0111 != 0
-}
-
-// LookPath searches for an executable binary named file
-// in the directories named by the PATH environment variable.
-// If file contains a slash, it is tried directly and the PATH is not consulted.
-//
-// TODO(rsc): Does LookPath belong in os instead?
-func LookPath(file string) (string, os.Error) {
- // NOTE(rsc): I wish we could use the Plan 9 behavior here
- // (only bypass the path if file begins with / or ./ or ../)
- // but that would not match all the Unix shells.
-
- if strings.Index(file, "/") >= 0 {
- if canExec(file) {
- return file, nil
- }
- return "", os.ENOENT
- }
- pathenv := os.Getenv("PATH")
- for _, dir := range strings.Split(pathenv, ":", -1) {
- if dir == "" {
- // Unix shell semantics: path element "" means "."
- dir = "."
- }
- if canExec(dir + "/" + file) {
- return dir + "/" + file, nil
- }
- }
- return "", os.ENOENT
-}
diff --git a/src/pkg/exec/exec_test.go b/src/pkg/exec/exec_test.go
index 3e4ab7d78..3a3d3b1a5 100644
--- a/src/pkg/exec/exec_test.go
+++ b/src/pkg/exec/exec_test.go
@@ -8,11 +8,24 @@ import (
"io"
"io/ioutil"
"testing"
+ "os"
+ "runtime"
)
+func run(argv []string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
+ if runtime.GOOS == "windows" {
+ argv = append([]string{"cmd", "/c"}, argv...)
+ }
+ exe, err := LookPath(argv[0])
+ if err != nil {
+ return nil, err
+ }
+ p, err = Run(exe, argv, nil, "", stdin, stdout, stderr)
+ return p, err
+}
+
func TestRunCat(t *testing.T) {
- cmd, err := Run("/bin/cat", []string{"cat"}, nil, "",
- Pipe, Pipe, DevNull)
+ cmd, err := run([]string{"cat"}, Pipe, Pipe, DevNull)
if err != nil {
t.Fatal("run:", err)
}
@@ -31,7 +44,7 @@ func TestRunCat(t *testing.T) {
}
func TestRunEcho(t *testing.T) {
- cmd, err := Run("/bin/echo", []string{"echo", "hello", "world"}, nil, "",
+ cmd, err := run([]string{"sh", "-c", "echo hello world"},
DevNull, Pipe, DevNull)
if err != nil {
t.Fatal("run:", err)
@@ -49,7 +62,7 @@ func TestRunEcho(t *testing.T) {
}
func TestStderr(t *testing.T) {
- cmd, err := Run("/bin/sh", []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
+ cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"},
DevNull, DevNull, Pipe)
if err != nil {
t.Fatal("run:", err)
@@ -66,9 +79,8 @@ func TestStderr(t *testing.T) {
}
}
-
func TestMergeWithStdout(t *testing.T) {
- cmd, err := Run("/bin/sh", []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
+ cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"},
DevNull, Pipe, MergeWithStdout)
if err != nil {
t.Fatal("run:", err)
@@ -84,3 +96,25 @@ func TestMergeWithStdout(t *testing.T) {
t.Fatal("close:", err)
}
}
+
+func TestAddEnvVar(t *testing.T) {
+ err := os.Setenv("NEWVAR", "hello world")
+ if err != nil {
+ t.Fatal("setenv:", err)
+ }
+ cmd, err := run([]string{"sh", "-c", "echo $NEWVAR"},
+ DevNull, Pipe, DevNull)
+ if err != nil {
+ t.Fatal("run:", err)
+ }
+ buf, err := ioutil.ReadAll(cmd.Stdout)
+ if err != nil {
+ t.Fatal("read:", err)
+ }
+ if string(buf) != "hello world\n" {
+ t.Fatalf("read: got %q", buf)
+ }
+ if err = cmd.Close(); err != nil {
+ t.Fatal("close:", err)
+ }
+}
diff --git a/src/pkg/exec/lp_unix.go b/src/pkg/exec/lp_unix.go
new file mode 100644
index 000000000..292e24fcc
--- /dev/null
+++ b/src/pkg/exec/lp_unix.go
@@ -0,0 +1,45 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+func canExec(file string) bool {
+ d, err := os.Stat(file)
+ if err != nil {
+ return false
+ }
+ return d.IsRegular() && d.Permission()&0111 != 0
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the PATH environment variable.
+// If file contains a slash, it is tried directly and the PATH is not consulted.
+func LookPath(file string) (string, os.Error) {
+ // NOTE(rsc): I wish we could use the Plan 9 behavior here
+ // (only bypass the path if file begins with / or ./ or ../)
+ // but that would not match all the Unix shells.
+
+ if strings.Contains(file, "/") {
+ if canExec(file) {
+ return file, nil
+ }
+ return "", &os.PathError{"lookpath", file, os.ENOENT}
+ }
+ pathenv := os.Getenv("PATH")
+ for _, dir := range strings.Split(pathenv, ":", -1) {
+ if dir == "" {
+ // Unix shell semantics: path element "" means "."
+ dir = "."
+ }
+ if canExec(dir + "/" + file) {
+ return dir + "/" + file, nil
+ }
+ }
+ return "", &os.PathError{"lookpath", file, os.ENOENT}
+}
diff --git a/src/pkg/exec/lp_windows.go b/src/pkg/exec/lp_windows.go
new file mode 100644
index 000000000..7b56afa85
--- /dev/null
+++ b/src/pkg/exec/lp_windows.go
@@ -0,0 +1,66 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+func chkStat(file string) bool {
+ d, err := os.Stat(file)
+ if err != nil {
+ return false
+ }
+ return d.IsRegular()
+}
+
+func canExec(file string, exts []string) (string, bool) {
+ if len(exts) == 0 {
+ return file, chkStat(file)
+ }
+ f := strings.ToLower(file)
+ for _, e := range exts {
+ if strings.HasSuffix(f, e) {
+ return file, chkStat(file)
+ }
+ }
+ for _, e := range exts {
+ if f := file + e; chkStat(f) {
+ return f, true
+ }
+ }
+ return ``, false
+}
+
+func LookPath(file string) (string, os.Error) {
+ exts := []string{}
+ if x := os.Getenv(`PATHEXT`); x != `` {
+ exts = strings.Split(strings.ToLower(x), `;`, -1)
+ for i, e := range exts {
+ if e == `` || e[0] != '.' {
+ exts[i] = `.` + e
+ }
+ }
+ }
+ if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
+ if f, ok := canExec(file, exts); ok {
+ return f, nil
+ }
+ return ``, &os.PathError{"lookpath", file, os.ENOENT}
+ }
+ if pathenv := os.Getenv(`PATH`); pathenv == `` {
+ if f, ok := canExec(`.\`+file, exts); ok {
+ return f, nil
+ }
+ } else {
+ for _, dir := range strings.Split(pathenv, `;`, -1) {
+ if f, ok := canExec(dir+`\`+file, exts); ok {
+ return f, nil
+ }
+ }
+ }
+ return ``, &os.PathError{"lookpath", file, os.ENOENT}
+}