Skip to content

Commit 0e0dae3

Browse files
authored
[versioned] If user adds new version, remove previous versions of canonical (#1105)
## Summary If there's an existing package with same canonical, remove it. If there's more than one do nothing. ## How was it tested? Need to test this a bit more to ensure no weird side-effects of doing a `remove` inside an `add` On this repo did: ```bash cat devbox.json devbox add [email protected] cat devbox.json devbox add [email protected] cat devbox.json ```
1 parent 9098282 commit 0e0dae3

File tree

4 files changed

+74
-21
lines changed

4 files changed

+74
-21
lines changed

internal/impl/packages.go

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,39 @@ import (
2626
"go.jetpack.io/devbox/internal/wrapnix"
2727
)
2828

29-
// packages.go has functions for adding, removing and getting info about nix packages
29+
// packages.go has functions for adding, removing and getting info about nix
30+
// packages
3031

31-
// Add adds the `pkgs` to the config (i.e. devbox.json) and nix profile for this devbox project
32+
// Add adds the `pkgs` to the config (i.e. devbox.json) and nix profile for this
33+
// devbox project
3234
func (d *Devbox) Add(ctx context.Context, pkgsNames ...string) error {
3335
ctx, task := trace.NewTask(ctx, "devboxAdd")
3436
defer task.End()
3537

36-
pkgs := nix.InputsFromStrings(lo.Uniq(pkgsNames), d.lockfile)
37-
38-
versionedPackages := []*nix.Input{}
39-
// Add to Packages of the config only if it's not already there. We do this
40-
// before addin @latest to ensure we don't accidentally add a package that
41-
// is already in the config.
42-
for _, pkg := range pkgs {
38+
// Only add packages that are not already in config. If same canonical exists,
39+
// replace it.
40+
pkgs := []*nix.Input{}
41+
for _, pkg := range nix.InputsFromStrings(lo.Uniq(pkgsNames), d.lockfile) {
4342
versioned := pkg.Versioned()
44-
versionedPackages = append(
45-
versionedPackages,
46-
nix.InputFromString(versioned, d.lockfile),
47-
)
48-
// Only add if the package doesn't exist versioned or unversioned.
49-
if !slices.Contains(d.cfg.Packages, pkg.Raw) && !slices.Contains(d.cfg.Packages, versioned) {
50-
d.cfg.Packages = append(d.cfg.Packages, versioned)
43+
44+
// If exact versioned package is already in the config, skip.
45+
if slices.Contains(d.cfg.Packages, versioned) {
46+
continue
5147
}
48+
49+
// On the other hand, if there's a package with same canonical name, replace
50+
// it. Ignore error (which is either missing or more than one). We search by
51+
// CanonicalName so any legacy or versioned packages will be removed if they
52+
// match.
53+
if name, _ := d.findPackageByName(pkg.CanonicalName()); name != "" {
54+
if err := d.Remove(ctx, name); err != nil {
55+
return err
56+
}
57+
}
58+
59+
pkgs = append(pkgs, nix.InputFromString(versioned, d.lockfile))
60+
d.cfg.Packages = append(d.cfg.Packages, versioned)
5261
}
53-
pkgs = versionedPackages
5462

5563
// Check packages are valid before adding.
5664
for _, pkg := range pkgs {

testscripts/add/add_replace.test.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Testscript for exercising adding packages
2+
3+
exec devbox init
4+
5+
exec devbox add [email protected]
6+
devboxjson.packages.contains devbox.json [email protected]
7+
! devboxjson.packages.contains devbox.json [email protected]
8+
9+
exec devbox add [email protected]
10+
! devboxjson.packages.contains devbox.json [email protected]
11+
devboxjson.packages.contains devbox.json [email protected]
12+
13+
-- devbox.json --
14+
{
15+
"packages": [
16+
17+
]
18+
}

testscripts/testrunner/assert.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/rogpeppe/go-internal/testscript"
1010

11+
"go.jetpack.io/devbox/internal/devconfig"
1112
"go.jetpack.io/devbox/internal/envir"
1213
)
1314

@@ -33,6 +34,31 @@ func assertPathLength(script *testscript.TestScript, neg bool, args []string) {
3334
}
3435
}
3536

37+
func assertDevboxJSONPackagesContains(script *testscript.TestScript, neg bool, args []string) {
38+
if len(args) != 2 {
39+
script.Fatalf("usage: json.list.contains list.json value")
40+
}
41+
42+
data := script.ReadFile(args[0])
43+
list := devconfig.Config{}
44+
err := json.Unmarshal([]byte(data), &list)
45+
script.Check(err)
46+
47+
expected := args[1]
48+
for _, actual := range list.Packages {
49+
if actual == expected {
50+
if neg {
51+
script.Fatalf("value '%s' found in '%s'", expected, list.Packages)
52+
}
53+
return
54+
}
55+
}
56+
57+
if !neg {
58+
script.Fatalf("value '%s' not found in '%s'", expected, list.Packages)
59+
}
60+
}
61+
3662
// Usage: json.superset superset.json subset.json
3763
// Checks that the JSON in superset.json contains all the keys and values
3864
// present in subset.json.

testscripts/testrunner/testrunner.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ func getTestscriptParams(t *testing.T, dir string) testscript.Params {
7474
TestWork: false, // Set to true if you're trying to debug a test.
7575
Setup: func(env *testscript.Env) error { return setupTestEnv(t, env) },
7676
Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
77-
"env.path.len": assertPathLength,
78-
"json.superset": assertJSONSuperset,
79-
"path.order": assertPathOrder,
80-
"source.path": sourcePath,
77+
"env.path.len": assertPathLength,
78+
"devboxjson.packages.contains": assertDevboxJSONPackagesContains,
79+
"json.superset": assertJSONSuperset,
80+
"path.order": assertPathOrder,
81+
"source.path": sourcePath,
8182
},
8283
}
8384
}

0 commit comments

Comments
 (0)