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

Commit c1ee51f

Browse files
authored
Merge pull request #884 from docker/win_fix_execute_working_dir
Windows: do not resolve files in current working dir if CWD is not explicitly in PATH.
2 parents 5a8eb00 + 66a1263 commit c1ee51f

File tree

4 files changed

+163
-3
lines changed

4 files changed

+163
-3
lines changed

cli/mobycli/exec.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
"github.com/spf13/cobra"
2828

29+
"github.com/docker/compose-cli/cli/mobycli/resolvepath"
2930
apicontext "github.com/docker/compose-cli/context"
3031
"github.com/docker/compose-cli/context/store"
3132
"github.com/docker/compose-cli/metrics"
@@ -60,7 +61,12 @@ 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, err := resolvepath.LookPath(ComDockerCli)
65+
if err != nil {
66+
fmt.Fprintln(os.Stderr, err)
67+
os.Exit(1)
68+
}
69+
cmd := exec.Command(execBinary, os.Args[1:]...)
6470
cmd.Stdin = os.Stdin
6571
cmd.Stdout = os.Stdout
6672
cmd.Stderr = os.Stderr
@@ -83,7 +89,7 @@ func Exec(root *cobra.Command) {
8389
}
8490
}()
8591

86-
err := cmd.Run()
92+
err = cmd.Run()
8793
childExit <- true
8894
if err != nil {
8995
metrics.Track(store.DefaultContextType, os.Args[1:], metrics.FailureStatus)

cli/mobycli/resolvepath/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 resolvepath
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/resolvepath/lp_windows.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
Copyright (c) 2009 The Go Authors. All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are
6+
met:
7+
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
* Redistributions in binary form must reproduce the above
11+
copyright notice, this list of conditions and the following disclaimer
12+
in the documentation and/or other materials provided with the
13+
distribution.
14+
* Neither the name of Google Inc. nor the names of its
15+
contributors may be used to endorse or promote products derived from
16+
this software without specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
package resolvepath
32+
33+
import (
34+
"errors"
35+
"os"
36+
"os/exec"
37+
"path/filepath"
38+
"strings"
39+
)
40+
41+
// ErrNotFound is the error resulting if a path search failed to find an executable file.
42+
var ErrNotFound = errors.New("executable file not found in %PATH%")
43+
44+
func chkStat(file string) error {
45+
d, err := os.Stat(file)
46+
if err != nil {
47+
return err
48+
}
49+
if d.IsDir() {
50+
return os.ErrPermission
51+
}
52+
return nil
53+
}
54+
55+
func hasExt(file string) bool {
56+
i := strings.LastIndex(file, ".")
57+
if i < 0 {
58+
return false
59+
}
60+
return strings.LastIndexAny(file, `:\/`) < i
61+
}
62+
63+
func findExecutable(file string, exts []string) (string, error) {
64+
if len(exts) == 0 {
65+
return file, chkStat(file)
66+
}
67+
if hasExt(file) {
68+
if chkStat(file) == nil {
69+
return file, nil
70+
}
71+
}
72+
for _, e := range exts {
73+
if f := file + e; chkStat(f) == nil {
74+
return f, nil
75+
}
76+
}
77+
return "", os.ErrNotExist
78+
}
79+
80+
// LookPath searches for an executable named file in the
81+
// directories named by the PATH environment variable.
82+
// If file contains a slash, it is tried directly and the PATH is not consulted.
83+
// LookPath also uses PATHEXT environment variable to match
84+
// a suitable candidate.
85+
// The result may be an absolute path or a path relative to the current directory.
86+
func LookPath(file string) (string, error) {
87+
var exts []string
88+
x := os.Getenv(`PATHEXT`)
89+
if x != "" {
90+
for _, e := range strings.Split(strings.ToLower(x), `;`) {
91+
if e == "" {
92+
continue
93+
}
94+
if e[0] != '.' {
95+
e = "." + e
96+
}
97+
exts = append(exts, e)
98+
}
99+
} else {
100+
exts = []string{".com", ".exe", ".bat", ".cmd"}
101+
}
102+
103+
if strings.ContainsAny(file, `:\/`) {
104+
if f, err := findExecutable(file, exts); err == nil {
105+
return f, nil
106+
} else {
107+
return "", &exec.Error{file, err}
108+
}
109+
}
110+
// See https://github.com/golang/go/issues/38736
111+
// DO NOT lookup current folder
112+
//if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
113+
// return f, nil
114+
//}
115+
path := os.Getenv("path")
116+
for _, dir := range filepath.SplitList(path) {
117+
// empty dir means dupicate semicolon in PATH, should not resolve files in current working dir...
118+
if strings.TrimSpace(dir) == "" {
119+
continue
120+
}
121+
if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
122+
return f, nil
123+
}
124+
}
125+
return "", &exec.Error{file, ErrNotFound}
126+
}

scripts/validate/fileheader

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ fi
2424

2525
BASEPATH="${1-}"
2626

27-
ltag -t "${BASEPATH}scripts/validate/template" -excludes "validate testdata" --check -v
27+
ltag -t "${BASEPATH}scripts/validate/template" -excludes "validate testdata resolvepath" --check -v

0 commit comments

Comments
 (0)