Skip to content

Commit af3fbcf

Browse files
authored
[direnv] run init-hooks in envrc, and generate shell files prior to gen envrc (#910)
## Summary Two changes: 1. Run `shellenv --init-hook` to ensure correctness. There will be a small perf hit if the init-hooks are very slow, but we are biasing towards correctness over perf. - To improve the perf, we can distinguish a generic init hook versus shell-specific init hook, later on. 2. Ensure packages are installed and shell files are generated. This is important because we check for existence of `.devbox/gen/flake/flake.nix` prior to running `devbox shellenv --init-hook`. - since this requires `nix`, we add `ensureNixInstalled` to `devbox init` and `devbox generate direnv` commands. - I refactored to call `ensureNixInstalled` from within `GenerateEnvrc` so that we don't block `devbox init` if envrc is not required. ## How was it tested? ``` # clear .devbox directory and nix profile contained therein > rm -rf .devbox # generate a new .envrc > devbox generate direnv --force # observe output ensuring packages are installed # go outside the directory and check my global `go` path > cd .. > which go # confirm `go` path is now from the /nix/store > cd devbox > which go ```
1 parent 8f99fb8 commit af3fbcf

File tree

6 files changed

+64
-51
lines changed

6 files changed

+64
-51
lines changed

.envrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use_devbox() {
55
watch_file devbox.json
66
if [ -f .devbox/gen/flake/flake.nix ]; then
77
DEVBOX_SHELL_ENABLED_BACKUP=$DEVBOX_SHELL_ENABLED
8-
eval $(devbox shell --print-env)
8+
eval $(devbox shellenv --init-hook)
99
export DEVBOX_SHELL_ENABLED=$DEVBOX_SHELL_ENABLED_BACKUP
1010
fi
1111
}

internal/boxcli/init.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ func runInitCmd(cmd *cobra.Command, args []string) error {
3636
if err != nil {
3737
return errors.WithStack(err)
3838
}
39+
3940
return errors.WithStack(box.GenerateEnvrc(false, "init"))
4041
}

internal/boxcli/setup.go

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@
44
package boxcli
55

66
import (
7-
"fmt"
87
"os"
98

109
"github.com/fatih/color"
11-
"github.com/mattn/go-isatty"
1210
"github.com/samber/lo"
1311
"github.com/spf13/cobra"
14-
"go.jetpack.io/devbox/internal/boxcli/usererr"
1512
"go.jetpack.io/devbox/internal/nix"
1613
"go.jetpack.io/devbox/internal/ux"
1714
)
@@ -50,44 +47,8 @@ func runInstallNixCmd(cmd *cobra.Command) error {
5047
return nix.Install(cmd.ErrOrStderr(), nixDaemonFlagVal(cmd))
5148
}
5249

53-
func ensureNixInstalled(cmd *cobra.Command, args []string) error {
54-
if nix.BinaryInstalled() {
55-
return nil
56-
}
57-
if nix.DirExists() {
58-
if err := nix.SourceNixEnv(); err != nil {
59-
return err
60-
} else if nix.BinaryInstalled() {
61-
return nil
62-
}
63-
64-
return usererr.New(
65-
"We found a /nix directory but nix binary is not in your PATH and we " +
66-
"were not able to find it in the usual locations. Your nix installation " +
67-
"might be broken. If restarting your terminal or reinstalling nix " +
68-
"doesn't work, please create an issue at " +
69-
"https://github.com/jetpack-io/devbox/issues",
70-
)
71-
}
72-
73-
color.Yellow("\nNix is not installed. Devbox will attempt to install it.\n\n")
74-
75-
if isatty.IsTerminal(os.Stdout.Fd()) {
76-
color.Yellow("Press enter to continue or ctrl-c to exit.\n")
77-
fmt.Scanln()
78-
}
79-
80-
if err := nix.Install(cmd.ErrOrStderr(), nixDaemonFlagVal(cmd)); err != nil {
81-
return err
82-
}
83-
84-
// Source again
85-
if err := nix.SourceNixEnv(); err != nil {
86-
return err
87-
}
88-
89-
cmd.PrintErrln("Nix installed successfully. Devbox is ready to use!")
90-
return nil
50+
func ensureNixInstalled(cmd *cobra.Command, _args []string) error {
51+
return nix.EnsureNixInstalled(cmd.ErrOrStderr(), nixDaemonFlagVal(cmd))
9152
}
9253

9354
func nixDaemonFlagVal(cmd *cobra.Command) *bool {

internal/impl/devbox.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ func (d *Devbox) GenerateDockerfile(force bool) error {
371371

372372
// GenerateEnvrc generates a .envrc file that makes direnv integration convenient
373373
func (d *Devbox) GenerateEnvrc(force bool, source string) error {
374+
ctx, task := trace.NewTask(context.Background(), "devboxGenerateEnvrc")
375+
defer task.End()
376+
374377
envrcfilePath := filepath.Join(d.projectDir, ".envrc")
375378
filesExist := fileutil.Exists(envrcfilePath)
376379
if !force && filesExist {
@@ -394,20 +397,27 @@ func (d *Devbox) GenerateEnvrc(force bool, source string) error {
394397
}
395398
}
396399

397-
if strings.ToLower(result) == "y" || !isInteractiveMode {
400+
if strings.ToLower(result) == "y" || !isInteractiveMode || source == "generate" {
401+
nixDaemon := false
402+
if err := nix.EnsureNixInstalled(d.writer, &nixDaemon); err != nil {
403+
return err
404+
}
405+
406+
// generate all shell files to ensure we can refer to them in the .envrc script
407+
if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil {
408+
return err
409+
}
410+
398411
// .envrc file creation
399412
err := generate.CreateEnvrc(tmplFS, d.projectDir)
400413
if err != nil {
401414
return errors.WithStack(err)
402415
}
416+
}
417+
418+
if strings.ToLower(result) == "y" || !isInteractiveMode {
403419
cmd := exec.Command("direnv", "allow")
404-
err = cmd.Run()
405-
if err != nil {
406-
return errors.WithStack(err)
407-
}
408-
} else if source == "generate" {
409-
// .envrc file creation
410-
err := generate.CreateEnvrc(tmplFS, d.projectDir)
420+
err := cmd.Run()
411421
if err != nil {
412422
return errors.WithStack(err)
413423
}

internal/impl/tmpl/envrc.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use_devbox() {
55
watch_file devbox.json
66
if [ -f .devbox/gen/flake/flake.nix ]; then
77
DEVBOX_SHELL_ENABLED_BACKUP=$DEVBOX_SHELL_ENABLED
8-
eval $(devbox shell --print-env)
8+
eval $(devbox shellenv --init-hook)
99
export DEVBOX_SHELL_ENABLED=$DEVBOX_SHELL_ENABLED_BACKUP
1010
fi
1111
}

internal/nix/install.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111

1212
"github.com/fatih/color"
13+
"github.com/mattn/go-isatty"
1314
"github.com/pkg/errors"
1415
"go.jetpack.io/devbox/internal/boxcli/usererr"
1516
"go.jetpack.io/devbox/internal/build"
@@ -88,3 +89,43 @@ func DirExists() bool {
8889
func isRoot() bool {
8990
return os.Geteuid() == 0
9091
}
92+
93+
func EnsureNixInstalled(writer io.Writer, daemon *bool) error {
94+
if BinaryInstalled() {
95+
return nil
96+
}
97+
if DirExists() {
98+
if err := SourceNixEnv(); err != nil {
99+
return err
100+
} else if BinaryInstalled() {
101+
return nil
102+
}
103+
104+
return usererr.New(
105+
"We found a /nix directory but nix binary is not in your PATH and we " +
106+
"were not able to find it in the usual locations. Your nix installation " +
107+
"might be broken. If restarting your terminal or reinstalling nix " +
108+
"doesn't work, please create an issue at " +
109+
"https://github.com/jetpack-io/devbox/issues",
110+
)
111+
}
112+
113+
color.Yellow("\nNix is not installed. Devbox will attempt to install it.\n\n")
114+
115+
if isatty.IsTerminal(os.Stdout.Fd()) {
116+
color.Yellow("Press enter to continue or ctrl-c to exit.\n")
117+
fmt.Scanln()
118+
}
119+
120+
if err := Install(writer, daemon); err != nil {
121+
return err
122+
}
123+
124+
// Source again
125+
if err := SourceNixEnv(); err != nil {
126+
return err
127+
}
128+
129+
fmt.Fprintln(writer, "Nix installed successfully. Devbox is ready to use!")
130+
return nil
131+
}

0 commit comments

Comments
 (0)