@@ -13,11 +13,11 @@ import (
13
13
"runtime/trace"
14
14
"strings"
15
15
16
- "github.com/fatih/color"
17
16
"github.com/pkg/errors"
18
17
"github.com/samber/lo"
19
18
"golang.org/x/exp/slices"
20
19
20
+ "go.jetpack.io/devbox/internal/boxcli/usererr"
21
21
"go.jetpack.io/devbox/internal/debug"
22
22
"go.jetpack.io/devbox/internal/lock"
23
23
"go.jetpack.io/devbox/internal/nix"
@@ -29,54 +29,53 @@ import (
29
29
// packages.go has functions for adding, removing and getting info about nix packages
30
30
31
31
// Add adds the `pkgs` to the config (i.e. devbox.json) and nix profile for this devbox project
32
- func (d * Devbox ) Add (ctx context.Context , pkgs ... string ) error {
32
+ func (d * Devbox ) Add (ctx context.Context , pkgsNames ... string ) error {
33
33
ctx , task := trace .NewTask (ctx , "devboxAdd" )
34
34
defer task .End ()
35
35
36
- pkgs = lo .Uniq (pkgs )
36
+ pkgs := nix . InputsFromStrings ( lo .Uniq (pkgsNames ), d . lockfile )
37
37
38
- original := d .cfg .Packages
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 {
43
+ 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 )
51
+ }
52
+ }
53
+ pkgs = versionedPackages
39
54
40
55
// Check packages are valid before adding.
41
56
for _ , pkg := range pkgs {
42
- ok , err := nix . PkgExists ( pkg , d . lockfile )
57
+ ok , err := pkg . ValidateExists ( )
43
58
if err != nil {
44
59
return err
45
60
}
46
61
if ! ok {
47
- return errors .WithMessage (nix .ErrPackageNotFound , pkg )
48
- }
49
- }
50
-
51
- // Add to Packages of the config only if it's not already there
52
- for _ , pkg := range pkgs {
53
- if slices .Contains (d .cfg .Packages , pkg ) {
54
- continue
62
+ return errors .WithMessage (nix .ErrPackageNotFound , pkg .Raw )
55
63
}
56
- d .cfg .Packages = append (d .cfg .Packages , pkg )
57
- }
58
- if err := d .saveCfg (); err != nil {
59
- return err
60
64
}
61
65
62
66
d .pluginManager .ApplyOptions (plugin .WithAddMode ())
63
67
if err := d .ensurePackagesAreInstalled (ctx , install ); err != nil {
64
- // if installation fails, revert devbox.json
65
- // This is not perfect because there may be more than 1 package being
66
- // installed and we don't know which one failed. But it's better than
67
- // blindly add all packages.
68
- color .New (color .FgRed ).Fprintf (
69
- d .writer ,
70
- "There was an error installing nix packages: %v. " +
71
- "Packages were not added to devbox.json\n " ,
72
- strings .Join (pkgs , ", " ),
68
+ return usererr .WithUserMessage (
69
+ err ,
70
+ "There was an error installing nix packages" ,
73
71
)
74
- d .cfg .Packages = original
75
- _ = d .saveCfg () // ignore error to ensure we return the original error
72
+ }
73
+
74
+ if err := d .saveCfg (); err != nil {
76
75
return err
77
76
}
78
77
79
- for _ , input := range nix . InputsFromStrings ( pkgs , d . lockfile ) {
78
+ for _ , input := range pkgs {
80
79
if err := plugin .PrintReadme (
81
80
input ,
82
81
d .projectDir ,
@@ -87,48 +86,58 @@ func (d *Devbox) Add(ctx context.Context, pkgs ...string) error {
87
86
}
88
87
}
89
88
90
- if err := d .lockfile .Add (pkgs ... ); err != nil {
89
+ if err := d .lockfile .Add (
90
+ lo .Map (pkgs , func (pkg * nix.Input , _ int ) string { return pkg .Raw })... ,
91
+ ); err != nil {
91
92
return err
92
93
}
93
94
94
95
return wrapnix .CreateWrappers (ctx , d )
95
96
}
96
97
97
- // Remove removes the `pkgs` from the config (i.e. devbox.json) and nix profile for this devbox project
98
+ // Remove removes the `pkgs` from the config (i.e. devbox.json) and nix profile
99
+ // for this devbox project
98
100
func (d * Devbox ) Remove (ctx context.Context , pkgs ... string ) error {
99
101
ctx , task := trace .NewTask (ctx , "devboxRemove" )
100
102
defer task .End ()
101
103
102
- pkgs = lo .Uniq (pkgs )
104
+ packagesToUninstall := []string {}
105
+ missingPkgs := []string {}
106
+ for _ , pkg := range lo .Uniq (pkgs ) {
107
+ found , _ := d .findPackageByName (pkg )
108
+ if found != "" {
109
+ packagesToUninstall = append (packagesToUninstall , found )
110
+ d .cfg .Packages = lo .Without (d .cfg .Packages , found )
111
+ } else {
112
+ missingPkgs = append (missingPkgs , pkg )
113
+ }
114
+ }
103
115
104
- // First, save which packages are being uninstalled. Do this before we modify d.cfg.RawPackages below.
105
- uninstalledPackages := lo .Intersect (d .cfg .Packages , pkgs )
106
- remainingPkgs , missingPkgs := lo .Difference (d .cfg .Packages , pkgs )
107
116
if len (missingPkgs ) > 0 {
108
117
ux .Fwarning (
109
118
d .writer ,
110
119
"the following packages were not found in your devbox.json: %s\n " ,
111
120
strings .Join (missingPkgs , ", " ),
112
121
)
113
122
}
114
- d . cfg . Packages = remainingPkgs
115
- if err := d . saveCfg ( ); err != nil {
123
+
124
+ if err := plugin . Remove ( d . projectDir , packagesToUninstall ); err != nil {
116
125
return err
117
126
}
118
127
119
- if err := plugin . Remove ( d . projectDir , uninstalledPackages ); err != nil {
128
+ if err := d . removePackagesFromProfile ( ctx , packagesToUninstall ); err != nil {
120
129
return err
121
130
}
122
131
123
- if err := d .removePackagesFromProfile (ctx , uninstalledPackages ); err != nil {
132
+ if err := d .ensurePackagesAreInstalled (ctx , uninstall ); err != nil {
124
133
return err
125
134
}
126
135
127
- if err := d .ensurePackagesAreInstalled ( ctx , uninstall ); err != nil {
136
+ if err := d .lockfile . Remove ( packagesToUninstall ... ); err != nil {
128
137
return err
129
138
}
130
139
131
- if err := d .lockfile . Remove ( uninstalledPackages ... ); err != nil {
140
+ if err := d .saveCfg ( ); err != nil {
132
141
return err
133
142
}
134
143
0 commit comments