Skip to content

Commit

Permalink
exec.LookPath() unix/windows separation
Browse files Browse the repository at this point in the history
R=brainman, rsc, vcc, rsc1
CC=golang-dev
https://golang.org/cl/2068041
  • Loading branch information
jpoirier authored and alexbrainman committed Sep 12, 2010
1 parent e181bf6 commit b155a76
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 44 deletions.
17 changes: 17 additions & 0 deletions src/pkg/exec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,21 @@ TARG=exec
GOFILES=\
exec.go\

GOFILES_freebsd=\
lp_unix.go\

GOFILES_darwin=\
lp_unix.go\

GOFILES_linux=\
lp_unix.go\

GOFILES_nacl=\
lp_unix.go\

GOFILES_windows=\
lp_windows.go\

GOFILES+=$(GOFILES_$(GOOS))

include ../../Make.pkg
38 changes: 0 additions & 38 deletions src/pkg/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package exec

import (
"os"
"strings"
)

// Arguments to Run.
Expand Down Expand Up @@ -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
}
31 changes: 25 additions & 6 deletions src/pkg/exec/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import (
)

func TestRunCat(t *testing.T) {
cmd, err := Run("/bin/cat", []string{"cat"}, nil, "",
cat, err := LookPath("cat")
if err != nil {
t.Fatal("cat: ", err)
}
cmd, err := Run(cat, []string{"cat"}, nil, "",
Pipe, Pipe, DevNull)
if err != nil {
t.Fatal("run:", err)
Expand All @@ -32,7 +36,11 @@ func TestRunCat(t *testing.T) {
}

func TestRunEcho(t *testing.T) {
cmd, err := Run("/bin/echo", []string{"echo", "hello", "world"}, nil, "",
echo, err := LookPath("echo")
if err != nil {
t.Fatal("echo: ", err)
}
cmd, err := Run(echo, []string{"echo", "hello", "world"}, nil, "",
DevNull, Pipe, DevNull)
if err != nil {
t.Fatal("run:", err)
Expand All @@ -50,7 +58,11 @@ func TestRunEcho(t *testing.T) {
}

func TestStderr(t *testing.T) {
cmd, err := Run("/bin/sh", []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
sh, err := LookPath("sh")
if err != nil {
t.Fatal("sh: ", err)
}
cmd, err := Run(sh, []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
DevNull, DevNull, Pipe)
if err != nil {
t.Fatal("run:", err)
Expand All @@ -67,9 +79,12 @@ func TestStderr(t *testing.T) {
}
}


func TestMergeWithStdout(t *testing.T) {
cmd, err := Run("/bin/sh", []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
sh, err := LookPath("sh")
if err != nil {
t.Fatal("sh: ", err)
}
cmd, err := Run(sh, []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
DevNull, Pipe, MergeWithStdout)
if err != nil {
t.Fatal("run:", err)
Expand All @@ -91,7 +106,11 @@ func TestAddEnvVar(t *testing.T) {
if err != nil {
t.Fatal("setenv:", err)
}
cmd, err := Run("/bin/sh", []string{"sh", "-c", "echo $NEWVAR"}, nil, "",
sh, err := LookPath("sh")
if err != nil {
t.Fatal("sh: ", err)
}
cmd, err := Run(sh, []string{"sh", "-c", "echo $NEWVAR"}, nil, "",
DevNull, Pipe, DevNull)
if err != nil {
t.Fatal("run:", err)
Expand Down
45 changes: 45 additions & 0 deletions src/pkg/exec/lp_unix.go
Original file line number Diff line number Diff line change
@@ -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.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
}
66 changes: 66 additions & 0 deletions src/pkg/exec/lp_windows.go
Original file line number Diff line number Diff line change
@@ -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.Index(file, `\`) >= 0 || strings.Index(file, `/`) >= 0 {
if f, ok := canExec(file, exts); ok {
return f, nil
}
return ``, 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.ENOENT
}

0 comments on commit b155a76

Please sign in to comment.