MCPcopy Index your code
hub / github.com/jetify-com/devbox / Add

Method Add

internal/devbox/packages.go:85–174  ·  view source on GitHub ↗

Add adds the `pkgs` to the config (i.e. devbox.json) and nix profile for this devbox project

(ctx context.Context, pkgsNames []string, opts devopt.AddOpts)

Source from the content-addressed store, hash-verified

83// Add adds the `pkgs` to the config (i.e. devbox.json) and nix profile for this
84// devbox project
85func (d *Devbox) Add(ctx context.Context, pkgsNames []string, opts devopt.AddOpts) error {
86 ctx, task := trace.NewTask(ctx, "devboxAdd")
87 defer task.End()
88
89 // Track which packages had no changes so we can report that to the user.
90 unchangedPackageNames := []string{}
91
92 // Only add packages that are not already in config. If same canonical exists,
93 // replace it.
94 pkgs := devpkg.PackagesFromStringsWithOptions(lo.Uniq(pkgsNames), d.lockfile, opts)
95
96 // addedPackageNames keeps track of the possibly transformed (versioned)
97 // names of added packages (even if they are already in config). We use this
98 // to know the exact name to mark as allowed insecure later on.
99 addedPackageNames := []string{}
100 existingPackageNames := lo.Map(
101 d.cfg.Root.TopLevelPackages(), func(p configfile.Package, _ int) string {
102 return p.VersionedName()
103 })
104 for _, pkg := range pkgs {
105 // If exact versioned package is already in the config, we can skip the
106 // next loop that only deals with newPackages.
107 if slices.Contains(existingPackageNames, pkg.Versioned()) {
108 // But we still need to add to addedPackageNames. See its comment.
109 addedPackageNames = append(addedPackageNames, pkg.Versioned())
110 unchangedPackageNames = append(unchangedPackageNames, pkg.Versioned())
111 ux.Finfof(d.stderr, "Package %q already in devbox.json\n", pkg.Versioned())
112 continue
113 }
114
115 // On the other hand, if there's a package with same canonical name, replace
116 // it. Ignore error (which is either missing or more than one). We search by
117 // CanonicalName so any legacy or versioned packages will be removed if they
118 // match.
119 found, _ := d.findPackageByName(pkg.CanonicalName())
120 if found != nil {
121 ux.Finfof(d.stderr, "Replacing package %q in devbox.json\n", found.Raw)
122 if err := d.Remove(ctx, found.Raw); err != nil {
123 return err
124 }
125 }
126
127 // validate that the versioned package exists in the search endpoint.
128 // if not, fallback to legacy vanilla nix.
129 versionedPkg := devpkg.PackageFromStringWithOptions(pkg.Versioned(), d.lockfile, opts)
130
131 packageNameForConfig := pkg.Raw
132 ok, err := versionedPkg.ValidateExists(ctx)
133 if (err == nil && ok) || errors.Is(err, devpkg.ErrCannotBuildPackageOnSystem) {
134 // Only use versioned if it exists in search. We can disregard the error
135 // about not building on the current system, since user's can continue
136 // via --exclude-platform flag.
137 packageNameForConfig = pkg.Versioned()
138 } else if !versionedPkg.IsDevboxPackage {
139 // This means it didn't validate and we don't want to fallback to legacy
140 // Just propagate the error.
141 return err
142 } else {

Callers 2

UpdateMethod · 0.95
initDevboxUtilityProjectFunction · 0.45

Calls 15

findPackageByNameMethod · 0.95
RemoveMethod · 0.95
StringMethod · 0.95
setPackageOptionsMethod · 0.95
ensureStateIsUpToDateMethod · 0.95
saveCfgMethod · 0.95
printPostAddMessageMethod · 0.95
FinfofFunction · 0.92
SearchFunction · 0.92
NewFunction · 0.92

Tested by

no test coverage detected