Skip to content

Commit 1052c4e

Browse files
authored
[env] Add env flags to direnv commands (#1354)
## Summary This allows users to generate .envrc files that use custom env variables like so: ```bash devbox generate direnv -e foo=bar -e foo1=bar2 devbox generate direnv --env-file .env ``` Users can also manually modify `.envrc` files to add additional flags: `devbox generate direnv --print-envrc -e foo=bar` ## How was it tested? Generated .envrc file with custom env flags. Then used direnv and verified environment was setup as expected. ## Backward compatibility Newly generated `.envrc` files that contain `--env` or `--env-file` flags will not be compatible with previous versions of devbox.
1 parent a1e8804 commit 1052c4e

File tree

8 files changed

+61
-27
lines changed

8 files changed

+61
-27
lines changed

devbox.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type Devbox interface {
2727
Generate(ctx context.Context) error
2828
GenerateDevcontainer(ctx context.Context, force bool) error
2929
GenerateDockerfile(ctx context.Context, force bool) error
30-
GenerateEnvrcFile(ctx context.Context, force bool) error
30+
GenerateEnvrcFile(ctx context.Context, force bool, envFlags devopt.EnvFlags) error
3131
Info(ctx context.Context, pkg string, markdown bool) error
3232
Install(ctx context.Context) error
3333
IsEnvEnabled() bool
@@ -67,8 +67,8 @@ func GlobalDataPath() (string, error) {
6767
return impl.GlobalDataPath()
6868
}
6969

70-
func PrintEnvrcContent(w io.Writer) error {
71-
return impl.PrintEnvrcContent(w)
70+
func PrintEnvrcContent(w io.Writer, envFlags devopt.EnvFlags) error {
71+
return impl.PrintEnvrcContent(w, envFlags)
7272
}
7373

7474
// ExportifySystemPathWithoutWrappers reads $PATH, removes `virtenv/.wrappers/bin` paths,

internal/boxcli/env.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,26 @@ import (
99
"github.com/joho/godotenv"
1010
"github.com/pkg/errors"
1111
"github.com/spf13/cobra"
12+
"go.jetpack.io/devbox/internal/impl/devopt"
1213
)
1314

1415
// to be composed into xyzCmdFlags structs
15-
type envFlag struct {
16-
env map[string]string
17-
envFile string
18-
}
16+
type envFlag devopt.EnvFlags
1917

2018
func (f *envFlag) register(cmd *cobra.Command) {
2119
cmd.PersistentFlags().StringToStringVarP(
22-
&f.env, "env", "e", nil, "environment variables to set in the devbox environment",
20+
&f.EnvMap, "env", "e", nil, "environment variables to set in the devbox environment",
2321
)
2422
cmd.PersistentFlags().StringVar(
25-
&f.envFile, "env-file", "", "path to a file containing environment variables to set in the devbox environment",
23+
&f.EnvFile, "env-file", "", "path to a file containing environment variables to set in the devbox environment",
2624
)
2725
}
2826

2927
func (f *envFlag) Env(path string) (map[string]string, error) {
3028
envs := map[string]string{}
3129
var err error
32-
if f.envFile != "" {
33-
envPath := f.envFile
30+
if f.EnvFile != "" {
31+
envPath := f.EnvFile
3432
if !filepath.IsAbs(envPath) {
3533
envPath = filepath.Join(path, envPath)
3634
}
@@ -40,7 +38,7 @@ func (f *envFlag) Env(path string) (map[string]string, error) {
4038
}
4139
}
4240

43-
for k, v := range f.env {
41+
for k, v := range f.EnvMap {
4442
envs[k] = v
4543
}
4644

internal/boxcli/generate.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
)
1414

1515
type generateCmdFlags struct {
16+
envFlag // only used by generate direnv command
1617
config configFlags
1718
force bool
1819
printEnvrcContent bool
@@ -96,6 +97,7 @@ func direnvCmd() *cobra.Command {
9697
return runGenerateDirenvCmd(cmd, flags)
9798
},
9899
}
100+
flags.envFlag.register(command)
99101
command.Flags().BoolVarP(
100102
&flags.force, "force", "f", false, "force overwrite existing files")
101103
command.Flags().BoolVarP(
@@ -150,7 +152,8 @@ func runGenerateCmd(cmd *cobra.Command, flags *generateCmdFlags) error {
150152

151153
func runGenerateDirenvCmd(cmd *cobra.Command, flags *generateCmdFlags) error {
152154
if flags.printEnvrcContent {
153-
return devbox.PrintEnvrcContent(cmd.OutOrStdout())
155+
return devbox.PrintEnvrcContent(
156+
cmd.OutOrStdout(), devopt.EnvFlags(flags.envFlag))
154157
}
155158

156159
box, err := devbox.Open(&devopt.Opts{
@@ -161,5 +164,6 @@ func runGenerateDirenvCmd(cmd *cobra.Command, flags *generateCmdFlags) error {
161164
return errors.WithStack(err)
162165
}
163166

164-
return box.GenerateEnvrcFile(cmd.Context(), flags.force)
167+
return box.GenerateEnvrcFile(
168+
cmd.Context(), flags.force, devopt.EnvFlags(flags.envFlag))
165169
}

internal/impl/devbox.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -431,12 +431,12 @@ func (d *Devbox) GenerateDockerfile(ctx context.Context, force bool) error {
431431
d.projectDir, d.getLocalFlakesDirs(), false /* isDevcontainer */))
432432
}
433433

434-
func PrintEnvrcContent(w io.Writer) error {
435-
return generate.EnvrcContent(w)
434+
func PrintEnvrcContent(w io.Writer, envFlags devopt.EnvFlags) error {
435+
return generate.EnvrcContent(w, envFlags)
436436
}
437437

438438
// GenerateEnvrcFile generates a .envrc file that makes direnv integration convenient
439-
func (d *Devbox) GenerateEnvrcFile(ctx context.Context, force bool) error {
439+
func (d *Devbox) GenerateEnvrcFile(ctx context.Context, force bool, envFlags devopt.EnvFlags) error {
440440
ctx, task := trace.NewTask(ctx, "devboxGenerateEnvrc")
441441
defer task.End()
442442

@@ -461,7 +461,7 @@ func (d *Devbox) GenerateEnvrcFile(ctx context.Context, force bool) error {
461461
}
462462

463463
// .envrc file creation
464-
err := generate.CreateEnvrc(ctx, d.projectDir)
464+
err := generate.CreateEnvrc(ctx, d.projectDir, envFlags)
465465
if err != nil {
466466
return errors.WithStack(err)
467467
}

internal/impl/devopt/devboxopts.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ type Opts struct {
1313
CustomProcessComposeFile string
1414
Writer io.Writer
1515
}
16+
17+
type EnvFlags struct {
18+
EnvMap map[string]string
19+
EnvFile string
20+
}

internal/impl/generate/devcontainer_util.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"context"
1010
"embed"
1111
"encoding/json"
12+
"fmt"
1213
"html/template"
1314
"io"
1415
"os"
@@ -18,6 +19,7 @@ import (
1819
"strings"
1920

2021
"go.jetpack.io/devbox/internal/debug"
22+
"go.jetpack.io/devbox/internal/impl/devopt"
2123
)
2224

2325
//go:embed tmpl/*
@@ -90,7 +92,7 @@ func CreateDevcontainer(ctx context.Context, path string, pkgs []string) error {
9092
return err
9193
}
9294

93-
func CreateEnvrc(ctx context.Context, path string) error {
95+
func CreateEnvrc(ctx context.Context, path string, envFlags devopt.EnvFlags) error {
9496
defer trace.StartRegion(ctx, "createEnvrc").End()
9597

9698
// create .envrc file
@@ -99,11 +101,24 @@ func CreateEnvrc(ctx context.Context, path string) error {
99101
return err
100102
}
101103
defer file.Close()
102-
// get .envrc content
103-
tmplName := "envrc.tmpl"
104-
t := template.Must(template.ParseFS(tmplFS, "tmpl/"+tmplName))
104+
105+
flags := []string{}
106+
107+
if len(envFlags.EnvMap) > 0 {
108+
for k, v := range envFlags.EnvMap {
109+
flags = append(flags, fmt.Sprintf("--env %s=%s", k, v))
110+
}
111+
}
112+
if envFlags.EnvFile != "" {
113+
flags = append(flags, fmt.Sprintf("--env-file %s", envFlags.EnvFile))
114+
}
115+
116+
t := template.Must(template.ParseFS(tmplFS, "tmpl/envrc.tmpl"))
117+
105118
// write content into file
106-
return t.Execute(file, nil)
119+
return t.Execute(file, map[string]string{
120+
"Flags": strings.Join(flags, " "),
121+
})
107122
}
108123

109124
func getDevcontainerContent(pkgs []string) *devcontainerObject {
@@ -156,8 +171,17 @@ func getDevcontainerContent(pkgs []string) *devcontainerObject {
156171
return devcontainerContent
157172
}
158173

159-
func EnvrcContent(w io.Writer) error {
174+
func EnvrcContent(w io.Writer, envFlags devopt.EnvFlags) error {
160175
tmplName := "envrcContent.tmpl"
161176
t := template.Must(template.ParseFS(tmplFS, "tmpl/"+tmplName))
162-
return t.Execute(w, nil)
177+
envFlag := ""
178+
if len(envFlags.EnvMap) > 0 {
179+
for k, v := range envFlags.EnvMap {
180+
envFlag += fmt.Sprintf("--env %s=%s ", k, v)
181+
}
182+
}
183+
return t.Execute(w, map[string]string{
184+
"EnvFlag": envFlag,
185+
"EnvFile": envFlags.EnvFile,
186+
})
163187
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Automatically sets up your devbox environment whenever you cd into this
22
# directory via our direnv integration:
33

4-
eval "$(devbox generate direnv --print-envrc)"
4+
eval "$(devbox generate direnv --print-envrc{{ if .Flags}} {{ .Flags }}{{ end }})"
55

66
# check out https://www.jetpack.io/devbox/docs/ide_configuration/direnv/
77
# for more details
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use_devbox() {
22
watch_file devbox.json
3-
eval "$(devbox shellenv --init-hook --install)"
3+
eval "$(devbox shellenv --init-hook --install{{ if .EnvFlag }} {{ .EnvFlag }}{{ end }})"
44
}
55
use devbox
6+
{{ if .EnvFile }}
7+
dotenv_if_exists {{ .EnvFile }}
8+
{{ end }}

0 commit comments

Comments
 (0)