@@ -255,13 +255,14 @@ func (d *Devbox) ensureStateIsUpToDate(ctx context.Context, mode installMode) er
255
255
defer trace .StartRegion (ctx , "devboxEnsureStateIsUpToDate" ).End ()
256
256
defer debug .FunctionTimer ().End ()
257
257
258
- // if mode is install or uninstall, then we need to update the nix-profile
259
- // and lockfile, so we must continue below.
260
258
upToDate , err := d .lockfile .IsUpToDateAndInstalled ()
261
259
if err != nil {
262
260
return err
263
261
}
264
262
263
+ // if mode is install or uninstall, then we need to compute some state
264
+ // like updating the flake or installing packages locally, so must continue
265
+ // below
265
266
if mode == ensure {
266
267
// if mode is ensure and we are up to date, then we can skip the rest
267
268
if upToDate {
@@ -270,6 +271,48 @@ func (d *Devbox) ensureStateIsUpToDate(ctx context.Context, mode installMode) er
270
271
fmt .Fprintln (d .stderr , "Ensuring packages are installed." )
271
272
}
272
273
274
+ recomputeState := mode == ensure || d .IsEnvEnabled ()
275
+ if recomputeState {
276
+ if err := d .recomputeState (ctx , mode ); err != nil {
277
+ return err
278
+ }
279
+ } else {
280
+ // TODO: in the next PR, we will only `nix build` the packages that are being
281
+ // added or updated. For now, we continue to call recomputeState here.
282
+ if err := d .recomputeState (ctx , mode ); err != nil {
283
+ return err
284
+ }
285
+ }
286
+
287
+ // If we're in a devbox shell (global or project), then the environment might
288
+ // be out of date after the user installs something. If have direnv active
289
+ // it should reload automatically so we don't need to refresh.
290
+ if d .IsEnvEnabled () && ! upToDate && ! d .IsDirenvActive () {
291
+ ux .Fwarning (
292
+ d .stderr ,
293
+ "Your shell environment may be out of date. Run `%s` to update it.\n " ,
294
+ d .refreshAliasOrCommand (),
295
+ )
296
+ }
297
+
298
+ if err := d .lockfile .Save (); err != nil {
299
+ return err
300
+ }
301
+
302
+ // If we are recomputing state, then we need to update the local.lock file.
303
+ // If not, we leave the local.lock in a stale state.
304
+ if recomputeState {
305
+ return d .lockfile .UpdateAndSaveLocalLock ()
306
+ }
307
+ return nil
308
+ }
309
+
310
+ // recomputeState updates the local state comprising of:
311
+ // - plugins directories
312
+ // - devbox.lock file
313
+ // - the generated flake
314
+ // - the nix-profile
315
+ func (d * Devbox ) recomputeState (ctx context.Context , mode installMode ) error {
273
316
// Create plugin directories first because packages might need them
274
317
for _ , pkg := range d .InstallablePackages () {
275
318
if err := d .PluginManager ().Create (pkg ); err != nil {
@@ -310,18 +353,7 @@ func (d *Devbox) ensureStateIsUpToDate(ctx context.Context, mode installMode) er
310
353
}
311
354
}
312
355
313
- // If we're in a devbox shell (global or project), then the environment might
314
- // be out of date after the user installs something. If have direnv active
315
- // it should reload automatically so we don't need to refresh.
316
- if d .IsEnvEnabled () && ! upToDate && ! d .IsDirenvActive () {
317
- ux .Fwarning (
318
- d .stderr ,
319
- "Your shell environment may be out of date. Run `%s` to update it.\n " ,
320
- d .refreshAliasOrCommand (),
321
- )
322
- }
323
-
324
- return d .lockfile .Save ()
356
+ return nil
325
357
}
326
358
327
359
func (d * Devbox ) profilePath () (string , error ) {
0 commit comments