Skip to content

Commit 01eb3fd

Browse files
authored
[bug-fix] Fix lockfile rewrite (#2007)
## Summary The source of this bug is that when calling `lockfile.Tidy()` we were passing in only top level packages and not including plugin packages as well. This bug was also affecting dev container construction and some edge case plugin template logic. This bug only affects users that are using custom plugins with packages. I renamed `PackageNames` to `AllPackageNames` for clarity. Also removed a redundant function in config package that was no longer needed. ## How was it tested? In other project added golang monorepo plugin and logged to ensure Tidy was not recreating lockfile. Also tested adding go to that project.
1 parent 405bfa9 commit 01eb3fd

File tree

12 files changed

+78
-59
lines changed

12 files changed

+78
-59
lines changed

internal/boxcli/global.go

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ func globalCmd() *cobra.Command {
4949
addCommandAndHideConfigFlag(globalCmd, servicesCmd(persistentPreRunE))
5050
addCommandAndHideConfigFlag(globalCmd, shellEnv)
5151
addCommandAndHideConfigFlag(globalCmd, updateCmd())
52-
53-
// Create list for non-global? Mike: I want it :)
54-
globalCmd.AddCommand(globalListCmd())
52+
addCommandAndHideConfigFlag(globalCmd, listCmd())
5553

5654
return globalCmd
5755
}
@@ -61,33 +59,33 @@ func addCommandAndHideConfigFlag(parent, child *cobra.Command) {
6159
_ = child.Flags().MarkHidden("config")
6260
}
6361

64-
func globalListCmd() *cobra.Command {
65-
return &cobra.Command{
62+
type listCmdFlags struct {
63+
config configFlags
64+
}
65+
66+
func listCmd() *cobra.Command {
67+
flags := listCmdFlags{}
68+
cmd := &cobra.Command{
6669
Use: "list",
6770
Aliases: []string{"ls"},
6871
Short: "List global packages",
6972
PreRunE: ensureNixInstalled,
70-
RunE: listGlobalCmdFunc,
71-
}
72-
}
73-
74-
func listGlobalCmdFunc(cmd *cobra.Command, args []string) error {
75-
path, err := ensureGlobalConfig()
76-
if err != nil {
77-
return errors.WithStack(err)
78-
}
79-
80-
box, err := devbox.Open(&devopt.Opts{
81-
Dir: path,
82-
Stderr: cmd.ErrOrStderr(),
83-
})
84-
if err != nil {
85-
return errors.WithStack(err)
86-
}
87-
for _, p := range box.PackageNames() {
88-
fmt.Fprintf(cmd.OutOrStdout(), "* %s\n", p)
73+
RunE: func(cmd *cobra.Command, args []string) error {
74+
box, err := devbox.Open(&devopt.Opts{
75+
Dir: flags.config.path,
76+
Stderr: cmd.ErrOrStderr(),
77+
})
78+
if err != nil {
79+
return errors.WithStack(err)
80+
}
81+
for _, p := range box.AllPackageNamesIncludingRemovedTriggerPackages() {
82+
fmt.Fprintf(cmd.OutOrStdout(), "* %s\n", p)
83+
}
84+
return nil
85+
},
8986
}
90-
return nil
87+
flags.config.register(cmd)
88+
return cmd
9189
}
9290

9391
var globalConfigPath string

internal/boxcli/midcobra/telemetry.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,6 @@ func getPackagesAndCommitHash(c *cobra.Command) ([]string, string) {
108108
return []string{}, ""
109109
}
110110

111-
return box.Config().PackagesVersionedNames(), box.Config().NixPkgsCommitHash()
111+
return box.AllPackageNamesIncludingRemovedTriggerPackages(),
112+
box.Config().NixPkgsCommitHash()
112113
}

internal/boxcli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func RootCmd() *cobra.Command {
6969
command.AddCommand(initCmd())
7070
command.AddCommand(installCmd())
7171
command.AddCommand(integrateCmd())
72+
command.AddCommand(listCmd())
7273
command.AddCommand(logCmd())
7374
command.AddCommand(removeCmd())
7475
command.AddCommand(runCmd())

internal/devbox/devbox.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ func (d *Devbox) GenerateDevcontainer(ctx context.Context, generateOpts devopt.G
446446
Path: devContainerPath,
447447
RootUser: generateOpts.RootUser,
448448
IsDevcontainer: true,
449-
Pkgs: d.PackageNames(),
449+
Pkgs: d.AllPackageNamesIncludingRemovedTriggerPackages(),
450450
LocalFlakeDirs: d.getLocalFlakesDirs(),
451451
}
452452

@@ -485,7 +485,7 @@ func (d *Devbox) GenerateDockerfile(ctx context.Context, generateOpts devopt.Gen
485485
Path: d.projectDir,
486486
RootUser: generateOpts.RootUser,
487487
IsDevcontainer: false,
488-
Pkgs: d.PackageNames(),
488+
Pkgs: d.AllPackageNamesIncludingRemovedTriggerPackages(),
489489
LocalFlakeDirs: d.getLocalFlakesDirs(),
490490
}
491491

@@ -1039,19 +1039,29 @@ func (d *Devbox) flakeDir() string {
10391039
return filepath.Join(d.projectDir, ".devbox/gen/flake")
10401040
}
10411041

1042-
// ConfigPackageNames returns the package names as defined in devbox.json
1043-
func (d *Devbox) PackageNames() []string {
1044-
// TODO savil: centralize implementation by calling d.configPackages and getting pkg.Raw
1045-
// Skipping for now to avoid propagating the error value.
1046-
return d.cfg.PackagesVersionedNames()
1042+
// AllPackageNamesIncludingRemovedTriggerPackages returns the all package names,
1043+
// including those added by plugins and also those removed by builtins.
1044+
// This has a gross name to differentiate it from AllPackages.
1045+
// Some uses cases for this are the lockfile and devbox list command.
1046+
//
1047+
// TODO: We may want to get rid of this function and have callers
1048+
// build their own list. e.g. Some callers need different representations of
1049+
// flakes (lockfile vs devbox list)
1050+
func (d *Devbox) AllPackageNamesIncludingRemovedTriggerPackages() []string {
1051+
result := []string{}
1052+
for _, p := range d.cfg.Packages(true /*includeRemovedTriggerPackages*/) {
1053+
result = append(result, p.VersionedName())
1054+
}
1055+
return result
10471056
}
10481057

10491058
// AllPackages returns the packages that are defined in devbox.json and
10501059
// recursively added by plugins.
10511060
// NOTE: This will not return packages removed by their plugin with the
10521061
// __remove_trigger_package field.
10531062
func (d *Devbox) AllPackages() []*devpkg.Package {
1054-
return devpkg.PackagesFromConfig(d.cfg.Packages(), d.lockfile)
1063+
packages := d.cfg.Packages(false /*includeRemovedTriggerPackages*/)
1064+
return devpkg.PackagesFromConfig(packages, d.lockfile)
10551065
}
10561066

10571067
func (d *Devbox) TopLevelPackages() []*devpkg.Package {

internal/devbox/flakes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func (d *Devbox) getLocalFlakesDirs() []string {
1414
localFlakeDirs := []string{}
1515

1616
// searching through installed packages to get location of local flakes
17-
for _, pkg := range d.PackageNames() {
17+
for _, pkg := range d.AllPackageNamesIncludingRemovedTriggerPackages() {
1818
// filtering local flakes packages
1919
if strings.HasPrefix(pkg, "path:") {
2020
pkgDirAndName, _ := strings.CutPrefix(pkg, "path:")

internal/devbox/packages.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/samber/lo"
2121
"go.jetpack.io/devbox/internal/devbox/devopt"
2222
"go.jetpack.io/devbox/internal/devconfig"
23+
"go.jetpack.io/devbox/internal/devconfig/configfile"
2324
"go.jetpack.io/devbox/internal/devpkg"
2425
"go.jetpack.io/devbox/internal/devpkg/pkgtype"
2526
"go.jetpack.io/devbox/internal/lock"
@@ -53,7 +54,10 @@ func (d *Devbox) Add(ctx context.Context, pkgsNames []string, opts devopt.AddOpt
5354
// names of added packages (even if they are already in config). We use this
5455
// to know the exact name to mark as allowed insecure later on.
5556
addedPackageNames := []string{}
56-
existingPackageNames := d.PackageNames()
57+
existingPackageNames := lo.Map(
58+
d.cfg.Root.TopLevelPackages(), func(p configfile.Package, _ int) string {
59+
return p.VersionedName()
60+
})
5761
for _, pkg := range pkgs {
5862
// If exact versioned package is already in the config, we can skip the
5963
// next loop that only deals with newPackages.

internal/devconfig/config.go

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,20 @@ func (c *Config) IncludedPluginConfigs() []*plugin.Config {
193193
return configs
194194
}
195195

196-
func (c *Config) Packages() []configfile.Package {
196+
// Returns all packages including those from included plugins.
197+
// If includeRemovedTriggerPackages is true, then trigger packages that have
198+
// been removed will also be returned. These are only used for built-ins
199+
// (e.g. php) when the plugin creates a flake that is meant to replace the
200+
// original package.
201+
func (c *Config) Packages(
202+
includeRemovedTriggerPackages bool,
203+
) []configfile.Package {
197204
packages := []configfile.Package{}
198205
packagesToRemove := map[string]bool{}
199206

200207
for _, i := range c.included {
201-
packages = append(packages, i.Packages()...)
202-
if i.pluginData.RemoveTriggerPackage {
208+
packages = append(packages, i.Packages(includeRemovedTriggerPackages)...)
209+
if i.pluginData.RemoveTriggerPackage && !includeRemovedTriggerPackages {
203210
packagesToRemove[i.pluginData.Source.LockfileKey()] = true
204211
}
205212
}
@@ -219,19 +226,6 @@ func (c *Config) Packages() []configfile.Package {
219226
))
220227
}
221228

222-
// PackagesVersionedNames returns a list of package names with versions.
223-
// NOTE: if the package is unversioned, the version will be omitted (doesn't default to @latest).
224-
//
225-
// example:
226-
// ["package1", "package2@latest", "[email protected]"]
227-
func (c *Config) PackagesVersionedNames() []string {
228-
result := make([]string, 0, len(c.Root.TopLevelPackages()))
229-
for _, p := range c.Root.TopLevelPackages() {
230-
result = append(result, p.VersionedName())
231-
}
232-
return result
233-
}
234-
235229
func (c *Config) NixPkgsCommitHash() string {
236230
return c.Root.NixPkgsCommitHash()
237231
}

internal/lock/interfaces.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ package lock
66
type devboxProject interface {
77
ConfigHash() (string, error)
88
NixPkgsCommitHash() string
9-
PackageNames() []string
9+
AllPackageNamesIncludingRemovedTriggerPackages() []string
1010
ProjectDir() string
1111
}
1212

internal/lock/lockfile.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,10 @@ func IsLegacyPackage(pkg string) bool {
173173
// Tidy ensures that the lockfile has the set of packages corresponding to the devbox.json config.
174174
// It gets rid of older packages that are no longer needed.
175175
func (f *File) Tidy() {
176-
f.Packages = lo.PickByKeys(f.Packages, f.devboxProject.PackageNames())
176+
f.Packages = lo.PickByKeys(
177+
f.Packages,
178+
f.devboxProject.AllPackageNamesIncludingRemovedTriggerPackages(),
179+
)
177180
}
178181

179182
// IsUpToDateAndInstalled returns true if the lockfile is up to date and the

internal/plugin/manager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Manager struct {
1414
}
1515

1616
type devboxProject interface {
17-
PackageNames() []string
17+
AllPackageNamesIncludingRemovedTriggerPackages() []string
1818
ProjectDir() string
1919
}
2020

0 commit comments

Comments
 (0)