Skip to content
This repository was archived by the owner on Nov 27, 2023. It is now read-only.

Commit 4489f39

Browse files
committed
duplicate windows os/exec.LookPath() and do not resolve files in current working dir if CWD is not explicitly in PATH.
Signed-off-by: guillaume.tardif <[email protected]>
1 parent c6fc0e1 commit 4489f39

File tree

3 files changed

+150
-1
lines changed

3 files changed

+150
-1
lines changed

cli/mobycli/exec.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"os"
2323
"os/exec"
2424
"os/signal"
25+
"runtime"
2526
"strings"
2627

2728
"github.com/spf13/cobra"
@@ -60,7 +61,16 @@ func mustDelegateToMoby(ctxType string) bool {
6061

6162
// Exec delegates to com.docker.cli if on moby context
6263
func Exec(root *cobra.Command) {
63-
cmd := exec.Command(ComDockerCli, os.Args[1:]...)
64+
execBinary := ComDockerCli
65+
if runtime.GOOS == "windows" { // workaround for windows issue https://github.com/golang/go/issues/38736
66+
var err error
67+
execBinary, err = LookPath(ComDockerCli)
68+
if err != nil {
69+
fmt.Fprintln(os.Stderr, err)
70+
os.Exit(1)
71+
}
72+
}
73+
cmd := exec.Command(execBinary, os.Args[1:]...)
6474
cmd.Stdin = os.Stdin
6575
cmd.Stdout = os.Stdout
6676
cmd.Stderr = os.Stderr

cli/mobycli/lp_unix.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// +build !windows
2+
3+
/*
4+
Copyright 2020 Docker Compose CLI authors
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package mobycli
20+
21+
import (
22+
"os/exec"
23+
)
24+
25+
// LookPath simply delegate to os/exec.LookPath if not on windows
26+
func LookPath(file string) (string, error) {
27+
return exec.LookPath(file)
28+
}

cli/mobycli/lp_windows.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
Copyright 2020 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package mobycli
18+
19+
import (
20+
"errors"
21+
"os"
22+
"os/exec"
23+
"path/filepath"
24+
"strings"
25+
)
26+
27+
// ErrNotFound is the error resulting if a path search failed to find an executable file.
28+
var ErrNotFound = errors.New("executable file not found in %PATH%")
29+
30+
func chkStat(file string) error {
31+
d, err := os.Stat(file)
32+
if err != nil {
33+
return err
34+
}
35+
if d.IsDir() {
36+
return os.ErrPermission
37+
}
38+
return nil
39+
}
40+
41+
func hasExt(file string) bool {
42+
i := strings.LastIndex(file, ".")
43+
if i < 0 {
44+
return false
45+
}
46+
return strings.LastIndexAny(file, `:\/`) < i
47+
}
48+
49+
func findExecutable(file string, exts []string) (string, error) {
50+
if len(exts) == 0 {
51+
return file, chkStat(file)
52+
}
53+
if hasExt(file) {
54+
if chkStat(file) == nil {
55+
return file, nil
56+
}
57+
}
58+
for _, e := range exts {
59+
if f := file + e; chkStat(f) == nil {
60+
return f, nil
61+
}
62+
}
63+
return "", os.ErrNotExist
64+
}
65+
66+
// LookPath searches for an executable named file in the
67+
// directories named by the PATH environment variable.
68+
// If file contains a slash, it is tried directly and the PATH is not consulted.
69+
// LookPath also uses PATHEXT environment variable to match
70+
// a suitable candidate.
71+
// The result may be an absolute path or a path relative to the current directory.
72+
func LookPath(file string) (string, error) {
73+
var exts []string
74+
x := os.Getenv(`PATHEXT`)
75+
if x != "" {
76+
for _, e := range strings.Split(strings.ToLower(x), `;`) {
77+
if e == "" {
78+
continue
79+
}
80+
if e[0] != '.' {
81+
e = "." + e
82+
}
83+
exts = append(exts, e)
84+
}
85+
} else {
86+
exts = []string{".com", ".exe", ".bat", ".cmd"}
87+
}
88+
89+
if strings.ContainsAny(file, `:\/`) {
90+
if f, err := findExecutable(file, exts); err == nil {
91+
return f, nil
92+
} else {
93+
return "", &exec.Error{file, err}
94+
}
95+
}
96+
// DO NOT lookup current folder
97+
//if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
98+
// return f, nil
99+
//}
100+
path := os.Getenv("path")
101+
for _, dir := range filepath.SplitList(path) {
102+
// empty dir means dupicate semicolon in PATH, should not resolve files in current working dir...
103+
if strings.TrimSpace(dir) == "" {
104+
continue
105+
}
106+
if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
107+
return f, nil
108+
}
109+
}
110+
return "", &exec.Error{file, ErrNotFound}
111+
}

0 commit comments

Comments
 (0)