Skip to content

Commit 31d2c00

Browse files
authored
[bin wrappers] Fixes: don't export PATH, and eval the symlink of the binary (#1330)
## Summary This PR tries to address some concerns with #1324. 1. We drop `export` from `PATH` in the bin-wrappers. This would have modified PATH for all child programs, which we need not do. 2. When creating the symlink, we ensure the target value is passed through `EvalSymlink`. Previously, it was set as the result of `os.Executable`, which may still have been a symlink. ## How was it tested? did a basic sanity test of opening a devbox shell in a golang project
1 parent 654e973 commit 31d2c00

File tree

3 files changed

+35
-16
lines changed

3 files changed

+35
-16
lines changed

internal/boxcli/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func versionCmdFunc(cmd *cobra.Command, _ []string, flags versionFlags) error {
7575
// Not doing for now, since users who have Devbox binary prior to this edit
7676
// (before Devbox v0.5.9) will not invoke this flag in `devbox version update`.
7777
// But we still want this to run for them.
78-
if _, err := wrapnix.CreateDevboxSymlink(); err != nil {
78+
if err := wrapnix.CreateDevboxSymlinkIfPossible(); err != nil {
7979
return err
8080
}
8181
} else {

internal/wrapnix/wrapper.go

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/pkg/errors"
1616
"go.jetpack.io/devbox/internal/cmdutil"
17+
"go.jetpack.io/devbox/internal/debug"
1718
"go.jetpack.io/devbox/internal/fileutil"
1819
"go.jetpack.io/devbox/internal/nix"
1920
"go.jetpack.io/devbox/internal/plugin"
@@ -31,6 +32,10 @@ type devboxer interface {
3132
var wrapper string
3233
var wrapperTemplate = template.Must(template.New("wrapper").Parse(wrapper))
3334

35+
// devboxSymlinkDir is the directory that has the symlink to the devbox binary,
36+
// which is used by the bin-wrappers
37+
var devboxSymlinkDir = xdg.CacheSubpath(filepath.Join("devbox", "bin", "current"))
38+
3439
// CreateWrappers creates wrappers for all the executables in nix paths
3540
func CreateWrappers(ctx context.Context, devbox devboxer) error {
3641
shellEnvHash, err := devbox.ShellEnvHash(ctx)
@@ -51,8 +56,7 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error {
5156
if err != nil {
5257
return err
5358
}
54-
devboxSymlinkPath, err := CreateDevboxSymlink()
55-
if err != nil {
59+
if err := CreateDevboxSymlinkIfPossible(); err != nil {
5660
return err
5761
}
5862

@@ -62,7 +66,7 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error {
6266
BashPath: bashPath,
6367
Command: bin,
6468
ShellEnvHash: shellEnvHash,
65-
DevboxSymlinkDir: filepath.Dir(devboxSymlinkPath),
69+
DevboxSymlinkDir: devboxSymlinkDir,
6670
destPath: filepath.Join(destPath, filepath.Base(bin)),
6771
}); err != nil {
6872
return errors.WithStack(err)
@@ -72,7 +76,7 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error {
7276
return createSymlinksForSupportDirs(devbox.ProjectDir())
7377
}
7478

75-
// CreateDevboxSymlink creates a symlink to the devbox binary
79+
// CreateDevboxSymlinkIfPossible creates a symlink to the devbox binary.
7680
//
7781
// Needed because:
7882
//
@@ -88,29 +92,44 @@ func CreateWrappers(ctx context.Context, devbox devboxer) error {
8892
//
8993
// So, the bin-wrappers need to use a symlink to the latest devbox binary. This
9094
// symlink is updated when devbox is updated.
91-
func CreateDevboxSymlink() (string, error) {
92-
curDir := xdg.CacheSubpath(filepath.Join("devbox", "bin", "current"))
93-
if err := fileutil.EnsureDirExists(curDir, 0755, false /*chmod*/); err != nil {
94-
return "", err
95+
func CreateDevboxSymlinkIfPossible() error {
96+
// Get the symlink path; create the symlink directory if it doesn't exist.
97+
if err := fileutil.EnsureDirExists(devboxSymlinkDir, 0755, false /*chmod*/); err != nil {
98+
return err
9599
}
96-
currentDevboxSymlinkPath := filepath.Join(curDir, "devbox")
100+
currentDevboxSymlinkPath := filepath.Join(devboxSymlinkDir, "devbox")
97101

98-
devboxBinaryPath, err := os.Executable()
102+
// Get the path to the devbox binary.
103+
execPath, err := os.Executable()
99104
if err != nil {
100-
return "", errors.WithStack(err)
105+
return errors.WithStack(err)
101106
}
107+
devboxBinaryPath, evalSymlinkErr := filepath.EvalSymlinks(execPath)
108+
// we check the error below, because we always want to remove the symlink
102109

103110
// We will always re-create this symlink to ensure correctness.
104111
if err := os.Remove(currentDevboxSymlinkPath); err != nil && !errors.Is(err, os.ErrNotExist) {
105-
return "", errors.WithStack(err)
112+
return errors.WithStack(err)
113+
}
114+
115+
if evalSymlinkErr != nil {
116+
// This may return an error due to symlink loops. But we don't stop the
117+
// process for this reason, so the bin-wrappers can still be created.
118+
//
119+
// Once the symlink loop is fixed, and the bin-wrappers
120+
// will start working without needing to be re-created.
121+
//
122+
// nolint:nilerr
123+
debug.Log("Error evaluating symlink: %v", evalSymlinkErr)
124+
return nil
106125
}
107126

108127
// Don't return error if error is os.ErrExist to protect against race conditions.
109128
if err := os.Symlink(devboxBinaryPath, currentDevboxSymlinkPath); err != nil && !errors.Is(err, os.ErrExist) {
110-
return "", errors.WithStack(err)
129+
return errors.WithStack(err)
111130
}
112131

113-
return currentDevboxSymlinkPath, nil
132+
return nil
114133
}
115134

116135
type createWrapperArgs struct {

internal/wrapnix/wrapper.sh.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!{{ .BashPath }}
22

3-
export PATH="{{ .DevboxSymlinkDir }}:$PATH"
3+
PATH="{{ .DevboxSymlinkDir }}:$PATH"
44

55
{{/*
66
# If env variable has never been set by devbox we set it, but also

0 commit comments

Comments
 (0)