@@ -29,7 +29,7 @@ import (
29
29
30
30
//go:embed shellrc.tmpl
31
31
var shellrcText string
32
- var shellrcTmpl = template .Must (template .New ("shellrc" ).Parse (shellrcText ))
32
+ var shellrcTmpl = template .Must (template .New ("shellrc" ).Funcs (template. FuncMap { "dirPath" : filepath . Dir }). Parse (shellrcText ))
33
33
34
34
//go:embed shellrc_fish.tmpl
35
35
var fishrcText string
@@ -228,8 +228,8 @@ func (s *DevboxShell) Run() error {
228
228
return errors .WithStack (err )
229
229
}
230
230
231
- // Link other files that affect the shell settings and environments.
232
- s .linkShellStartupFiles (filepath .Dir (shellrc ))
231
+ // Setup other files that affect the shell settings and environments.
232
+ s .setupShellStartupFiles (filepath .Dir (shellrc ))
233
233
extraEnv , extraArgs := s .shellRCOverrides (shellrc )
234
234
env := s .env
235
235
for k , v := range extraEnv {
@@ -323,6 +323,7 @@ func (s *DevboxShell) writeDevboxShellrc() (path string, err error) {
323
323
ShellStartTime string
324
324
HistoryFile string
325
325
ExportEnv string
326
+ ShellName string
326
327
327
328
RefreshAliasName string
328
329
RefreshCmd string
@@ -335,6 +336,7 @@ func (s *DevboxShell) writeDevboxShellrc() (path string, err error) {
335
336
ShellStartTime : telemetry .FormatShellStart (s .shellStartTime ),
336
337
HistoryFile : strings .TrimSpace (s .historyFile ),
337
338
ExportEnv : exportify (s .env ),
339
+ ShellName : string (s .name ),
338
340
RefreshAliasName : s .devbox .refreshAliasName (),
339
341
RefreshCmd : s .devbox .refreshCmd (),
340
342
RefreshAliasEnvVar : s .devbox .refreshAliasEnvVar (),
@@ -347,12 +349,13 @@ func (s *DevboxShell) writeDevboxShellrc() (path string, err error) {
347
349
return path , nil
348
350
}
349
351
350
- // linkShellStartupFiles will link files used by the shell for initialization.
351
- // We choose to link instead of copy so that changes made outside can be reflected
352
- // within the devbox shell.
352
+ // setupShellStartupFiles creates initialization files for the shell by sourcing the user's originals.
353
+ // We do this instead of linking or copying, so that we can set correct ZDOTDIR when sourcing
354
+ // user's config files which may use the ZDOTDIR env var inside them.
355
+ // This also allows us to make sure any devbox config is run after correctly sourcing the user's config.
353
356
//
354
357
// We do not link the .{shell}rc files, since devbox modifies them. See writeDevboxShellrc
355
- func (s * DevboxShell ) linkShellStartupFiles (shellSettingsDir string ) {
358
+ func (s * DevboxShell ) setupShellStartupFiles (shellSettingsDir string ) {
356
359
// For now, we only need to do this for zsh shell
357
360
if s .name == shZsh {
358
361
// List of zsh startup files: https://zsh.sourceforge.io/Intro/intro_3.html
@@ -375,10 +378,41 @@ func (s *DevboxShell) linkShellStartupFiles(shellSettingsDir string) {
375
378
}
376
379
377
380
fileNew := filepath .Join (shellSettingsDir , filename )
378
- cmd := exec .Command ("cp" , fileOld , fileNew )
379
- if err := cmd .Run (); err != nil {
380
- // This is a best-effort operation. If there's an error then log it for visibility but continue.
381
- slog .Error ("error copying zsh setting file" , "from" , fileOld , "to" , fileNew , "err" , err )
381
+
382
+ // Create template content that sources the original file
383
+ templateContent := `if [[ -f "{{.FileOld}}" ]]; then
384
+ local OLD_ZDOTDIR="$ZDOTDIR"
385
+ export ZDOTDIR="{{.ZDOTDIR}}"
386
+ . "{{.FileOld}}"
387
+ export ZDOTDIR="$OLD_ZDOTDIR"
388
+ fi`
389
+
390
+ // Parse and execute the template
391
+ tmpl , err := template .New ("shellrc" ).Parse (templateContent )
392
+ if err != nil {
393
+ slog .Error ("error parsing template for zsh setting file" , "filename" , filename , "err" , err )
394
+ continue
395
+ }
396
+
397
+ // Create the new file with template content
398
+ file , err := os .Create (fileNew )
399
+ if err != nil {
400
+ slog .Error ("error creating zsh setting file" , "filename" , filename , "err" , err )
401
+ continue
402
+ }
403
+ defer file .Close ()
404
+
405
+ // Execute template with data
406
+ data := struct {
407
+ FileOld string
408
+ ZDOTDIR string
409
+ }{
410
+ FileOld : fileOld ,
411
+ ZDOTDIR : filepath .Dir (s .userShellrcPath ),
412
+ }
413
+
414
+ if err := tmpl .Execute (file , data ); err != nil {
415
+ slog .Error ("error executing template for zsh setting file" , "filename" , filename , "err" , err )
382
416
continue
383
417
}
384
418
}
0 commit comments