@@ -12,6 +12,8 @@ import (
1212 "os"
1313 "path/filepath"
1414 "strings"
15+
16+ "go.jetpack.io/devbox/debug"
1517)
1618
1719type name string
@@ -30,6 +32,22 @@ type Shell struct {
3032 path string
3133 initFile string
3234 devboxInitFile string
35+
36+ // PreInitHook contains commands that will run before the user's init
37+ // files at shell startup.
38+ //
39+ // The script's environment will contain an ORIGINAL_PATH environment
40+ // variable, which will bet set to the PATH before the shell's init
41+ // files have had a chance to modify it.
42+ PreInitHook string
43+
44+ // PostInitHook contains commands that will run after the user's init
45+ // files at shell startup.
46+ //
47+ // The script's environment will contain an ORIGINAL_PATH environment
48+ // variable, which will bet set to the PATH before the shell's init
49+ // files have had a chance to modify it.
50+ PostInitHook string
3351}
3452
3553// Detect attempts to determine the user's default shell.
@@ -67,6 +85,9 @@ func Detect() (*Shell, error) {
6785 default :
6886 sh .name = shUnknown
6987 }
88+ debug .Log ("Detected shell: %s" , sh .path )
89+ debug .Log ("Recognized shell as: %s" , sh .path )
90+ debug .Log ("Looking for user's shell init file at: %s" , sh .initFile )
7091 return sh , nil
7192}
7293
@@ -80,33 +101,62 @@ func rcfilePath(basename string) string {
80101 return filepath .Join (home , basename )
81102}
82103
83- // SetInit configures the shell to run a script at startup. The script runs
84- // after the user's usual init files. The script's environment will contain an
85- // ORIGINAL_PATH environment variable, which will bet set to the PATH before
86- // the user's init files have had a chance to modify it.
87- func (s * Shell ) SetInit (script string ) error {
88- script = strings .TrimSpace (script )
89- if script == "" {
90- return nil
104+ func (s * Shell ) buildInitFile () ([]byte , error ) {
105+ prehook := strings .TrimSpace (s .PreInitHook )
106+ posthook := strings .TrimSpace (s .PostInitHook )
107+ if prehook == "" && posthook == "" {
108+ return nil , nil
109+ }
110+
111+ buf := bytes.Buffer {}
112+ if prehook != "" {
113+ buf .WriteString (`
114+ # Begin Devbox Pre-init Hook
115+
116+ ` )
117+ buf .WriteString (prehook )
118+ buf .WriteString (`
119+
120+ # End Devbox Pre-init Hook
121+
122+ ` )
91123 }
92124
93- initFile , _ := os .ReadFile (s .initFile )
125+ initFile , err := os .ReadFile (s .initFile )
126+ if err != nil {
127+ return nil , err
128+ }
94129 initFile = bytes .TrimSpace (initFile )
95130 if len (initFile ) > 0 {
96- initFile = append (initFile , '\n' , '\n' )
131+ buf . Write (initFile )
97132 }
98133
99- buf := bytes . NewBuffer ( initFile )
100- buf .WriteString (`
134+ if posthook != "" {
135+ buf .WriteString (`
101136
102- # Begin Devbox Shell Hook
137+ # Begin Devbox Pre-init Hook
103138
104139` )
105- buf .WriteString (script )
106- buf .WriteString (`
140+ buf .WriteString (posthook )
141+ buf .WriteString (`
107142
108- # End Devbox Shell Hook
109- ` )
143+ # End Devbox Post-init Hook` )
144+ }
145+
146+ b := buf .Bytes ()
147+ b = bytes .TrimSpace (b )
148+ if len (b ) == 0 {
149+ return nil , nil
150+ }
151+ b = append (b , '\n' )
152+ return b , nil
153+ }
154+
155+ func (s * Shell ) writeHooks () error {
156+ initContents , err := s .buildInitFile ()
157+ if err != nil {
158+ return err
159+ }
110160
111161 // We need a temp dir (as opposed to a temp file) because zsh uses
112162 // ZDOTDIR to point to a new directory containing the .zshrc.
@@ -115,16 +165,20 @@ func (s *Shell) SetInit(script string) error {
115165 return fmt .Errorf ("create temp dir for shell init file: %v" , err )
116166 }
117167 devboxInitFile := filepath .Join (tmp , filepath .Base (s .initFile ))
118- if err := os .WriteFile (devboxInitFile , buf . Bytes () , 0600 ); err != nil {
168+ if err := os .WriteFile (devboxInitFile , initContents , 0600 ); err != nil {
119169 return fmt .Errorf ("write to shell init file: %v" , err )
120170 }
121171 s .devboxInitFile = devboxInitFile
172+
173+ debug .Log ("Wrote devbox shell init file to: %s" , s .devboxInitFile )
174+ debug .Log ("--- Begin Devbox Shell Init Contents ---\n %s--- End Devbox Shell Init Contents ---" , initContents )
122175 return nil
123176}
124177
125178// ExecCommand is a command that replaces the current shell with s.
126179func (s * Shell ) ExecCommand () string {
127- if s .devboxInitFile == "" {
180+ if err := s .writeHooks (); err != nil || s .devboxInitFile == "" {
181+ debug .Log ("Failed to write shell pre-init and post-init hooks: %v" , err )
128182 return "exec " + s .path
129183 }
130184
0 commit comments