Skip to content

Commit 3cd4dbf

Browse files
authored
[direnv] .envrc simplified (#974)
## Summary Updated .envrc template to make it simpler and also future proof. So that if the contents of `use devbox` function changes in the future, we won't have mismatch between devbox binary and user's `.envrc` file. Added `--envrc` flag to `devbox generate direnv` so that it outputs the content of `use devbox` function. Without the flag, the command generates the following: ``` # Automatically sets up your devbox environment whenever you cd into this # directory via our direnv integration: eval $(devbox generate direnv --envrc) Note: this needs a follow up PR for updating the docs in regards to direnv integration. # check out https://www.jetpack.io/devbox/docs/ide_configuration/direnv/ # for more details ``` ## How was it tested? - compile - in a new directory run `devbox generate direnv` (answer No to the prompt) - update the .envrc file and change `devbox generate ...` to `./devbox generate` (so that it uses the compiled binary). - cd out of directory and back in to check if direnv works as expected.
1 parent 1b0358c commit 3cd4dbf

File tree

8 files changed

+64
-64
lines changed

8 files changed

+64
-64
lines changed

devbox.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ type Devbox interface {
2727
Generate() error
2828
GenerateDevcontainer(force bool) error
2929
GenerateDockerfile(force bool) error
30-
GenerateEnvrc(force bool, source string) error
30+
GenerateEnvrcFile(force bool) error
3131
Info(pkg string, markdown bool) error
3232
ListScripts() []string
3333
PrintEnv(ctx context.Context, includeHooks bool) (string, error)
3434
PrintGlobalList() error
35+
PrintEnvrcContent(w io.Writer) error
3536
PullGlobal(path string) error
3637
// Remove removes Nix packages from the config so that it no longer exists in
3738
// the devbox environment.

internal/boxcli/generate.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
package boxcli
55

66
import (
7-
"os"
8-
97
"github.com/pkg/errors"
108
"github.com/spf13/cobra"
119

@@ -14,9 +12,10 @@ import (
1412
)
1513

1614
type generateCmdFlags struct {
17-
config configFlags
18-
force bool
19-
githubUsername string
15+
config configFlags
16+
force bool
17+
printEnvrcContent bool
18+
githubUsername string
2019
}
2120

2221
func generateCmd() *cobra.Command {
@@ -98,6 +97,11 @@ func direnvCmd() *cobra.Command {
9897
}
9998
command.Flags().BoolVarP(
10099
&flags.force, "force", "f", false, "force overwrite existing files")
100+
command.Flags().BoolVarP(
101+
&flags.printEnvrcContent, "print-envrc", "p", false, "output contents of devbox configuration to use in .envrc")
102+
// this command marks a flag as hidden. Error handling for it is not necessary.
103+
_ = command.Flags().MarkHidden("print-envrc")
104+
101105
flags.config.register(command)
102106
return command
103107
}
@@ -125,7 +129,7 @@ func sshConfigCmd() *cobra.Command {
125129

126130
func runGenerateCmd(cmd *cobra.Command, flags *generateCmdFlags) error {
127131
// Check the directory exists.
128-
box, err := devbox.Open(flags.config.path, os.Stdout)
132+
box, err := devbox.Open(flags.config.path, cmd.ErrOrStderr())
129133
if err != nil {
130134
return errors.WithStack(err)
131135
}
@@ -137,7 +141,10 @@ func runGenerateCmd(cmd *cobra.Command, flags *generateCmdFlags) error {
137141
case "dockerfile":
138142
return box.GenerateDockerfile(flags.force)
139143
case "direnv":
140-
return box.GenerateEnvrc(flags.force, "generate")
144+
if flags.printEnvrcContent {
145+
return box.PrintEnvrcContent(cmd.OutOrStdout())
146+
}
147+
return box.GenerateEnvrcFile(flags.force)
141148
}
142149
return nil
143150
}

internal/boxcli/init.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ func runInitCmd(cmd *cobra.Command, args []string) error {
3232
if err != nil {
3333
return errors.WithStack(err)
3434
}
35-
box, err := devbox.Open(path, cmd.ErrOrStderr())
36-
if err != nil {
37-
return errors.WithStack(err)
38-
}
3935

40-
return errors.WithStack(box.GenerateEnvrc(false, "init"))
36+
return nil
4137
}

internal/impl/devbox.go

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ import (
1515
"runtime/trace"
1616
"strings"
1717
"text/tabwriter"
18+
"text/template"
1819

19-
"github.com/AlecAivazis/survey/v2"
2020
"github.com/fatih/color"
21-
"github.com/mattn/go-isatty"
2221
"github.com/pkg/errors"
2322
"github.com/samber/lo"
2423
"golang.org/x/exp/slices"
@@ -42,6 +41,7 @@ import (
4241
"go.jetpack.io/devbox/internal/searcher"
4342
"go.jetpack.io/devbox/internal/services"
4443
"go.jetpack.io/devbox/internal/telemetry"
44+
"go.jetpack.io/devbox/internal/ux"
4545
"go.jetpack.io/devbox/internal/wrapnix"
4646
)
4747

@@ -388,8 +388,15 @@ func (d *Devbox) GenerateDockerfile(force bool) error {
388388
return errors.WithStack(generate.CreateDockerfile(tmplFS, d.projectDir))
389389
}
390390

391-
// GenerateEnvrc generates a .envrc file that makes direnv integration convenient
392-
func (d *Devbox) GenerateEnvrc(force bool, source string) error {
391+
func (d *Devbox) PrintEnvrcContent(w io.Writer) error {
392+
tmplName := "envrcContent.tmpl"
393+
t := template.Must(template.ParseFS(tmplFS, "tmpl/"+tmplName))
394+
// write content into file
395+
return t.Execute(w, nil)
396+
}
397+
398+
// GenerateEnvrcFile generates a .envrc file that makes direnv integration convenient
399+
func (d *Devbox) GenerateEnvrcFile(force bool) error {
393400
ctx, task := trace.NewTask(context.Background(), "devboxGenerateEnvrc")
394401
defer task.End()
395402

@@ -402,48 +409,31 @@ func (d *Devbox) GenerateEnvrc(force bool, source string) error {
402409
)
403410
}
404411
// confirm .envrc doesn't exist and don't overwrite an existing .envrc
405-
if cmdutil.Exists("direnv") {
406-
// prompt for direnv allow
407-
var result string
408-
isInteractiveMode := isatty.IsTerminal(os.Stdin.Fd())
409-
if isInteractiveMode {
410-
prompt := &survey.Input{
411-
Message: "Do you want to enable direnv integration for this devbox project? [y/N]",
412-
}
413-
err := survey.AskOne(prompt, &result)
414-
if err != nil {
415-
return errors.WithStack(err)
416-
}
417-
}
418-
419-
if strings.ToLower(result) == "y" || !isInteractiveMode || source == "generate" {
420-
if err := nix.EnsureNixInstalled(
421-
d.writer, func() *bool { return lo.ToPtr(false) },
422-
); err != nil {
423-
return err
424-
}
425-
426-
// generate all shell files to ensure we can refer to them in the .envrc script
427-
if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil {
428-
return err
429-
}
412+
if err := nix.EnsureNixInstalled(
413+
d.writer, func() *bool { return lo.ToPtr(false) },
414+
); err != nil {
415+
return err
416+
}
430417

431-
// .envrc file creation
432-
err := generate.CreateEnvrc(tmplFS, d.projectDir)
433-
if err != nil {
434-
return errors.WithStack(err)
435-
}
436-
}
418+
// generate all shell files to ensure we can refer to them in the .envrc script
419+
if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil {
420+
return err
421+
}
437422

438-
if strings.ToLower(result) == "y" || !isInteractiveMode {
439-
cmd := exec.Command("direnv", "allow")
440-
err := cmd.Run()
441-
if err != nil {
442-
return errors.WithStack(err)
443-
}
423+
// .envrc file creation
424+
err := generate.CreateEnvrc(tmplFS, d.projectDir)
425+
if err != nil {
426+
return errors.WithStack(err)
427+
}
428+
ux.Fsuccess(d.writer, "generated .envrc file\n")
429+
if cmdutil.Exists("direnv") {
430+
cmd := exec.Command("direnv", "allow")
431+
err := cmd.Run()
432+
if err != nil {
433+
return errors.WithStack(err)
444434
}
435+
ux.Fsuccess(d.writer, "ran `direnv allow`\n")
445436
}
446-
447437
return nil
448438
}
449439

internal/impl/tmpl/envrc.tmpl

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
# Automatically sets up your devbox environment whenever you cd into this
22
# directory via our direnv integration:
33

4-
use_devbox() {
5-
watch_file devbox.json
6-
if [ -f .devbox/gen/flake/flake.nix ]; then
7-
DEVBOX_SHELL_ENABLED_BACKUP=$DEVBOX_SHELL_ENABLED
8-
eval "$(devbox shellenv --init-hook)"
9-
export DEVBOX_SHELL_ENABLED=$DEVBOX_SHELL_ENABLED_BACKUP
10-
fi
11-
}
12-
use devbox
4+
eval "$(devbox generate direnv --print-envrc)"
135

146
# check out https://www.jetpack.io/devbox/docs/ide_configuration/direnv/
157
# for more details
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use_devbox() {
2+
watch_file devbox.json
3+
eval "$(devbox shellenv --init-hook)"
4+
}
5+
use devbox

internal/ux/messages.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import (
1010
"github.com/fatih/color"
1111
)
1212

13+
func Fsuccess(w io.Writer, format string, a ...any) {
14+
color.New(color.FgHiGreen).Fprint(w, "Success: ")
15+
fmt.Fprintf(w, format, a...)
16+
}
17+
1318
func Fwarning(w io.Writer, format string, a ...any) {
1419
color.New(color.FgHiYellow).Fprint(w, "Warning: ")
1520
fmt.Fprintf(w, format, a...)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
exec devbox init
2+
exec devbox generate direnv
3+
exists .envrc
4+

0 commit comments

Comments
 (0)