Skip to content

Commit 06fd5ff

Browse files
authored
Bring back: derive nix profile changes (#1742) (#1747)
## Summary This reverts #1742 ## How was it tested? cicd should pass
1 parent 4a49a04 commit 06fd5ff

File tree

19 files changed

+454
-273
lines changed

19 files changed

+454
-273
lines changed

.github/workflows/cli-tests.yaml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
- name: Build devbox
6060
run: go build -o dist/devbox ./cmd/devbox
6161
- name: Upload devbox artifact
62-
uses: actions/upload-artifact@v3
62+
uses: actions/upload-artifact@v3
6363
with:
6464
name: devbox-${{ runner.os }}-${{ runner.arch }}
6565
path: ./dist/devbox
@@ -113,7 +113,7 @@ jobs:
113113
run: |
114114
chmod +x ./devbox
115115
sudo mv ./devbox /usr/local/bin/
116-
116+
117117
- run: devbox run lint
118118

119119
test:
@@ -129,9 +129,8 @@ jobs:
129129
run-project-tests: ["project-tests", "project-tests-off"]
130130
# Run tests on:
131131
# 1. the oldest supported nix version (which is 2.9.0? But determinate-systems installer has 2.12.0)
132-
# 2. nix version 2.17.0 which introduces a new code path that minimizes nixpkgs downloads.
133-
# 3. latest nix version
134-
nix-version: ["2.12.0", "2.17.0", "2.19.2"]
132+
# 2. latest nix version
133+
nix-version: ["2.12.0", "2.19.2"]
135134
exclude:
136135
- is-main: "not-main"
137136
os: "${{ inputs.run-mac-tests && 'dummy' || 'macos-latest' }}"
@@ -200,7 +199,7 @@ jobs:
200199
go test -v -timeout $DEVBOX_GOLANG_TEST_TIMEOUT ./...
201200
202201
auto-nix-install: # ensure Devbox installs nix and works properly after installation.
203-
needs: build-devbox
202+
needs: build-devbox
204203
strategy:
205204
matrix:
206205
os: [ubuntu-latest, macos-latest]

internal/devbox/nixprofile.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package devbox
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/samber/lo"
9+
"go.jetpack.io/devbox/internal/nix"
10+
"go.jetpack.io/devbox/internal/nix/nixprofile"
11+
"go.jetpack.io/devbox/internal/ux"
12+
)
13+
14+
// syncNixProfileFromFlake ensures the nix profile has the packages from the buildInputs
15+
// from the devshell of the generated flake.
16+
//
17+
// It also removes any packages from the nix profile that are no longer in the buildInputs.
18+
func (d *Devbox) syncNixProfileFromFlake(ctx context.Context) error {
19+
// Get the computed Devbox environment from the generated flake
20+
env, err := d.computeEnv(ctx, false /*usePrintDevEnvCache*/)
21+
if err != nil {
22+
return err
23+
}
24+
25+
// Get the store-paths of the packages we want installed in the nix profile
26+
wantStorePaths := []string{}
27+
if env["buildInputs"] != "" {
28+
// env["buildInputs"] can be empty string if there are no packages in the project
29+
// if buildInputs is empty, then we don't want wantStorePaths to be an array with a single "" entry
30+
wantStorePaths = strings.Split(env["buildInputs"], " ")
31+
}
32+
33+
profilePath, err := d.profilePath()
34+
if err != nil {
35+
return err
36+
}
37+
38+
// Get the store-paths of the packages currently installed in the nix profile
39+
items, err := nixprofile.ProfileListItems(d.stderr, profilePath)
40+
if err != nil {
41+
return fmt.Errorf("nix profile list: %v", err)
42+
}
43+
gotStorePaths := make([]string, 0, len(items))
44+
for _, item := range items {
45+
gotStorePaths = append(gotStorePaths, item.StorePaths()...)
46+
}
47+
48+
// Diff the store paths and install/remove packages as needed
49+
remove, add := lo.Difference(gotStorePaths, wantStorePaths)
50+
if len(remove) > 0 {
51+
packagesToRemove := make([]string, 0, len(remove))
52+
for _, p := range remove {
53+
storePath := nix.NewStorePathParts(p)
54+
packagesToRemove = append(packagesToRemove, fmt.Sprintf("%s@%s", storePath.Name, storePath.Version))
55+
}
56+
if len(packagesToRemove) == 1 {
57+
ux.Finfo(d.stderr, "Removing %s\n", strings.Join(packagesToRemove, ", "))
58+
} else {
59+
ux.Finfo(d.stderr, "Removing packages: %s\n", strings.Join(packagesToRemove, ", "))
60+
}
61+
62+
if err := nix.ProfileRemove(profilePath, remove...); err != nil {
63+
return err
64+
}
65+
}
66+
if len(add) > 0 {
67+
// We need to install the packages in the nix profile one-by-one because
68+
// we do checks for insecure packages.
69+
// TODO: move the insecure package check here, and do `nix profile install installables...`
70+
// in one command for speed.
71+
for _, addPath := range add {
72+
if err = nix.ProfileInstall(ctx, &nix.ProfileInstallArgs{
73+
Installable: addPath,
74+
// Install in offline mode for speed. We know we should have all the files
75+
// locally in /nix/store since we have run `nix print-dev-env` prior to this.
76+
// Also avoids some "substituter not found for store-path" errors.
77+
Offline: true,
78+
ProfilePath: profilePath,
79+
Writer: d.stderr,
80+
}); err != nil {
81+
return fmt.Errorf("error installing package in nix profile %s: %w", addPath, err)
82+
}
83+
}
84+
}
85+
return nil
86+
}

0 commit comments

Comments
 (0)