Commit df8ec65b authored by Alex Brainman's avatar Alex Brainman

os/exec: always try appropriate command extensions during Cmd.Start on windows

Update #7362
Fixes #7377
Fixes #7570

LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/83020043
parent 72dbc4cc
......@@ -218,7 +218,7 @@ func TestHello(t *testing.T) {
t.Fatal("cannot find GOCHAR in 'go env' output:\n", out)
}
char := fields[1]
run("go", "build", "-o", "pack", "cmd/pack") // writes pack binary to dir
run("go", "build", "cmd/pack") // writes pack binary to dir
run("go", "tool", char+"g", "hello.go")
run("./pack", "grc", "hello.a", "hello."+char)
run("go", "tool", char+"l", "-o", "a.out", "hello.a")
......
......@@ -13,7 +13,9 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"syscall"
)
......@@ -237,6 +239,32 @@ 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
......@@ -247,6 +275,15 @@ func (c *Cmd) Start() error {
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")
}
......
......@@ -682,6 +682,24 @@ func TestHelperProcess(*testing.T) {
}
fmt.Fprintf(os.Stderr, "child: %s", response)
os.Exit(0)
case "exec":
cmd := exec.Command(args[1])
cmd.Dir = args[0]
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "Child: %s %s", err, string(output))
os.Exit(1)
}
fmt.Printf("%s", string(output))
os.Exit(0)
case "lookpath":
p, err := exec.LookPath(args[0])
if err != nil {
fmt.Fprintf(os.Stderr, "LookPath failed: %v\n", err)
os.Exit(1)
}
fmt.Print(p)
os.Exit(0)
default:
fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
os.Exit(2)
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment