Skip to content

Commit f19dbfc

Browse files
authored
wrappers] ensure bin-wrappers invoke other binaries and not bin-wrappers (#1160)
## Summary This is an alternate to #1151 (see explanation in #1159) In this approach, the wrapped-binary always calls: `eval $(devbox shellenv only-path-without-wrappers)` to ensure that the PATH is set without the `wrappers/bin` directory. In contrast to #1151, we do not always set any other environment variables Fixes #1142 ## How was it tested? issue from #1142 is fixed: ``` > devbox run -- iex -S mix * creating .nix-mix/archives/hex-2.0.6 * creating .nix-mix/elixir/1-14/rebar3 Resolving Hex dependencies... Resolution completed in 0.016s Unchanged: cowboy 2.9.0 cowlib 2.11.0 ranch 1.8.0 All dependencies are up to date Erlang/OTP 25 [erts-13.2.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] Hello World! Interactive Elixir (1.14.4) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> Goodbye World 17:18:09.349 [notice] Application elixir_hello exited: shutdown BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution ``` - [ ] testscripts should pass
1 parent 51b98a7 commit f19dbfc

File tree

7 files changed

+93
-9
lines changed

7 files changed

+93
-9
lines changed

devbox.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type Devbox interface {
3333
Install(ctx context.Context) error
3434
IsEnvEnabled() bool
3535
ListScripts() []string
36-
PrintEnv(ctx context.Context, includeHooks bool) (string, error)
36+
PrintEnv(opts *devopt.PrintEnv) (string, error)
3737
PrintGlobalList() error
3838
Pull(ctx context.Context, overwrite bool, path string) error
3939
Push(url string) error

examples/stacks/lapp-stack/devbox.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@
3131
]
3232
}
3333
}
34-
}
34+
}

