Skip to content

Commit 51c8829

Browse files
authored
[fish] Fix init hooks for fish (#1741)
## Summary Fixes issue introduced in #1709 `devbox run` uses `sh` instead of native shell. So init hooks must always be `sh` compatible for `run`. On the other hand, `devbox shell` uses native shell so init hooks must be `fish` if the native shell is fish. This is ugly, but it's how it has always worked. #1709 introduced recursion protection that would be `fish` or `sh` depending on native shell. This worked fine for `devbox shell` but would break `devbox run`. This change fixes that by creating 2 hooks files, one fish and one sh and sourcing the correct one in shellrc, while still always using the `sh` for run. cc: @Lagoja ## How was it tested? ``` devbox run echo 5 devbox shell SHELL=fish devbox run echo 5 SHELL=fish devbox shell ```
1 parent a927b0f commit 51c8829

File tree

8 files changed

+36
-32
lines changed

8 files changed

+36
-32
lines changed

internal/devbox/devbox.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ func (d *Devbox) Shell(ctx context.Context) error {
204204
}
205205

206206
opts := []ShellOption{
207-
WithHooksFilePath(shellgen.ScriptPath(d.ProjectDir(), shellgen.HooksFilename)),
208207
WithHistoryFile(filepath.Join(d.projectDir, shellHistoryFile)),
209208
WithProjectDir(d.projectDir),
210209
WithEnvVariables(envs),

internal/devbox/shell.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/alessio/shellescape"
1919
"github.com/pkg/errors"
20+
"go.jetpack.io/devbox/internal/shellgen"
2021
"go.jetpack.io/devbox/internal/telemetry"
2122

2223
"go.jetpack.io/devbox/internal/debug"
@@ -59,8 +60,7 @@ type DevboxShell struct {
5960
env map[string]string
6061
userShellrcPath string
6162

62-
hooksFilePath string
63-
historyFile string
63+
historyFile string
6464

6565
// shellStartTime is the unix timestamp for when the command was invoked
6666
shellStartTime time.Time
@@ -183,12 +183,6 @@ func WithHistoryFile(historyFile string) ShellOption {
183183
}
184184
}
185185

186-
func WithHooksFilePath(hooksFilePath string) ShellOption {
187-
return func(s *DevboxShell) {
188-
s.hooksFilePath = hooksFilePath
189-
}
190-
}
191-
192186
// TODO: Consider removing this once plugins add env vars directly to binaries via wrapper scripts.
193187
func WithEnvVariables(envVariables map[string]string) ShellOption {
194188
return func(s *DevboxShell) {
@@ -317,8 +311,10 @@ func (s *DevboxShell) writeDevboxShellrc() (path string, err error) {
317311
}()
318312

319313
tmpl := shellrcTmpl
314+
hooksFilePath := shellgen.ScriptPath(s.projectDir, shellgen.HooksFilename)
320315
if s.name == shFish {
321316
tmpl = fishrcTmpl
317+
hooksFilePath = shellgen.ScriptPath(s.projectDir, shellgen.HooksFishFilename)
322318
}
323319

324320
err = tmpl.Execute(shellrcf, struct {
@@ -337,7 +333,7 @@ func (s *DevboxShell) writeDevboxShellrc() (path string, err error) {
337333
ProjectDir: s.projectDir,
338334
OriginalInit: string(bytes.TrimSpace(userShellrc)),
339335
OriginalInitPath: s.userShellrcPath,
340-
HooksFilePath: s.hooksFilePath,
336+
HooksFilePath: hooksFilePath,
341337
ShellStartTime: telemetry.FormatShellStart(s.shellStartTime),
342338
HistoryFile: strings.TrimSpace(s.historyFile),
343339
ExportEnv: exportify(s.env),

internal/devbox/shell_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,8 @@ func testWriteDevboxShellrc(t *testing.T, testdirs []string) {
6767
s := &DevboxShell{
6868
devbox: &Devbox{projectDir: projectDir},
6969
env: test.env,
70-
projectDir: "path/to/projectDir",
70+
projectDir: "/path/to/projectDir",
7171
userShellrcPath: test.shellrcPath,
72-
hooksFilePath: test.hooksFilePath,
7372
}
7473
gotPath, err := s.writeDevboxShellrc()
7574
if err != nil {

internal/devbox/testdata/shellrc/basic/shellrc.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export PS1="(devbox) $PS1"
1515

1616
# Run plugin and user init hooks from the devbox.json directory.
1717
working_dir="$(pwd)"
18-
cd "path/to/projectDir" || exit
18+
cd "/path/to/projectDir" || exit
1919

2020
# Source the hooks file, which contains the project's init hooks and plugin hooks.
2121
. /path/to/projectDir/.devbox/gen/scripts/.hooks.sh

internal/devbox/testdata/shellrc/noshellrc/shellrc.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export PS1="(devbox) $PS1"
99

1010
# Run plugin and user init hooks from the devbox.json directory.
1111
working_dir="$(pwd)"
12-
cd "path/to/projectDir" || exit
12+
cd "/path/to/projectDir" || exit
1313

1414
# Source the hooks file, which contains the project's init hooks and plugin hooks.
1515
. /path/to/projectDir/.devbox/gen/scripts/.hooks.sh

internal/shellgen/scripts.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,18 @@ import (
2121
//go:embed tmpl/init-hook.tmpl
2222
var initHookTmpl string
2323

24+
//go:embed tmpl/init-hook-fish.tmpl
25+
var initHookFishTmpl string
26+
2427
const scriptsDir = ".devbox/gen/scripts"
2528

2629
// HooksFilename is the name of the file that contains the project's init-hooks and plugin hooks
2730
const HooksFilename = ".hooks"
2831

32+
// This is only used in shellrc_fish.tmpl. A bit of a hack, because scripts use
33+
// sh instead of fish.
34+
const HooksFishFilename = ".hooks.fish"
35+
2936
type devboxer interface {
3037
Config() *devconfig.Config
3138
Lockfile() *lock.File
@@ -62,11 +69,16 @@ func WriteScriptsToFiles(devbox devboxer) error {
6269
}
6370
hooks := strings.Join(append(pluginHooks, devbox.Config().InitHook().String()), "\n\n")
6471
// always write it, even if there are no hooks, because scripts will source it.
65-
err = writeInitHookFile(devbox, hooks)
72+
err = writeInitHookFile(devbox, hooks, initHookTmpl, HooksFilename)
6673
if err != nil {
6774
return errors.WithStack(err)
6875
}
6976
written[HooksFilename] = struct{}{}
77+
err = writeInitHookFile(devbox, hooks, initHookFishTmpl, HooksFishFilename)
78+
if err != nil {
79+
return errors.WithStack(err)
80+
}
81+
written[HooksFishFilename] = struct{}{}
7082

7183
// Write scripts to files.
7284
for name, body := range devbox.Config().Scripts() {
@@ -91,25 +103,21 @@ func WriteScriptsToFiles(devbox devboxer) error {
91103
return nil
92104
}
93105

94-
func writeInitHookFile(devbox devboxer, body string) (err error) {
95-
script, err := createScriptFile(devbox, HooksFilename)
106+
func writeInitHookFile(devbox devboxer, body, tmpl, filename string) (err error) {
107+
script, err := createScriptFile(devbox, filename)
96108
if err != nil {
97109
return errors.WithStack(err)
98110
}
99111
defer script.Close() // best effort: close file
100112

101-
t, err := template.New("init-hook-template").Parse(initHookTmpl)
113+
t, err := template.New(filename).Parse(tmpl)
102114
if err != nil {
103115
return errors.WithStack(err)
104116
}
105117

106118
return t.Execute(script, map[string]any{
107119
"Body": body,
108120
"InitHookHash": "__DEVBOX_INIT_HOOK_" + devbox.ProjectDirHash(),
109-
// TODO put IsFish() in common place so we can call here and in devbox package
110-
// without adding more stuff to interface
111-
"IsFish": filepath.Base(os.Getenv("SHELL")) == "fish" ||
112-
os.Getenv("FISH_VERSION") != "",
113121
})
114122
}
115123

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{{/* Fish version */ -}}
2+
{{/* if hash is set, we're in recursive loop, just exit */ -}}
3+
4+
if set -q {{ .InitHookHash }}; then
5+
return
6+
end
7+
8+
export {{ .InitHookHash }}=true
9+
10+
{{ .Body }}
11+
12+
set -e {{ .InitHookHash }}

internal/shellgen/tmpl/init-hook.tmpl

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11

22
{{/* if hash is set, we're in recursive loop, just exit */ -}}
33

4-
{{ if .IsFish }}
5-
if set -q {{ .InitHookHash }}; then
6-
return
7-
end
8-
{{ else }}
94
if [ -n "${{ .InitHookHash }}" ]; then
105
return
116
fi
12-
{{ end }}
137

148
export {{ .InitHookHash }}=true
159

1610
{{ .Body }}
1711

18-
{{ if .IsFish }}
19-
set -e {{ .InitHookHash }}
20-
{{ else }}
2112
unset {{ .InitHookHash }}
22-
{{ end }}

0 commit comments

Comments
 (0)