Skip to content

Commit

Permalink
recompute env in shell and run
Browse files Browse the repository at this point in the history
  • Loading branch information
savil authored and savil committed Oct 29, 2024
1 parent 399b7f3 commit 2ecb5ed
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 47 deletions.
19 changes: 13 additions & 6 deletions internal/boxcli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import (

type runCmdFlags struct {
envFlag
config configFlags
omitNixEnv bool
pure bool
listScripts bool
config configFlags
omitNixEnv bool
pure bool
listScripts bool
recomputeEnv bool
}

// runFlagDefaults are the flag default values that differ
Expand Down Expand Up @@ -62,6 +63,7 @@ func runCmd(defaults runFlagDefaults) *cobra.Command {
"shell environment will omit the env-vars from print-dev-env",
)
_ = command.Flags().MarkHidden("omit-nix-env")
command.Flags().BoolVar(&flags.recomputeEnv, "recompute", true, "recompute environment if needed")

command.ValidArgs = listScripts(command, flags)

Expand All @@ -84,6 +86,7 @@ func listScripts(cmd *cobra.Command, flags runCmdFlags) []string {
}

func runScriptCmd(cmd *cobra.Command, args []string, flags runCmdFlags) error {
ctx := cmd.Context()
if len(args) == 0 || flags.listScripts {
scripts := listScripts(cmd, flags)
if len(scripts) == 0 {
Expand Down Expand Up @@ -111,9 +114,9 @@ func runScriptCmd(cmd *cobra.Command, args []string, flags runCmdFlags) error {
// Check the directory exists.
box, err := devbox.Open(&devopt.Opts{
Dir: path,
Env: env,
Environment: flags.config.environment,
Stderr: cmd.ErrOrStderr(),
Env: env,
})
if err != nil {
return redact.Errorf("error reading devbox.json: %w", err)
Expand All @@ -122,8 +125,12 @@ func runScriptCmd(cmd *cobra.Command, args []string, flags runCmdFlags) error {
envOpts := devopt.EnvOptions{
OmitNixEnv: flags.omitNixEnv,
Pure: flags.pure,
RecomputeEnv: &devopt.RecomputeEnvOpts{
Disabled: !flags.recomputeEnv,
StateOutOfDateMessage: fmt.Sprintf(devbox.StateOutOfDateMessage, "with --recompute=true"),
},
}
if err := box.RunScript(cmd.Context(), envOpts, script, scriptArgs); err != nil {
if err := box.RunScript(ctx, envOpts, script, scriptArgs); err != nil {
return redact.Errorf("error running script %q in Devbox: %w", script, err)
}
return nil
Expand Down
18 changes: 13 additions & 5 deletions internal/boxcli/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import (

type shellCmdFlags struct {
envFlag
config configFlags
omitNixEnv bool
printEnv bool
pure bool
config configFlags
omitNixEnv bool
printEnv bool
pure bool
recomputeEnv bool
}

// shellFlagDefaults are the flag default values that differ
Expand Down Expand Up @@ -53,17 +54,20 @@ func shellCmd(defaults shellFlagDefaults) *cobra.Command {
"shell environment will omit the env-vars from print-dev-env",
)
_ = command.Flags().MarkHidden("omit-nix-env")
command.Flags().BoolVar(&flags.recomputeEnv, "recompute", true, "recompute environment if needed")

flags.config.register(command)
flags.envFlag.register(command)
return command
}

func runShellCmd(cmd *cobra.Command, flags shellCmdFlags) error {
ctx := cmd.Context()
env, err := flags.Env(flags.config.path)
if err != nil {
return err
}

// Check the directory exists.
box, err := devbox.Open(&devopt.Opts{
Dir: flags.config.path,
Expand Down Expand Up @@ -91,9 +95,13 @@ func runShellCmd(cmd *cobra.Command, flags shellCmdFlags) error {
return shellInceptionErrorMsg("devbox shell")
}

return box.Shell(cmd.Context(), devopt.EnvOptions{
return box.Shell(ctx, devopt.EnvOptions{
OmitNixEnv: flags.omitNixEnv,
Pure: flags.pure,
RecomputeEnv: &devopt.RecomputeEnvOpts{
Disabled: !flags.recomputeEnv,
StateOutOfDateMessage: fmt.Sprintf(devbox.StateOutOfDateMessage, "with --recompute=true"),
},
})
}

Expand Down
5 changes: 4 additions & 1 deletion internal/boxcli/shellenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,14 @@ func shellEnvFunc(
}

envStr, err := box.EnvExports(ctx, devopt.EnvExportsOpts{
DontRecomputeEnvironment: !flags.recomputeEnv,
EnvOptions: devopt.EnvOptions{
OmitNixEnv: flags.omitNixEnv,
PreservePathStack: flags.preservePathStack,
Pure: flags.pure,
RecomputeEnv: &devopt.RecomputeEnvOpts{
Disabled: !flags.recomputeEnv,
StateOutOfDateMessage: fmt.Sprintf(devbox.StateOutOfDateMessage, box.RefreshAliasOrCommand()),
},
},
NoRefreshAlias: flags.noRefreshAlias,
RunHooks: flags.runInitHook,
Expand Down
54 changes: 25 additions & 29 deletions internal/devbox/devbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,22 +351,7 @@ func (d *Devbox) EnvExports(ctx context.Context, opts devopt.EnvExportsOpts) (st
var envs map[string]string
var err error

if opts.DontRecomputeEnvironment {
upToDate, _ := d.lockfile.IsUpToDateAndInstalled(isFishShell())
if !upToDate {
ux.FHidableWarning(
ctx,
d.stderr,
StateOutOfDateMessage,
d.refreshAliasOrCommand(),
)
}

envs, err = d.computeEnv(ctx, true /*usePrintDevEnvCache*/, opts.EnvOptions)
} else {
envs, err = d.ensureStateIsUpToDateAndComputeEnv(ctx, opts.EnvOptions)
}

envs, err = d.ensureStateIsUpToDateAndComputeEnv(ctx, opts.EnvOptions)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -819,23 +804,34 @@ func (d *Devbox) ensureStateIsUpToDateAndComputeEnv(
) (map[string]string, error) {
defer debug.FunctionTimer().End()

// When ensureStateIsUpToDate is called with ensure=true, it always
// returns early if the lockfile is up to date. So we don't need to check here
if err := d.ensureStateIsUpToDate(ctx, ensure); isConnectionError(err) {
if !fileutil.Exists(d.nixPrintDevEnvCachePath()) {
ux.Ferrorf(
if envOpts.RecomputeEnv.Disabled {
upToDate, _ := d.lockfile.IsUpToDateAndInstalled(isFishShell())
if !upToDate {
ux.FHidableWarning(
ctx,
d.stderr,
"Error connecting to the internet and no cached environment found. Aborting.\n",
envOpts.RecomputeEnv.StateOutOfDateMessage,
)
}
} else {
// When ensureStateIsUpToDate is called with ensure=true, it always
// returns early if the lockfile is up to date. So we don't need to check here
if err := d.ensureStateIsUpToDate(ctx, ensure); isConnectionError(err) {
if !fileutil.Exists(d.nixPrintDevEnvCachePath()) {
ux.Ferrorf(
d.stderr,
"Error connecting to the internet and no cached environment found. Aborting.\n",
)
return nil, err
}
ux.Fwarningf(
d.stderr,
"Error connecting to the internet. Will attempt to use cached environment.\n",
)
} else if err != nil {
// Some other non connection error, just return it.
return nil, err
}
ux.Fwarningf(
d.stderr,
"Error connecting to the internet. Will attempt to use cached environment.\n",
)
} else if err != nil {
// Some other non connection error, just return it.
return nil, err
}

// Since ensureStateIsUpToDate calls computeEnv when not up do date,
Expand Down
13 changes: 9 additions & 4 deletions internal/devbox/devopt/devboxopts.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ type UpdateOpts struct {
}

type EnvExportsOpts struct {
DontRecomputeEnvironment bool
EnvOptions EnvOptions
NoRefreshAlias bool
RunHooks bool
EnvOptions EnvOptions
NoRefreshAlias bool
RunHooks bool
}

// EnvOptions configure the Devbox Environment in the `computeEnv` function.
Expand All @@ -76,4 +75,10 @@ type EnvOptions struct {
OmitNixEnv bool
PreservePathStack bool
Pure bool
RecomputeEnv *RecomputeEnvOpts
}

type RecomputeEnvOpts struct {
Disabled bool // Disabled instead of Enabled, because zero-value is false
StateOutOfDateMessage string
}
2 changes: 1 addition & 1 deletion internal/devbox/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ func (d *Devbox) ensureStateIsUpToDate(ctx context.Context, mode installMode) er
ctx,
d.stderr,
StateOutOfDateMessage,
d.refreshAliasOrCommand(),
d.RefreshAliasOrCommand(),
)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/devbox/refresh.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (d *Devbox) isGlobal() bool {
// In some cases (e.g. 2 non-global projects somehow active at the same time),
// refresh might not match. This is a tiny edge case, so no need to make UX
// great, we just print out the entire command.
func (d *Devbox) refreshAliasOrCommand() string {
func (d *Devbox) RefreshAliasOrCommand() string {
if !d.isRefreshAliasSet() {
// even if alias is not set, it might still be set by the end of this process
return fmt.Sprintf("`%s` or `%s`", d.refreshAliasName(), d.refreshCmd())
Expand Down

0 comments on commit 2ecb5ed

Please sign in to comment.