Skip to content

Commit d41ec67

Browse files
authored
[devbox shell] ensure all zsh startup files are linked to ZDOTDIR (#250)
## Summary User `mtunski` in discord helpfully pointed out that their shell setup using zsh4humans (https://github.com/romkatv/zsh4humans) wasn't working with devbox shell. Specifically, they get an error saying: > Installing nix packages. This may take a while...done. Starting a devbox shell... /tmp/devbox3134336657/.zshrc:62: command not found: z4h We currently just copy over the `.zshrc` file into the new `ZDOTDIR` of devbox shell. The fix is: 1. to link more zsh startup files (specifically, .zshenv, .zprofile, .zlogin) 2. manually link other zsh-plugin specific files in the .zshrc. This is not great, but a workaround until we introduce a more formal architecture for custom shells to be hooked up (i.e. with a provider or plugin model). ## How was it tested? 1. installed zsh4humans on my laptop 2. The advanced config docs point to three files to manage for [Backup and Restore](https://github.com/romkatv/zsh4humans/blob/master/tips.md#backup-and-restore) for zsh4humans: - zshenv - zshrc - p10k*.zsh The first two are handled by devbox CLI as part of zsh startup scripts. The last one needs to be manually handled. Added the following to my .zshrc: ``` # within my .zshrc file: ... #### my addition ### if [ -n "${ZDOTDIR+1}" ] && [[ $HOME != $ZDOTDIR ]] then ln $HOME/.p10k*.zsh $ZDOTDIR fi #### end of my addition ### # Install or update core components (fzf, zsh-autosuggestions, etc.) and # initialize Zsh. After this point console I/O is unavailable until Zsh # is fully initialized. Everything that requires user interaction or can # perform network I/O must be done above. Everything else is best done below. z4h init || return ``` 3. opened `devbox shell` in `testdata/zig/zig-hello-world`. Did `which zig` to verify that the nix paths are active (i.e. devbox shell is active). NOTE: in the absence of step (2), the `z4h init` step will start a setup wizard. 4. Opened a new zsh shell (new terminal window) to ensure the .zshrc changes are okay. 4. Deleted zsh4humans (instructions https://github.com/romkatv/zsh4humans#uninstalling), and re-did step 3 without issues.
1 parent 4d21eb6 commit d41ec67

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

nix/shell.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"bytes"
88
_ "embed"
99
"fmt"
10+
"io/fs"
1011
"os"
1112
"os/exec"
1213
"path/filepath"
@@ -202,6 +203,9 @@ func (s *Shell) execCommand() string {
202203
return strings.Join(append(args, s.binPath), " ")
203204
}
204205

206+
// Link other files that affect the shell settings and environments.
207+
s.linkShellStartupFiles(filepath.Dir(shellrc))
208+
205209
// Shells have different ways of overriding the shellrc, so we need to
206210
// look at the name to know which env vars or args to set.
207211
var (
@@ -286,6 +290,38 @@ func (s *Shell) writeDevboxShellrc() (path string, err error) {
286290
return path, nil
287291
}
288292

293+
// linkShellStartupFiles will link files used by the shell for initialization.
294+
// We choose to link instead of copy so that changes made outside can be reflected
295+
// within the devbox shell.
296+
//
297+
// We do not link the .{shell}rc files, since devbox modifies them. See writeDevboxShellrc
298+
func (s *Shell) linkShellStartupFiles(shellSettingsDir string) {
299+
300+
// For now, we only need to do this for zsh shell
301+
if s.name == shZsh {
302+
// Useful explanation of zsh startup files: https://zsh.sourceforge.io/FAQ/zshfaq03.html#l20
303+
filenames := []string{".zshenv", ".zprofile", ".zlogin"}
304+
for _, filename := range filenames {
305+
fileOld := filepath.Join(filepath.Dir(s.userShellrcPath), filename)
306+
if _, err := os.Stat(fileOld); errors.Is(err, fs.ErrNotExist) {
307+
// this file may not be relevant for the user's setup.
308+
continue
309+
} else if err != nil {
310+
debug.Log("os.Stat error for %s is %v", fileOld, err)
311+
}
312+
313+
fileNew := filepath.Join(shellSettingsDir, filename)
314+
315+
if err := os.Link(fileOld, fileNew); err == nil {
316+
debug.Log("Linked shell startup file %s to %s", fileOld, fileNew)
317+
} else {
318+
// This is a best-effort operation. If there's an error then log it for visibility but continue.
319+
debug.Log("Error linking zsh setting file from %s to %s: %v", fileOld, fileNew, err)
320+
}
321+
}
322+
}
323+
}
324+
289325
// envToKeep is the set of environment variables that we want to copy verbatim
290326
// to the new devbox shell.
291327
var envToKeep = map[string]bool{

0 commit comments

Comments
 (0)