@@ -18,7 +18,6 @@ import (
18
18
"go.jetpack.io/devbox/internal/devbox/devopt"
19
19
"go.jetpack.io/devbox/internal/devpkg"
20
20
"go.jetpack.io/devbox/internal/devpkg/pkgtype"
21
- "go.jetpack.io/devbox/internal/nix/nixprofile"
22
21
"go.jetpack.io/devbox/internal/shellgen"
23
22
24
23
"go.jetpack.io/devbox/internal/boxcli/usererr"
@@ -274,10 +273,6 @@ func (d *Devbox) ensureStateIsUpToDate(ctx context.Context, mode installMode) er
274
273
}
275
274
}
276
275
277
- if err := d .syncPackagesToProfile (ctx , mode ); err != nil {
278
- return err
279
- }
280
-
281
276
if err := d .InstallRunXPackages (ctx ); err != nil {
282
277
return err
283
278
}
@@ -297,6 +292,14 @@ func (d *Devbox) ensureStateIsUpToDate(ctx context.Context, mode installMode) er
297
292
return err
298
293
}
299
294
295
+ profile , err := d .profilePath ()
296
+ if err != nil {
297
+ return err
298
+ }
299
+ if err := syncFlakeToProfile (ctx , d .flakeDir (), profile ); err != nil {
300
+ return err
301
+ }
302
+
300
303
// Ensure we clean out packages that are no longer needed.
301
304
d .lockfile .Tidy ()
302
305
@@ -331,162 +334,6 @@ func (d *Devbox) profilePath() (string, error) {
331
334
return absPath , errors .WithStack (os .MkdirAll (filepath .Dir (absPath ), 0o755 ))
332
335
}
333
336
334
- // syncPackagesToProfile can ensure that all packages in devbox.json exist in the nix profile,
335
- // and no more. However, it may skip some steps depending on the `mode`.
336
- func (d * Devbox ) syncPackagesToProfile (ctx context.Context , mode installMode ) error {
337
- defer debug .FunctionTimer ().End ()
338
- defer trace .StartRegion (ctx , "syncPackagesToProfile" ).End ()
339
-
340
- // First, fetch the profile items from the nix-profile,
341
- // and get the installable packages
342
- profileDir , err := d .profilePath ()
343
- if err != nil {
344
- return err
345
- }
346
- profileItems , err := nixprofile .ProfileListItems (d .stderr , profileDir )
347
- if err != nil {
348
- return err
349
- }
350
- packages , err := d .AllInstallablePackages ()
351
- if err != nil {
352
- return err
353
- }
354
-
355
- // Remove non-nix packages from the list
356
- packages = lo .Filter (packages , devpkg .IsNix )
357
-
358
- if err := devpkg .FillNarInfoCache (ctx , packages ... ); err != nil {
359
- return err
360
- }
361
-
362
- // Second, remove any packages from the nix-profile that are not in the config
363
- itemsToKeep := profileItems
364
- if mode != install {
365
- itemsToKeep , err = d .removeExtraItemsFromProfile (ctx , profileDir , profileItems , packages )
366
- if err != nil {
367
- return err
368
- }
369
- }
370
-
371
- // we are done if mode is uninstall
372
- if mode == uninstall {
373
- return nil
374
- }
375
-
376
- // Last, find the pending packages, and ensure they are added to the nix-profile
377
- // Important to maintain the order of packages as specified by
378
- // Devbox.InstallablePackages() (higher priority first).
379
- // We also run nix profile upgrade on any virtenv flakes. This is a bit of a
380
- // blunt approach, but ensured any plugin created flakes are up-to-date.
381
- pending := []* devpkg.Package {}
382
- for _ , pkg := range packages {
383
- idx , err := nixprofile .ProfileListIndex (& nixprofile.ProfileListIndexArgs {
384
- Items : itemsToKeep ,
385
- Lockfile : d .lockfile ,
386
- Writer : d .stderr ,
387
- Package : pkg ,
388
- ProfileDir : profileDir ,
389
- })
390
- if err != nil {
391
- if ! errors .Is (err , nix .ErrPackageNotFound ) {
392
- return err
393
- }
394
- pending = append (pending , pkg )
395
- } else if f , err := pkg .FlakeInstallable (); err == nil && d .pluginManager .PathIsInVirtenv (f .Ref .Path ) {
396
- if err := nix .ProfileUpgrade (profileDir , idx ); err != nil {
397
- return err
398
- }
399
- }
400
- }
401
-
402
- return d .addPackagesToProfile (ctx , pending )
403
- }
404
-
405
- func (d * Devbox ) removeExtraItemsFromProfile (
406
- ctx context.Context ,
407
- profileDir string ,
408
- profileItems []* nixprofile.NixProfileListItem ,
409
- packages []* devpkg.Package ,
410
- ) ([]* nixprofile.NixProfileListItem , error ) {
411
- defer debug .FunctionTimer ().End ()
412
- defer trace .StartRegion (ctx , "removeExtraPackagesFromProfile" ).End ()
413
-
414
- itemsToKeep := []* nixprofile.NixProfileListItem {}
415
- extras := []* nixprofile.NixProfileListItem {}
416
- // Note: because devpkg.Package uses memoization when normalizing attribute paths (slow operation),
417
- // and since we're reusing the Package objects, this O(n*m) loop becomes O(n+m) wrt the slow operation.
418
- for _ , item := range profileItems {
419
- found := false
420
- for _ , pkg := range packages {
421
- if item .Matches (pkg , d .lockfile ) {
422
- itemsToKeep = append (itemsToKeep , item )
423
- found = true
424
- break
425
- }
426
- }
427
- if ! found {
428
- extras = append (extras , item )
429
- }
430
- }
431
- // Remove by index to avoid comparing nix.ProfileListItem <> nix.Inputs again.
432
- if err := nixprofile .ProfileRemoveItems (profileDir , extras ); err != nil {
433
- return nil , err
434
- }
435
- return itemsToKeep , nil
436
- }
437
-
438
- // addPackagesToProfile inspects the packages in devbox.json, checks which of them
439
- // are missing from the nix profile, and then installs each package individually into the
440
- // nix profile.
441
- func (d * Devbox ) addPackagesToProfile (ctx context.Context , pkgs []* devpkg.Package ) error {
442
- defer debug .FunctionTimer ().End ()
443
- defer trace .StartRegion (ctx , "addPackagesToProfile" ).End ()
444
-
445
- if len (pkgs ) == 0 {
446
- return nil
447
- }
448
-
449
- // If packages are in profile but nixpkgs has been purged, the experience
450
- // will be poor when we try to run print-dev-env. So we ensure nixpkgs is
451
- // prefetched for all relevant packages (those not in binary cache).
452
- if err := devpkg .EnsureNixpkgsPrefetched (ctx , d .stderr , pkgs ); err != nil {
453
- return err
454
- }
455
-
456
- var msg string
457
- if len (pkgs ) == 1 {
458
- msg = fmt .Sprintf ("Installing package: %s." , pkgs [0 ])
459
- } else {
460
- pkgNames := lo .Map (pkgs , func (p * devpkg.Package , _ int ) string { return p .Raw })
461
- msg = fmt .Sprintf ("Installing %d packages: %s." , len (pkgs ), strings .Join (pkgNames , ", " ))
462
- }
463
- fmt .Fprintf (d .stderr , "\n %s\n \n " , msg )
464
-
465
- profileDir , err := d .profilePath ()
466
- if err != nil {
467
- return fmt .Errorf ("error getting profile path: %w" , err )
468
- }
469
-
470
- total := len (pkgs )
471
- for idx , pkg := range pkgs {
472
- stepNum := idx + 1
473
-
474
- stepMsg := fmt .Sprintf ("[%d/%d] %s" , stepNum , total , pkg )
475
-
476
- if err = nixprofile .ProfileInstall (ctx , & nixprofile.ProfileInstallArgs {
477
- CustomStepMessage : stepMsg ,
478
- Lockfile : d .lockfile ,
479
- Package : pkg .Raw ,
480
- ProfilePath : profileDir ,
481
- Writer : d .stderr ,
482
- }); err != nil {
483
- return fmt .Errorf ("error installing package %s: %w" , pkg , err )
484
- }
485
- }
486
-
487
- return nil
488
- }
489
-
490
337
var resetCheckDone = false
491
338
492
339
// resetProfileDirForFlakes ensures the profileDir directory is cleared of old
0 commit comments