Skip to content

Commit e952923

Browse files
committed
Search for the data directory using argv[0] *and* os.Executable()
Some version managers like aqua rely on shims in $PATH to run the proper application. This isn't particularly unusual, but it was broken by the changes in #3566, because directory lookup ends up pointing to *the shim* rather than the underlying installation. The existing logic already has the concept of falling back to os.Executable if a path based on `argv[0]` can't be determined, so this issue can be solved by just always checking os.Executable *in addition* to `argv[0]`. Signed-off-by: re:fi.64 <[email protected]>
1 parent 599677f commit e952923

File tree

1 file changed

+56
-42
lines changed

1 file changed

+56
-42
lines changed

pkg/usrlocalsharelima/usrlocalsharelima.go

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,42 @@ import (
2323
// It will also append the file extension on Windows, if necessary.
2424
// This function is different from os.Executable(), which will use /proc/self/exe on Linux
2525
// and therefore will resolve any symlink used to locate the executable. This function will
26-
// return the symlink instead because we want to locate ../share/lima relative to the location
27-
// of the symlink, and not the actual executable. This is important when using Homebrew.
28-
//
29-
// If os.Args[0] is invalid, this function still falls back on os.Executable().
26+
// return the symlink instead because we want to be able to locate ../share/lima relative
27+
// to the location of the symlink, and not the actual executable. This is important when
28+
// using Homebrew.
3029
var executableViaArgs0 = sync.OnceValues(func() (string, error) {
3130
if os.Args[0] == "" {
32-
logrus.Warn("os.Args[0] has not been set")
33-
} else {
34-
executable, err := exec.LookPath(os.Args[0])
35-
if err == nil {
36-
// LookPath() will add the `.exe` file extension on Windows, but will not return an
37-
// absolute path if the argument contained any of `:/\` (or just `/` on Unix).
38-
return filepath.Abs(executable)
39-
}
40-
logrus.Warnf("os.Args[0] is invalid: %v", err)
31+
return "", errors.New("os.Args[0] has not been set")
32+
}
33+
executable, err := exec.LookPath(os.Args[0])
34+
if err == nil {
35+
executable, err = filepath.Abs(executable)
36+
}
37+
if err != nil {
38+
return "", fmt.Errorf("os.Args[0] is invalid: %w", err)
4139
}
42-
return os.Executable()
40+
41+
return executable, nil
4342
})
4443

4544
// Dir returns the location of the <PREFIX>/lima/share directory, relative to the location
4645
// of the current executable. It checks for multiple possible filesystem layouts and returns
4746
// the first candidate that contains the native guest agent binary.
4847
func Dir() (string, error) {
49-
self, err := executableViaArgs0()
48+
selfPaths := []string{}
49+
50+
selfViaArgs0, err := executableViaArgs0()
5051
if err != nil {
51-
return "", err
52+
logrus.WithError(err).Warn("failed to find executable from os.Args[0]")
53+
} else {
54+
selfPaths = append(selfPaths, selfViaArgs0)
55+
}
56+
57+
selfViaOS, err := os.Executable()
58+
if err != nil {
59+
logrus.WithError(err).Warn("failed to find os.Executable()")
60+
} else if len(selfPaths) == 0 || selfViaOS != selfPaths[0] {
61+
selfPaths = append(selfPaths, selfViaOS)
5262
}
5363

5464
ostype := limayaml.NewOS("linux")
@@ -57,31 +67,35 @@ func Dir() (string, error) {
5767
return "", fmt.Errorf("failed to get arch for %q", runtime.GOARCH)
5868
}
5969

60-
// self: /usr/local/bin/limactl
61-
selfDir := filepath.Dir(self)
62-
selfDirDir := filepath.Dir(selfDir)
63-
gaCandidates := []string{
64-
// candidate 0:
65-
// - self: /Applications/Lima.app/Contents/MacOS/limactl
66-
// - agent: /Applications/Lima.app/Contents/MacOS/lima-guestagent.Linux-x86_64
67-
// - dir: /Applications/Lima.app/Contents/MacOS
68-
filepath.Join(selfDir, "lima-guestagent."+ostype+"-"+arch),
69-
// candidate 1:
70-
// - self: /usr/local/bin/limactl
71-
// - agent: /usr/local/share/lima/lima-guestagent.Linux-x86_64
72-
// - dir: /usr/local/share/lima
73-
filepath.Join(selfDirDir, "share/lima/lima-guestagent."+ostype+"-"+arch),
74-
// TODO: support custom path
75-
}
76-
if debugutil.Debug {
77-
// candidate 2: launched by `~/go/bin/dlv dap`
78-
// - self: ${workspaceFolder}/cmd/limactl/__debug_bin_XXXXXX
79-
// - agent: ${workspaceFolder}/_output/share/lima/lima-guestagent.Linux-x86_64
80-
// - dir: ${workspaceFolder}/_output/share/lima
81-
candidateForDebugBuild := filepath.Join(filepath.Dir(selfDirDir), "_output/share/lima/lima-guestagent."+ostype+"-"+arch)
82-
gaCandidates = append(gaCandidates, candidateForDebugBuild)
83-
logrus.Infof("debug mode detected, adding more guest agent candidates: %v", candidateForDebugBuild)
70+
gaCandidates := []string{}
71+
for _, self := range selfPaths {
72+
// self: /usr/local/bin/limactl
73+
selfDir := filepath.Dir(self)
74+
selfDirDir := filepath.Dir(selfDir)
75+
gaCandidates = append(gaCandidates,
76+
// candidate 0:
77+
// - self: /Applications/Lima.app/Contents/MacOS/limactl
78+
// - agent: /Applications/Lima.app/Contents/MacOS/lima-guestagent.Linux-x86_64
79+
// - dir: /Applications/Lima.app/Contents/MacOS
80+
filepath.Join(selfDir, "lima-guestagent."+ostype+"-"+arch),
81+
// candidate 1:
82+
// - self: /usr/local/bin/limactl
83+
// - agent: /usr/local/share/lima/lima-guestagent.Linux-x86_64
84+
// - dir: /usr/local/share/lima
85+
filepath.Join(selfDirDir, "share/lima/lima-guestagent."+ostype+"-"+arch),
86+
// TODO: support custom path
87+
)
88+
if debugutil.Debug {
89+
// candidate 2: launched by `~/go/bin/dlv dap`
90+
// - self: ${workspaceFolder}/cmd/limactl/__debug_bin_XXXXXX
91+
// - agent: ${workspaceFolder}/_output/share/lima/lima-guestagent.Linux-x86_64
92+
// - dir: ${workspaceFolder}/_output/share/lima
93+
candidateForDebugBuild := filepath.Join(filepath.Dir(selfDirDir), "_output/share/lima/lima-guestagent."+ostype+"-"+arch)
94+
gaCandidates = append(gaCandidates, candidateForDebugBuild)
95+
logrus.Infof("debug mode detected, adding more guest agent candidates: %v", candidateForDebugBuild)
96+
}
8497
}
98+
8599
for _, gaCandidate := range gaCandidates {
86100
if _, err := os.Stat(gaCandidate); err == nil {
87101
return filepath.Dir(gaCandidate), nil
@@ -95,8 +109,8 @@ func Dir() (string, error) {
95109
}
96110
}
97111

98-
return "", fmt.Errorf("failed to find \"lima-guestagent.%s-%s\" binary for %q, attempted %v",
99-
ostype, arch, self, gaCandidates)
112+
return "", fmt.Errorf("failed to find \"lima-guestagent.%s-%s\" binary for %v, attempted %v",
113+
ostype, arch, selfPaths, gaCandidates)
100114
}
101115

102116
// GuestAgentBinary returns the absolute path of the guest agent binary, possibly with ".gz" suffix.

0 commit comments

Comments
 (0)