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

Commit 7e355b8

Browse files
authored
Merge pull request #2178 from nicksieger/cli-binary-path-handling
cli binary path handling
2 parents 77e61c2 + 4678a3e commit 7e355b8

File tree

2 files changed

+74
-13
lines changed

2 files changed

+74
-13
lines changed

cli/mobycli/exec.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"os/signal"
2525
"path/filepath"
2626
"regexp"
27+
"runtime"
2728

2829
"github.com/docker/compose/v2/pkg/compose"
2930
"github.com/docker/compose/v2/pkg/utils"
@@ -38,7 +39,13 @@ import (
3839
var delegatedContextTypes = []string{store.DefaultContextType}
3940

4041
// ComDockerCli name of the classic cli binary
41-
const ComDockerCli = "com.docker.cli"
42+
var ComDockerCli = "com.docker.cli"
43+
44+
func init() {
45+
if runtime.GOOS == "windows" {
46+
ComDockerCli += ".exe"
47+
}
48+
}
4249

4350
// ExecIfDefaultCtxType delegates to com.docker.cli if on moby context
4451
func ExecIfDefaultCtxType(ctx context.Context, root *cobra.Command) {
@@ -92,16 +99,7 @@ func Exec(root *cobra.Command) {
9299

93100
// RunDocker runs a docker command, and forward signals to the shellout command (stops listening to signals when an event is sent to childExit)
94101
func RunDocker(childExit chan bool, args ...string) error {
95-
execBinary, err := resolvepath.LookPath(ComDockerCli)
96-
if err != nil {
97-
execBinary = findBinary(ComDockerCli)
98-
if execBinary == "" {
99-
fmt.Fprintln(os.Stderr, err)
100-
fmt.Fprintln(os.Stderr, "Current PATH : "+os.Getenv("PATH"))
101-
os.Exit(1)
102-
}
103-
}
104-
cmd := exec.Command(execBinary, args...)
102+
cmd := exec.Command(comDockerCli(), args...)
105103
cmd.Stdin = os.Stdin
106104
cmd.Stdout = os.Stdout
107105
cmd.Stderr = os.Stderr
@@ -131,6 +129,25 @@ func RunDocker(childExit chan bool, args ...string) error {
131129
return cmd.Run()
132130
}
133131

132+
func comDockerCli() string {
133+
if v := os.Getenv("DOCKER_COM_DOCKER_CLI"); v != "" {
134+
return v
135+
}
136+
137+
execBinary := findBinary(ComDockerCli)
138+
if execBinary == "" {
139+
var err error
140+
execBinary, err = resolvepath.LookPath(ComDockerCli)
141+
if err != nil {
142+
fmt.Fprintln(os.Stderr, err)
143+
fmt.Fprintln(os.Stderr, "Current PATH : "+os.Getenv("PATH"))
144+
os.Exit(1)
145+
}
146+
}
147+
148+
return execBinary
149+
}
150+
134151
func findBinary(filename string) string {
135152
currentBinaryPath, err := os.Executable()
136153
if err != nil {
@@ -149,7 +166,7 @@ func findBinary(filename string) string {
149166

150167
// IsDefaultContextCommand checks if the command exists in the classic cli (issues a shellout --help)
151168
func IsDefaultContextCommand(dockerCommand string) bool {
152-
cmd := exec.Command(ComDockerCli, dockerCommand, "--help")
169+
cmd := exec.Command(comDockerCli(), dockerCommand, "--help")
153170
b, e := cmd.CombinedOutput()
154171
if e != nil {
155172
fmt.Println(e)
@@ -162,7 +179,7 @@ func ExecSilent(ctx context.Context, args ...string) ([]byte, error) {
162179
if len(args) == 0 {
163180
args = os.Args[1:]
164181
}
165-
cmd := exec.CommandContext(ctx, ComDockerCli, args...)
182+
cmd := exec.CommandContext(ctx, comDockerCli(), args...)
166183
cmd.Stderr = os.Stderr
167184
return cmd.Output()
168185
}

cli/mobycli/exec_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717
package mobycli
1818

1919
import (
20+
"os"
21+
"path/filepath"
2022
"testing"
2123

2224
"gotest.tools/v3/assert"
2325

2426
"github.com/docker/compose-cli/api/context/store"
27+
"github.com/stretchr/testify/require"
2528
)
2629

2730
func TestDelegateContextTypeToMoby(t *testing.T) {
@@ -44,3 +47,44 @@ func TestDelegateContextTypeToMoby(t *testing.T) {
4447
assert.Assert(t, !mustDelegateToMoby(ctx))
4548
}
4649
}
50+
51+
func TestFindComDockerCli(t *testing.T) {
52+
tmp := t.TempDir()
53+
bin := filepath.Join(tmp, "bin")
54+
55+
// com.docker.cli on path
56+
pathFile := filepath.Join(bin, ComDockerCli)
57+
require.NoError(t, os.MkdirAll(bin, os.ModePerm))
58+
require.NoError(t, os.WriteFile(pathFile, []byte(""), os.ModePerm))
59+
60+
exe, err := os.Executable()
61+
require.NoError(t, err)
62+
exe, err = filepath.EvalSymlinks(exe)
63+
require.NoError(t, err)
64+
65+
// com.docker.cli in same directory as current executable
66+
currFile := filepath.Join(filepath.Dir(exe), ComDockerCli)
67+
require.NoError(t, os.WriteFile(currFile, []byte(""), os.ModePerm))
68+
69+
savePath := os.Getenv("PATH")
70+
t.Cleanup(func() { _ = os.Setenv("PATH", savePath) })
71+
72+
_ = os.Setenv("PATH", bin)
73+
74+
t.Run("from $DOCKER_COM_DOCKER_CLI", func(t *testing.T) {
75+
fromenv := filepath.Join(tmp, "fromenv")
76+
_ = os.Setenv("DOCKER_COM_DOCKER_CLI", fromenv)
77+
t.Cleanup(func() { _ = os.Unsetenv("DOCKER_COM_DOCKER_CLI") })
78+
79+
assert.Equal(t, fromenv, comDockerCli())
80+
})
81+
82+
t.Run("from binary next to current executable", func(t *testing.T) {
83+
assert.Equal(t, currFile, comDockerCli())
84+
})
85+
86+
t.Run("from binary on path", func(t *testing.T) {
87+
_ = os.Remove(currFile)
88+
assert.Equal(t, pathFile, comDockerCli())
89+
})
90+
}

0 commit comments

Comments
 (0)