internal/boxcli/shell.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func runShellCmd(cmd *cobra.Command, flags shellCmdFlags) error {
5959
if flags.printEnv {
6060
// false for includeHooks is because init hooks is not compatible with .envrc files generated
6161
// by versions older than 0.4.6
62-
script, err := box.PrintEnv(cmd.Context(), false /*includeHooks*/)
62+
script, err := box.PrintEnv(&devopt.PrintEnv{Ctx: cmd.Context()})
6363
if err != nil {
6464
return err
6565
}

internal/boxcli/shellenv.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ func shellEnvCmd() *cobra.Command {
5555
// This is used by bin wrappers and not meant for end users.
5656
command.Flag("use-cached-print-dev-env").Hidden = true
5757
flags.config.register(command)
58+
59+
command.AddCommand(shellEnvOnlyPathWithoutWrappersCmd())
60+
5861
return command
5962
}
6063

@@ -74,7 +77,60 @@ func shellEnvFunc(cmd *cobra.Command, flags shellEnvCmdFlags) (string, error) {
7477
}
7578
}
7679

77-
envStr, err := box.PrintEnv(cmd.Context(), flags.runInitHook)
80+
opts := &devopt.PrintEnv{
81+
Ctx: cmd.Context(),
82+
IncludeHooks: flags.runInitHook,
83+
}
84+
envStr, err := box.PrintEnv(opts)
85+
if err != nil {
86+
return "", err
87+
}
88+
89+
return envStr, nil
90+
}
91+
92+
type shellEnvOnlyPathWithoutWrappersCmdFlags struct {
93+
config configFlags
94+
}
95+
96+
func shellEnvOnlyPathWithoutWrappersCmd() *cobra.Command {
97+
flags := shellEnvOnlyPathWithoutWrappersCmdFlags{}
98+
command := &cobra.Command{
99+
Use: "only-path-without-wrappers",
100+
Hidden: true,
101+
Short: "Print shell commands that export PATH without the bin-wrappers",
102+
Args: cobra.ExactArgs(0),
103+
PreRunE: ensureNixInstalled,
104+
RunE: func(cmd *cobra.Command, args []string) error {
105+
s, err := shellEnvOnlyPathWithoutWrappersFunc(cmd, &flags)
106+
if err != nil {
107+
return err
108+
}
109+
fmt.Fprintln(cmd.OutOrStdout(), s)
110+
fmt.Fprintln(cmd.OutOrStdout(), "hash -r")
111+
return nil
112+
},
113+
}
114+
flags.config.register(command)
115+
return command
116+
}
117+
118+
func shellEnvOnlyPathWithoutWrappersFunc(cmd *cobra.Command, flags *shellEnvOnlyPathWithoutWrappersCmdFlags) (string, error) {
119+
120+
box, err := devbox.Open(&devopt.Opts{
121+
Dir: flags.config.path,
122+
Writer: cmd.ErrOrStderr(),
123+
Pure: false,
124+
})
125+
if err != nil {
126+
return "", err
127+
}
128+
129+
opts := &devopt.PrintEnv{
130+
Ctx: cmd.Context(),
131+
OnlyPathWithoutWrappers: true,
132+
}
133+
envStr, err := box.PrintEnv(opts)
78134
if err != nil {
79135
return "", err
80136
}

internal/impl/devbox.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ func (d *Devbox) RunScript(ctx context.Context, cmdName string, cmdArgs []string
293293
// creates all wrappers, but does not run init hooks. It is used to power
294294
// devbox install cli command.
295295
func (d *Devbox) Install(ctx context.Context) error {
296-
if _, err := d.PrintEnv(ctx, false /* run init hooks */); err != nil {
296+
if _, err := d.PrintEnv(&devopt.PrintEnv{Ctx: ctx}); err != nil {
297297
return err
298298
}
299299
return wrapnix.CreateWrappers(ctx, d)
@@ -309,8 +309,8 @@ func (d *Devbox) ListScripts() []string {
309309
return keys
310310
}
311311

312-
func (d *Devbox) PrintEnv(ctx context.Context, includeHooks bool) (string, error) {
313-
ctx, task := trace.NewTask(ctx, "devboxPrintEnv")
312+
func (d *Devbox) PrintEnv(opts *devopt.PrintEnv) (string, error) {
313+
ctx, task := trace.NewTask(opts.Ctx, "devboxPrintEnv")
314314
defer task.End()
315315

316316
if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil {
@@ -322,9 +322,23 @@ func (d *Devbox) PrintEnv(ctx context.Context, includeHooks bool) (string, error
322322
return "", err
323323
}
324324

325+
if opts.OnlyPathWithoutWrappers {
326+
path := []string{}
327+
for _, p := range strings.Split(envs["PATH"], string(filepath.ListSeparator)) {
328+
if !strings.Contains(p, plugin.WrapperPath) {
329+
path = append(path, p)
330+
}
331+
}
332+
333+
// reset envs to be PATH only!
334+
envs = map[string]string{
335+
"PATH": strings.Join(path, string(filepath.ListSeparator)),
336+
}
337+
}
338+
325339
envStr := exportify(envs)
326340

327-
if includeHooks {
341+
if opts.IncludeHooks {
328342
hooksStr := ". " + d.scriptPath(hooksFilename)
329343
envStr = fmt.Sprintf("%s\n%s;\n", envStr, hooksStr)
330344
}

internal/impl/devopt/devboxopts.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
package devopt
22

3-
import "io"
3+
import (
4+
"context"
5+
"io"
6+
)
47

58
type Opts struct {
69
Dir string
710
Pure bool
811
IgnoreWarnings bool
912
Writer io.Writer
1013
}
14+
15+
type PrintEnv struct {
16+
Ctx context.Context
17+
IncludeHooks bool
18+
OnlyPathWithoutWrappers bool
19+
}

internal/wrapnix/wrapper.sh.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,9 @@ export {{ .ShellEnvHashKey }}_GUARD=true
2929
eval "$(DO_NOT_TRACK=1 devbox shellenv -c {{ .ProjectDir }})"
3030
fi
3131

32+
# So that we do not invoke other bin-wrappers from
33+
# this bin-wrapper. Instead, we directly invoke the binary from the nix store, which
34+
# should be in PATH.
35+
eval "$(devbox shellenv only-path-without-wrappers)"
36+
3237
exec {{ .Command }} "$@"

0 commit comments

Comments
 (0)