@@ -35,6 +35,7 @@ import (
35
35
"go.jetpack.io/devbox/internal/services"
36
36
"go.jetpack.io/devbox/internal/telemetry"
37
37
"go.jetpack.io/devbox/internal/ux"
38
+ "go.jetpack.io/devbox/internal/wrapnix"
38
39
)
39
40
40
41
const (
@@ -148,8 +149,8 @@ func (d *Devbox) Generate() error {
148
149
return errors .WithStack (d .generateShellFiles ())
149
150
}
150
151
151
- func (d * Devbox ) Shell () error {
152
- ctx , task := trace .NewTask (context . Background () , "devboxShell" )
152
+ func (d * Devbox ) Shell (ctx context. Context ) error {
153
+ ctx , task := trace .NewTask (ctx , "devboxShell" )
153
154
defer task .End ()
154
155
155
156
if err := d .ensurePackagesAreInstalled (ctx , ensure ); err != nil {
@@ -167,11 +168,15 @@ func (d *Devbox) Shell() error {
167
168
return err
168
169
}
169
170
170
- env , err := d .computeNixEnv (ctx )
171
+ env , err := d .cachedComputeNixEnv (ctx )
171
172
if err != nil {
172
173
return err
173
174
}
174
175
176
+ if err := wrapnix .CreateWrappers (ctx , d ); err != nil {
177
+ return err
178
+ }
179
+
175
180
shellStartTime := os .Getenv ("DEVBOX_SHELL_START_TIME" )
176
181
if shellStartTime == "" {
177
182
shellStartTime = telemetry .UnixTimestampFromTime (telemetry .CommandStartTime ())
@@ -207,11 +212,15 @@ func (d *Devbox) RunScript(cmdName string, cmdArgs []string) error {
207
212
return err
208
213
}
209
214
210
- env , err := d .computeNixEnv (ctx )
215
+ env , err := d .cachedComputeNixEnv (ctx )
211
216
if err != nil {
212
217
return err
213
218
}
214
219
220
+ if err = wrapnix .CreateWrappers (ctx , d ); err != nil {
221
+ return err
222
+ }
223
+
215
224
var cmdWithArgs []string
216
225
if _ , ok := d .cfg .Shell .Scripts [cmdName ]; ok {
217
226
// it's a script, so replace the command with the script file's path.
@@ -247,7 +256,7 @@ func (d *Devbox) PrintEnv() (string, error) {
247
256
ctx , task := trace .NewTask (context .Background (), "devboxPrintEnv" )
248
257
defer task .End ()
249
258
250
- envs , err := d .computeNixEnv (ctx )
259
+ envs , err := d .cachedComputeNixEnv (ctx )
251
260
if err != nil {
252
261
return "" , err
253
262
}
@@ -544,21 +553,26 @@ func (d *Devbox) computeNixEnv(ctx context.Context) (map[string]string, error) {
544
553
debug .Log ("nix environment PATH is: %s" , env )
545
554
546
555
// Add any vars defined in plugins.
556
+ // TODO: Now that we have bin wrappers, this may can eventually be removed.
557
+ // We still need to be able to add env variables to non-service binaries
558
+ // (e.g. ruby). This would involve understanding what binaries are associated
559
+ // to a given plugin.
547
560
pluginEnv , err := plugin .Env (d .mergedPackages (), d .projectDir , env )
548
561
if err != nil {
549
562
return nil , err
550
563
}
551
564
552
- for k , v := range pluginEnv {
553
- env [k ] = v
554
- }
565
+ addEnvIfNotPreviouslySetByDevbox (env , pluginEnv )
566
+
567
+ // Prepend virtenv bin path first so user can override it if needed. Virtenv
568
+ // is where the bin wrappers live
569
+ env ["PATH" ] = JoinPathLists (d .virtenvBinPath (), env ["PATH" ])
555
570
556
571
// Include env variables in devbox.json
557
- if featureflag .EnvConfig .Enabled () {
558
- for k , v := range d .configEnvs (env ) {
559
- env [k ] = v
560
- }
561
- }
572
+ configEnv := d .configEnvs (env )
573
+ addEnvIfNotPreviouslySetByDevbox (env , configEnv )
574
+
575
+ markEnvsAsSetByDevbox (pluginEnv , configEnv )
562
576
563
577
nixEnvPath := env ["PATH" ]
564
578
debug .Log ("PATH after plugins and config is: %s" , nixEnvPath )
@@ -571,6 +585,17 @@ func (d *Devbox) computeNixEnv(ctx context.Context) (map[string]string, error) {
571
585
return env , nil
572
586
}
573
587
588
+ var nixEnvCache map [string ]string
589
+
590
+ // cachedComputeNixEnv is a wrapper around computeNixEnv that caches the result.
591
+ func (d * Devbox ) cachedComputeNixEnv (ctx context.Context ) (map [string ]string , error ) {
592
+ var err error
593
+ if nixEnvCache == nil {
594
+ nixEnvCache , err = d .computeNixEnv (ctx )
595
+ }
596
+ return nixEnvCache , err
597
+ }
598
+
574
599
// writeScriptsToFiles writes scripts defined in devbox.json into files inside .devbox/gen/scripts.
575
600
// Scripts (and hooks) are persisted so that we can easily call them from devbox run (inside or outside shell).
576
601
func (d * Devbox ) writeScriptsToFiles () error {
@@ -768,3 +793,37 @@ func (d *Devbox) setCommonHelperEnvVars(env map[string]string) {
768
793
env ["LD_LIBRARY_PATH" ] = filepath .Join (d .projectDir , nix .ProfilePath , "lib" ) + ":" + env ["LD_LIBRARY_PATH" ]
769
794
env ["LIBRARY_PATH" ] = filepath .Join (d .projectDir , nix .ProfilePath , "lib" ) + ":" + env ["LIBRARY_PATH" ]
770
795
}
796
+
797
+ func (d * Devbox ) virtenvBinPath () string {
798
+ return filepath .Join (d .projectDir , plugin .VirtenvBinPath )
799
+ }
800
+
801
+ // nix bins returns the paths to all the nix binaries that are installed by
802
+ // the flake. If there are conflicts, it returns the first one it finds of a
803
+ // give name. This matches how nix flakes behaves if there are conflicts in
804
+ // buildInputs
805
+ func (d * Devbox ) NixBins (ctx context.Context ) ([]string , error ) {
806
+ env , err := d .cachedComputeNixEnv (ctx )
807
+
808
+ if err != nil {
809
+ return nil , err
810
+ }
811
+ dirs := strings .Split (env ["buildInputs" ], " " )
812
+ bins := map [string ]string {}
813
+ for _ , dir := range dirs {
814
+ binPath := filepath .Join (dir , "bin" )
815
+ if _ , err = os .Stat (binPath ); os .IsNotExist (err ) {
816
+ continue
817
+ }
818
+ files , err := os .ReadDir (binPath )
819
+ if err != nil {
820
+ return nil , errors .WithStack (err )
821
+ }
822
+ for _ , file := range files {
823
+ if _ , alreadySet := bins [file .Name ()]; ! alreadySet {
824
+ bins [file .Name ()] = filepath .Join (binPath , file .Name ())
825
+ }
826
+ }
827
+ }
828
+ return lo .Values (bins ), nil
829
+ }
0 commit comments