1
2
3
4
5
6
7
8
9
10
11 package execabs
12
13 import (
14 "context"
15 "fmt"
16 "os/exec"
17 "path/filepath"
18 "reflect"
19 "unsafe"
20 )
21
22 var ErrNotFound = exec.ErrNotFound
23
24 type (
25 Cmd = exec.Cmd
26 Error = exec.Error
27 ExitError = exec.ExitError
28 )
29
30 func relError(file, path string) error {
31 return fmt.Errorf("%s resolves to executable relative to current directory (.%c%s)", file, filepath.Separator, path)
32 }
33
34 func LookPath(file string) (string, error) {
35 path, err := exec.LookPath(file)
36 if err != nil {
37 return "", err
38 }
39 if filepath.Base(file) == file && !filepath.IsAbs(path) {
40 return "", relError(file, path)
41 }
42 return path, nil
43 }
44
45 func fixCmd(name string, cmd *exec.Cmd) {
46 if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) {
47
48
49
50
51 lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer()))
52 if *lookPathErr == nil {
53 *lookPathErr = relError(name, cmd.Path)
54 }
55 cmd.Path = ""
56 }
57 }
58
59 func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd {
60 cmd := exec.CommandContext(ctx, name, arg...)
61 fixCmd(name, cmd)
62 return cmd
63
64 }
65
66 func Command(name string, arg ...string) *exec.Cmd {
67 cmd := exec.Command(name, arg...)
68 fixCmd(name, cmd)
69 return cmd
70 }
71
View as plain text