From 265f10047fdcfed31facaa8ec4c52e23c03eec3a Mon Sep 17 00:00:00 2001 From: Savil Srivastava <676452+savil@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:31:37 -0700 Subject: [PATCH 1/4] [perf] skip forcing printDevEnv when add/rm/update outside shellenv --- internal/impl/devbox.go | 16 ++++++++-------- internal/impl/envvars.go | 4 ++-- internal/impl/packages.go | 35 ++++++++++++++++++++++------------- internal/impl/update.go | 2 +- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/internal/impl/devbox.go b/internal/impl/devbox.go index 7d0089d8e14..154a38952a9 100644 --- a/internal/impl/devbox.go +++ b/internal/impl/devbox.go @@ -259,7 +259,7 @@ func (d *Devbox) Install(ctx context.Context) error { ctx, task := trace.NewTask(ctx, "devboxInstall") defer task.End() - return d.ensurePackagesAreInstalled(ctx, ensure) + return d.ensureDevboxEnvIsUpToDate(ctx, ensure) } func (d *Devbox) ListScripts() []string { @@ -477,7 +477,7 @@ func (d *Devbox) GenerateEnvrcFile(ctx context.Context, force bool, envFlags dev } // generate all shell files to ensure we can refer to them in the .envrc script - if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil { + if err := d.ensureDevboxEnvIsUpToDate(ctx, ensure); err != nil { return err } @@ -931,9 +931,9 @@ func (d *Devbox) ensurePackagesAreInstalledAndComputeEnv( ) (map[string]string, error) { defer debug.FunctionTimer().End() - // When ensurePackagesAreInstalled is called with ensure=true, it always + // When ensureDevboxEnvIsUpToDate is called with ensure=true, it always // returns early if the lockfile is up to date. So we don't need to check here - if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil { + if err := d.ensureDevboxEnvIsUpToDate(ctx, ensure); err != nil { return nil, err } @@ -1172,10 +1172,10 @@ func (d *Devbox) parseEnvAndExcludeSpecialCases(currentEnv []string) (map[string if ignoreCurrentEnvVar[key] { continue } - // handling special cases to for pure shell - // Passing HOME for pure shell to leak through otherwise devbox binary won't work - // We also include PATH to find the nix installation. It is cleaned for pure mode below - // TERM leaking through is to enable colored text in the pure shell + // handling special cases for pure shell + // - HOME required for devbox binary to work + // - PATH to find the nix installation. It is cleaned for pure mode below. + // - TERM to enable colored text in the pure shell if !d.pure || key == "HOME" || key == "PATH" || key == "TERM" { env[key] = val } diff --git a/internal/impl/envvars.go b/internal/impl/envvars.go index 488e9ad0508..2013a05ef1c 100644 --- a/internal/impl/envvars.go +++ b/internal/impl/envvars.go @@ -69,8 +69,8 @@ func markEnvsAsSetByDevbox(envs ...map[string]string) { } } -// IsEnvEnabled checks if the devbox environment is enabled. We use the ogPathKey -// as a proxy for this. This allows us to differentiate between global and +// IsEnvEnabled checks if the devbox environment is enabled. +// This allows us to differentiate between global and // individual project shells. func (d *Devbox) IsEnvEnabled() bool { fakeEnv := map[string]string{} diff --git a/internal/impl/packages.go b/internal/impl/packages.go index 9db082fea7d..0bc5bc1e422 100644 --- a/internal/impl/packages.go +++ b/internal/impl/packages.go @@ -108,7 +108,7 @@ func (d *Devbox) Add(ctx context.Context, platforms, excludePlatforms []string, } } - // Resolving here ensures we allow insecure before running ensurePackagesAreInstalled + // Resolving here ensures we allow insecure before running ensureDevboxEnvIsUpToDate // which will call print-dev-env. Resolving does not save the lockfile, we // save at the end when everything has succeeded. if d.allowInsecureAdds { @@ -126,7 +126,7 @@ func (d *Devbox) Add(ctx context.Context, platforms, excludePlatforms []string, } } - if err := d.ensurePackagesAreInstalled(ctx, install); err != nil { + if err := d.ensureDevboxEnvIsUpToDate(ctx, install); err != nil { return usererr.WithUserMessage(err, "There was an error installing nix packages") } @@ -190,28 +190,35 @@ func (d *Devbox) Remove(ctx context.Context, pkgs ...string) error { } // this will clean up the now-extra package from nix profile and the lockfile - if err := d.ensurePackagesAreInstalled(ctx, uninstall); err != nil { + if err := d.ensureDevboxEnvIsUpToDate(ctx, uninstall); err != nil { return err } return d.saveCfg() } -// installMode is an enum for helping with ensurePackagesAreInstalled implementation +// installMode is an enum for helping with ensureDevboxEnvIsUpToDate implementation type installMode string const ( install installMode = "install" uninstall installMode = "uninstall" - ensure installMode = "ensure" + // update is both install new package version and uninstall old package version + update installMode = "update" + ensure installMode = "ensure" ) -// ensurePackagesAreInstalled ensures that the nix profile has the packages specified -// in the config (devbox.json). The `mode` is used for user messaging to explain -// what operations are happening, because this function may take time to execute. -// TODO we should rename this to ensureDevboxEnvironmentIsUpToDate since it does -// much more than ensuring packages are installed. -func (d *Devbox) ensurePackagesAreInstalled(ctx context.Context, mode installMode) error { +// ensureDevboxEnvIsUpToDate ensures: +// 1. Packages are installed, in nix-profile or runx. +// Extraneous packages are removed (references purged, not uninstalled). +// 2. Files for devbox shellenv are generated +// 3. Env-vars for shellenv are computed +// 4. Lockfile is synced +// +// The `mode` is used for: +// 1. Skipping certain operations that may not apply. +// 2. User messaging to explain what operations are happening, because this function may take time to execute. +func (d *Devbox) ensureDevboxEnvIsUpToDate(ctx context.Context, mode installMode) error { defer trace.StartRegion(ctx, "ensurePackages").End() defer debug.FunctionTimer().End() @@ -248,8 +255,10 @@ func (d *Devbox) ensurePackagesAreInstalled(ctx context.Context, mode installMod return err } - // Force print-dev-env cache to be recomputed. - nixEnv, err := d.computeNixEnv(ctx, false /*use cache*/) + // Use the printDevEnvCache if we are adding or removing or updating any package, + // AND we are not in the shellenv-enabled environment of the current devbox-project. + usePrintDevEnvCache := mode != ensure && !d.IsEnvEnabled() + nixEnv, err := d.computeNixEnv(ctx, usePrintDevEnvCache) if err != nil { return err } diff --git a/internal/impl/update.go b/internal/impl/update.go index 9679059b7d8..0dea6adcb35 100644 --- a/internal/impl/update.go +++ b/internal/impl/update.go @@ -62,7 +62,7 @@ func (d *Devbox) Update(ctx context.Context, opts devopt.UpdateOpts) error { } } - if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil { + if err := d.ensureDevboxEnvIsUpToDate(ctx, update); err != nil { return err } From f5ab63d559062b0305dee5acb3888db1457debb3 Mon Sep 17 00:00:00 2001 From: Savil Srivastava <676452+savil@users.noreply.github.com> Date: Fri, 6 Oct 2023 16:59:17 -0700 Subject: [PATCH 2/4] lint fix --- internal/impl/shell_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/impl/shell_test.go b/internal/impl/shell_test.go index 98255ef2b79..6813f4a443a 100644 --- a/internal/impl/shell_test.go +++ b/internal/impl/shell_test.go @@ -17,8 +17,8 @@ import ( "go.jetpack.io/devbox/internal/shellgen" ) -// update overwrites golden files with the new test results. -var update = flag.Bool("update", false, "update the golden files with the test results") +// updateFlag overwrites golden files with the new test results. +var updateFlag = flag.Bool("update", false, "update the golden files with the test results") func TestWriteDevboxShellrc(t *testing.T) { testdirs, err := filepath.Glob("testdata/shellrc/*") @@ -83,7 +83,7 @@ func testWriteDevboxShellrc(t *testing.T, testdirs []string) { // Overwrite the golden file if the -update flag was // set, and then proceed normally. The test should // always pass in this case. - if *update { + if *updateFlag { err = os.WriteFile(test.goldShellrcPath, gotShellrc, 0o666) if err != nil { t.Error("Error updating golden files:", err) From 609f2bc33e64c8ee9e18eb0f075514c11c786ece Mon Sep 17 00:00:00 2001 From: Savil Srivastava <676452+savil@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:59:15 -0700 Subject: [PATCH 3/4] rename back to ensurePackagesAreInstalled --- internal/impl/devbox.go | 8 ++++---- internal/impl/packages.go | 13 +++++++------ internal/impl/update.go | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/internal/impl/devbox.go b/internal/impl/devbox.go index 154a38952a9..a4edbfa3293 100644 --- a/internal/impl/devbox.go +++ b/internal/impl/devbox.go @@ -259,7 +259,7 @@ func (d *Devbox) Install(ctx context.Context) error { ctx, task := trace.NewTask(ctx, "devboxInstall") defer task.End() - return d.ensureDevboxEnvIsUpToDate(ctx, ensure) + return d.ensurePackagesAreInstalled(ctx, ensure) } func (d *Devbox) ListScripts() []string { @@ -477,7 +477,7 @@ func (d *Devbox) GenerateEnvrcFile(ctx context.Context, force bool, envFlags dev } // generate all shell files to ensure we can refer to them in the .envrc script - if err := d.ensureDevboxEnvIsUpToDate(ctx, ensure); err != nil { + if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil { return err } @@ -931,9 +931,9 @@ func (d *Devbox) ensurePackagesAreInstalledAndComputeEnv( ) (map[string]string, error) { defer debug.FunctionTimer().End() - // When ensureDevboxEnvIsUpToDate is called with ensure=true, it always + // When ensurePackagesAreInstalled is called with ensure=true, it always // returns early if the lockfile is up to date. So we don't need to check here - if err := d.ensureDevboxEnvIsUpToDate(ctx, ensure); err != nil { + if err := d.ensurePackagesAreInstalled(ctx, ensure); err != nil { return nil, err } diff --git a/internal/impl/packages.go b/internal/impl/packages.go index 0bc5bc1e422..71823271c32 100644 --- a/internal/impl/packages.go +++ b/internal/impl/packages.go @@ -108,7 +108,7 @@ func (d *Devbox) Add(ctx context.Context, platforms, excludePlatforms []string, } } - // Resolving here ensures we allow insecure before running ensureDevboxEnvIsUpToDate + // Resolving here ensures we allow insecure before running ensurePackagesAreInstalled // which will call print-dev-env. Resolving does not save the lockfile, we // save at the end when everything has succeeded. if d.allowInsecureAdds { @@ -126,7 +126,7 @@ func (d *Devbox) Add(ctx context.Context, platforms, excludePlatforms []string, } } - if err := d.ensureDevboxEnvIsUpToDate(ctx, install); err != nil { + if err := d.ensurePackagesAreInstalled(ctx, install); err != nil { return usererr.WithUserMessage(err, "There was an error installing nix packages") } @@ -190,14 +190,14 @@ func (d *Devbox) Remove(ctx context.Context, pkgs ...string) error { } // this will clean up the now-extra package from nix profile and the lockfile - if err := d.ensureDevboxEnvIsUpToDate(ctx, uninstall); err != nil { + if err := d.ensurePackagesAreInstalled(ctx, uninstall); err != nil { return err } return d.saveCfg() } -// installMode is an enum for helping with ensureDevboxEnvIsUpToDate implementation +// installMode is an enum for helping with ensurePackagesAreInstalled implementation type installMode string const ( @@ -208,7 +208,7 @@ const ( ensure installMode = "ensure" ) -// ensureDevboxEnvIsUpToDate ensures: +// ensurePackagesAreInstalled ensures: // 1. Packages are installed, in nix-profile or runx. // Extraneous packages are removed (references purged, not uninstalled). // 2. Files for devbox shellenv are generated @@ -218,7 +218,8 @@ const ( // The `mode` is used for: // 1. Skipping certain operations that may not apply. // 2. User messaging to explain what operations are happening, because this function may take time to execute. -func (d *Devbox) ensureDevboxEnvIsUpToDate(ctx context.Context, mode installMode) error { +// TODO: Rename method since it does more than just ensure packages are installed. +func (d *Devbox) ensurePackagesAreInstalled(ctx context.Context, mode installMode) error { defer trace.StartRegion(ctx, "ensurePackages").End() defer debug.FunctionTimer().End() diff --git a/internal/impl/update.go b/internal/impl/update.go index 0dea6adcb35..69064e18f97 100644 --- a/internal/impl/update.go +++ b/internal/impl/update.go @@ -62,7 +62,7 @@ func (d *Devbox) Update(ctx context.Context, opts devopt.UpdateOpts) error { } } - if err := d.ensureDevboxEnvIsUpToDate(ctx, update); err != nil { + if err := d.ensurePackagesAreInstalled(ctx, update); err != nil { return err } From da47197088db4e5aebdd93d9e97dec943d750423 Mon Sep 17 00:00:00 2001 From: Savil Srivastava <676452+savil@users.noreply.github.com> Date: Fri, 6 Oct 2023 17:17:24 -0700 Subject: [PATCH 4/4] [perf] in syncPackagesToProfile, only removeExtraItemsFromProfile is mode is not install --- examples/development/go/hello-world/trace.out | Bin 0 -> 46231 bytes internal/impl/packages.go | 13 ++++++++----- trace.out | Bin 0 -> 50363 bytes 3 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 examples/development/go/hello-world/trace.out create mode 100644 trace.out diff --git a/examples/development/go/hello-world/trace.out b/examples/development/go/hello-world/trace.out new file mode 100644 index 0000000000000000000000000000000000000000..508fa304ee2d4eab5f2f2fcf08ffb3f74dd400d9 GIT binary patch literal 46231 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 literal 0 HcmV?d00001 diff --git a/internal/impl/packages.go b/internal/impl/packages.go index 71823271c32..2c204d85f83 100644 --- a/internal/impl/packages.go +++ b/internal/impl/packages.go @@ -301,8 +301,8 @@ func (d *Devbox) profilePath() (string, error) { return absPath, errors.WithStack(os.MkdirAll(filepath.Dir(absPath), 0o755)) } -// syncPackagesToProfile ensures that all packages in devbox.json exist in the nix profile, -// and no more. +// syncPackagesToProfile can ensure that all packages in devbox.json exist in the nix profile, +// and no more. However, it may skip some steps depending on the `mode`. func (d *Devbox) syncPackagesToProfile(ctx context.Context, mode installMode) error { defer debug.FunctionTimer().End() defer trace.StartRegion(ctx, "syncPackagesToProfile").End() @@ -330,9 +330,12 @@ func (d *Devbox) syncPackagesToProfile(ctx context.Context, mode installMode) er } // Second, remove any packages from the nix-profile that are not in the config - itemsToKeep, err := d.removeExtraItemsFromProfile(ctx, profileDir, profileItems, packages) - if err != nil { - return err + itemsToKeep := profileItems + if mode != install { + itemsToKeep, err = d.removeExtraItemsFromProfile(ctx, profileDir, profileItems, packages) + if err != nil { + return err + } } // we are done if mode is uninstall diff --git a/trace.out b/trace.out new file mode 100644 index 0000000000000000000000000000000000000000..a3a65f653f9c6bd0da326092c52c3d3b654f6b56 GIT binary patch literal 50363 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