Skip to content

Commit 07c437e

Browse files
authored
[pure shell] Fixed devbox not being in path (#1170)
## Summary Fixed an issue which caused devbox to disappear from PATH in pure shell mode. NOTE: Moved the location of the symlink from `.devbox/virtenv/bin` to `.devbox/bin`. I'm open to changing the location but since it's only in pure mode and the location doesn't really affect the user (they can just use `$(which devbox)` inside the shell to get the location dynamically) I'm eager to not have the location of devbox symlink be a blocking issue. ## How was it tested? - compile - ./devbox shell --pure - which devbox - which nix
1 parent 5f4b9d0 commit 07c437e

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

internal/impl/devbox.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,12 +1238,14 @@ func (d *Devbox) convertEnvToMap(currentEnv []string) (map[string]string, error)
12381238
// handling special case for PATH
12391239
if d.pure {
12401240
// Finding nix executables in path and passing it through
1241-
// Needed for devbox commands inside pure shell to work
1242-
nixInPath, err := findNixInPATH(env)
1241+
// As well as adding devbox itself to PATH
1242+
// Both are needed for devbox commands inside pure shell to work
1243+
includedInPath, err := findNixInPATH(env)
12431244
if err != nil {
12441245
return nil, err
12451246
}
1246-
env["PATH"] = nixInPath
1247+
includedInPath = append(includedInPath, wrapnix.DotdevboxBinPath(d))
1248+
env["PATH"] = JoinPathLists(includedInPath...)
12471249
}
12481250
return env, nil
12491251
}

internal/impl/shell.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,20 +412,29 @@ func filterPathList(pathList string, keep func(string) bool) string {
412412
return strings.Join(filtered, string(filepath.ListSeparator))
413413
}
414414

415-
func findNixInPATH(env map[string]string) (string, error) {
415+
// findNixInPATH looks for locations in PATH which nix might exist and
416+
// it returns a slice containing all paths that might contain nix.
417+
// For single-user, and multi-user installation there are default locations
418+
// unless XDG_* env variables are set. So we look for nix in 3 locations
419+
// to see if any of those exist in path.
420+
func findNixInPATH(env map[string]string) ([]string, error) {
416421
defaultSingleUserNixBin := fmt.Sprintf("%s/.nix-profile/bin", env["HOME"])
417422
defaultMultiUserNixBin := "/nix/var/nix/profiles/default/bin"
418423
xdgNixBin := xdg.StateSubpath("/nix/profile/bin")
419424
pathElements := strings.Split(env["PATH"], ":")
420425
debug.Log("path elements: %v", pathElements)
426+
nixBinsInPath := []string{}
421427
for _, el := range pathElements {
422428
if el == xdgNixBin ||
423429
el == defaultSingleUserNixBin ||
424430
el == defaultMultiUserNixBin {
425-
return el, nil
431+
nixBinsInPath = append(nixBinsInPath, el)
426432
}
427433
}
428434

429-
// did not find nix executable in PATH, return error
430-
return "", errors.New("could not find any nix executable in PATH. Make sure Nix is installed and in PATH, then try again")
435+
if len(nixBinsInPath) == 0 {
436+
// did not find nix executable in PATH, return error
437+
return nil, errors.New("could not find any nix executable in PATH. Make sure Nix is installed and in PATH, then try again")
438+
}
439+
return nixBinsInPath, nil
431440
}

internal/wrapnix/wrapper.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,13 @@ func createDevboxSymlink(devbox devboxer) error {
145145
if err != nil {
146146
return errors.Wrap(err, "failed to create devbox symlink. Devbox command won't be available inside the shell")
147147
}
148-
// Create a symlink between devbox in .wrappers/bin
149-
err = os.Symlink(devboxPath, filepath.Join(wrapperBinPath(devbox), "devbox"))
148+
// ensure .devbox/bin directory exists
149+
binPath := DotdevboxBinPath(devbox)
150+
if err := os.MkdirAll(binPath, 0755); err != nil {
151+
return errors.WithStack(err)
152+
}
153+
// Create a symlink between devbox and .devbox/bin
154+
err = os.Symlink(devboxPath, filepath.Join(binPath, "devbox"))
150155
if err != nil && !errors.Is(err, fs.ErrExist) {
151156
return errors.Wrap(err, "failed to create devbox symlink. Devbox command won't be available inside the shell")
152157
}
@@ -156,3 +161,7 @@ func createDevboxSymlink(devbox devboxer) error {
156161
func wrapperBinPath(devbox devboxer) string {
157162
return filepath.Join(devbox.ProjectDir(), plugin.WrapperBinPath)
158163
}
164+
165+
func DotdevboxBinPath(devbox devboxer) string {
166+
return filepath.Join(devbox.ProjectDir(), ".devbox/bin")
167+
}

0 commit comments

Comments
 (0)