Skip to content

Commit 347f65b

Browse files
authored
[plugins] Implement --disable-plugin flag (#1666)
## Summary This adds a new `--disable-plugin` flag to `devbox add`. It also adds a new `disable_plugin` field to the package object in the config. If this field is true packages with built in plugins will not install the plugin. If the package does not trigger a plugin, the field is ignored. The field can be added via flag or manually. It can be removed manually or by running `devbox add <pkg>` again without the flag. Other fixes/improvements: * Moved allowInsecure to `AddOpts` instead of devbox general options. * Refactored Add() so it no longer violates the linter complexity rule. Fixes: #1615 cc: @Lagoja ## How was it tested? * Unit tests * `devbox add python --disable-plugin`
1 parent a45f27d commit 347f65b

File tree

20 files changed

+252
-93
lines changed

20 files changed

+252
-93
lines changed

devbox.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
// Devbox provides an isolated development environment.
1818
type Devbox interface {
19-
Add(ctx context.Context, platforms, excludePlatforms []string, pkgs ...string) error
19+
Add(ctx context.Context, pkgs []string, opts devopt.AddOpts) error
2020
Config() *devconfig.Config
2121
EnvVars(ctx context.Context) ([]string, error)
2222
Info(ctx context.Context, pkg string, markdown bool) (string, error)

devbox.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
2-
"packages": [
3-
"go@latest",
4-
"runx:golangci/golangci-lint@latest",
5-
"runx:mvdan/gofumpt@latest"
6-
],
2+
"packages": {
3+
"go": "latest",
4+
"runx:golangci/golangci-lint": "latest",
5+
"runx:mvdan/gofumpt": "latest"
6+
},
77
"env": {
88
"GOENV": "off",
99
"PATH": "$PATH:$PWD/dist"

internal/boxcli/add.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const toSearchForPackages = "To search for packages, use the `devbox search` com
2020
type addCmdFlags struct {
2121
config configFlags
2222
allowInsecure bool
23+
disablePlugin bool
2324
platforms []string
2425
excludePlatforms []string
2526
}
@@ -53,6 +54,9 @@ func addCmd() *cobra.Command {
5354
command.Flags().BoolVar(
5455
&flags.allowInsecure, "allow-insecure", false,
5556
"allow adding packages marked as insecure.")
57+
command.Flags().BoolVar(
58+
&flags.disablePlugin, "disable-plugin", false,
59+
"disable plugin (if any) for this package.")
5660
command.Flags().StringSliceVarP(
5761
&flags.platforms, "platform", "p", []string{},
5862
"add packages to run on only this platform.")
@@ -65,13 +69,17 @@ func addCmd() *cobra.Command {
6569

6670
func addCmdFunc(cmd *cobra.Command, args []string, flags addCmdFlags) error {
6771
box, err := devbox.Open(&devopt.Opts{
68-
Dir: flags.config.path,
69-
Stderr: cmd.ErrOrStderr(),
70-
AllowInsecureAdds: flags.allowInsecure,
72+
Dir: flags.config.path,
73+
Stderr: cmd.ErrOrStderr(),
7174
})
7275
if err != nil {
7376
return errors.WithStack(err)
7477
}
7578

76-
return box.Add(cmd.Context(), flags.platforms, flags.excludePlatforms, args...)
79+
return box.Add(cmd.Context(), args, devopt.AddOpts{
80+
AllowInsecure: flags.allowInsecure,
81+
DisablePlugin: flags.disablePlugin,
82+
Platforms: flags.platforms,
83+
ExcludePlatforms: flags.excludePlatforms,
84+
})
7785
}

internal/devconfig/ast.go

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,25 +170,37 @@ func (c *configAST) removePackageElement(arr *hujson.Array, name string) {
170170
arr.Elements = slices.Delete(arr.Elements, i, i+1)
171171
}
172172

173-
// appendPlatforms appends a platform to a package's "platforms" or
174-
// "excluded_platforms" field. It automatically converts the package to an
175-
// object if it isn't already.
173+
// setPackageBool sets a bool field on a package.
174+
func (c *configAST) setPackageBool(name, fieldName string, val bool) {
175+
pkgObject := c.FindPkgObject(name)
176+
if pkgObject == nil {
177+
return
178+
}
179+
if i := c.memberIndex(pkgObject, fieldName); i == -1 {
180+
pkgObject.Members = append(pkgObject.Members, hujson.ObjectMember{
181+
Name: hujson.Value{
182+
Value: hujson.String(fieldName),
183+
BeforeExtra: []byte{'\n'},
184+
},
185+
Value: hujson.Value{Value: hujson.Bool(val)},
186+
})
187+
} else {
188+
pkgObject.Members[i].Value.Value = hujson.Bool(val)
189+
}
190+
191+
c.root.Format()
192+
}
193+
176194
func (c *configAST) appendPlatforms(name, fieldName string, platforms []string) {
177195
if len(platforms) == 0 {
178196
return
179197
}
180198

181-
pkgs := c.packagesField(true).Value.Value.(*hujson.Object)
182-
i := c.memberIndex(pkgs, name)
183-
if i == -1 {
199+
pkgObject := c.FindPkgObject(name)
200+
if pkgObject == nil {
184201
return
185202
}
186203

187-
// We need to ensure that the package value is a full object
188-
// (not a version string) before we can add a platform.
189-
c.convertVersionToObject(&pkgs.Members[i].Value)
190-
191-
pkgObject := pkgs.Members[i].Value.Value.(*hujson.Object)
192204
var arr *hujson.Array
193205
if i := c.memberIndex(pkgObject, fieldName); i == -1 {
194206
arr = &hujson.Array{
@@ -212,6 +224,21 @@ func (c *configAST) appendPlatforms(name, fieldName string, platforms []string)
212224
c.root.Format()
213225
}
214226

227+
func (c *configAST) FindPkgObject(name string) *hujson.Object {
228+
pkgs := c.packagesField(true).Value.Value.(*hujson.Object)
229+
i := c.memberIndex(pkgs, name)
230+
if i == -1 {
231+
return nil
232+
}
233+
234+
// We need to ensure that the package value is a full object
235+
// (not a version string) before we can set a custom field on it.
236+
c.convertVersionToObject(&pkgs.Members[i].Value)
237+
238+
pkgObject := pkgs.Members[i].Value.Value.(*hujson.Object)
239+
return pkgObject
240+
}
241+
215242
// migratePackagesArray migrates a legacy array of package versionedNames to an
216243
// object. See packagesField for details.
217244
func (c *configAST) migratePackagesArray(pkgs *hujson.Value) {

internal/devconfig/packages.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,19 @@ func (pkgs *Packages) UnmarshalJSON(data []byte) error {
177177
return nil
178178
}
179179

180+
func (pkgs *Packages) DisablePlugin(versionedName string, v bool) error {
181+
name, version := parseVersionedName(versionedName)
182+
i := pkgs.index(name, version)
183+
if i == -1 {
184+
return errors.Errorf("package %s not found", versionedName)
185+
}
186+
if pkgs.Collection[i].DisablePlugin != v {
187+
pkgs.Collection[i].DisablePlugin = v
188+
pkgs.ast.setPackageBool(name, "disable_plugin", v)
189+
}
190+
return nil
191+
}
192+
180193
func (pkgs *Packages) index(name, version string) int {
181194
return slices.IndexFunc(pkgs.Collection, func(p Package) bool {
182195
return p.name == name && p.Version == version
@@ -187,6 +200,7 @@ type Package struct {
187200
name string
188201
Version string `json:"version,omitempty"`
189202

203+
DisablePlugin bool `json:"disable_plugin,omitempty"`
190204
Platforms []string `json:"platforms,omitempty"`
191205
ExcludedPlatforms []string `json:"excluded_platforms,omitempty"`
192206

internal/devpkg/package.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"go.jetpack.io/devbox/internal/cuecfg"
2121
"go.jetpack.io/devbox/internal/devconfig"
2222
"go.jetpack.io/devbox/internal/devpkg/pkgtype"
23+
"go.jetpack.io/devbox/internal/impl/devopt"
2324
"go.jetpack.io/devbox/internal/lock"
2425
"go.jetpack.io/devbox/internal/nix"
2526
"go.jetpack.io/devbox/plugins"
@@ -33,6 +34,10 @@ type Package struct {
3334
lockfile lock.Locker
3435
IsDevboxPackage bool
3536

37+
// If package triggers a built-in plugin, setting this to true will disable it.
38+
// If package does not trigger plugin, this will have no effect.
39+
DisablePlugin bool
40+
3641
// installable is the flake attribute that the package resolves to.
3742
// When it gets set depends on the original package string:
3843
//
@@ -85,12 +90,21 @@ type Package struct {
8590
normalizedPackageAttributePathCache string // memoized value from normalizedPackageAttributePath()
8691
}
8792

88-
// PackageFromStrings constructs Package from the list of package names provided.
93+
// PackagesFromStringsWithDefaults constructs Package from the list of package names provided.
8994
// These names correspond to devbox packages from the devbox.json config.
90-
func PackageFromStrings(rawNames []string, l lock.Locker) []*Package {
95+
func PackagesFromStringsWithDefaults(rawNames []string, l lock.Locker) []*Package {
9196
packages := []*Package{}
9297
for _, rawName := range rawNames {
93-
packages = append(packages, PackageFromString(rawName, l))
98+
pkg := PackageFromStringWithDefaults(rawName, l)
99+
packages = append(packages, pkg)
100+
}
101+
return packages
102+
}
103+
104+
func PackagesFromStringsWithOptions(rawNames []string, l lock.Locker, opts devopt.AddOpts) []*Package {
105+
packages := []*Package{}
106+
for _, name := range rawNames {
107+
packages = append(packages, PackageFromStringWithOptions(name, l, opts))
94108
}
95109
return packages
96110
}
@@ -99,19 +113,24 @@ func PackagesFromConfig(config *devconfig.Config, l lock.Locker) []*Package {
99113
result := []*Package{}
100114
for _, cfgPkg := range config.Packages.Collection {
101115
pkg := newPackage(cfgPkg.VersionedName(), cfgPkg.IsEnabledOnPlatform(), l)
116+
pkg.DisablePlugin = cfgPkg.DisablePlugin
102117
pkg.PatchGlibc = cfgPkg.PatchGlibc
103118
result = append(result, pkg)
104119
}
105120
return result
106121
}
107122

108-
// PackageFromString constructs Package from the raw name provided.
109-
// The raw name corresponds to a devbox package from the devbox.json config.
110-
func PackageFromString(raw string, locker lock.Locker) *Package {
111-
// Packages are installable by default.
123+
func PackageFromStringWithDefaults(raw string, locker lock.Locker) *Package {
112124
return newPackage(raw, true /*isInstallable*/, locker)
113125
}
114126

127+
func PackageFromStringWithOptions(raw string, locker lock.Locker, opts devopt.AddOpts) *Package {
128+
pkg := PackageFromStringWithDefaults(raw, locker)
129+
pkg.DisablePlugin = opts.DisablePlugin
130+
// TODO: add patchGlibc flag
131+
return pkg
132+
}
133+
115134
func newPackage(raw string, isInstallable bool, locker lock.Locker) *Package {
116135
pkg := &Package{
117136
Raw: raw,

internal/devpkg/package_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func (l *lockfile) Resolve(pkg string) (*lock.Package, error) {
134134
}
135135

136136
func testInputFromString(s, projectDir string) *testInput {
137-
return lo.ToPtr(testInput{Package: PackageFromString(s, &lockfile{projectDir})})
137+
return lo.ToPtr(testInput{Package: PackageFromStringWithDefaults(s, &lockfile{projectDir})})
138138
}
139139

140140
func TestHashFromNixPkgsURL(t *testing.T) {
@@ -241,7 +241,7 @@ func TestCanonicalName(t *testing.T) {
241241

242242
for _, tt := range tests {
243243
t.Run(tt.pkgName, func(t *testing.T) {
244-
pkg := PackageFromString(tt.pkgName, &lockfile{})
244+
pkg := PackageFromStringWithDefaults(tt.pkgName, &lockfile{})
245245
got := pkg.CanonicalName()
246246
if got != tt.expectedName {
247247
t.Errorf("Expected canonical name %q, but got %q", tt.expectedName, got)

internal/impl/devbox.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ type Devbox struct {
6464
pluginManager *plugin.Manager
6565
preservePathStack bool
6666
pure bool
67-
allowInsecureAdds bool
6867
customProcessComposeFile string
6968

7069
// This is needed because of the --quiet flag.
@@ -94,7 +93,6 @@ func Open(opts *devopt.Opts) (*Devbox, error) {
9493
preservePathStack: opts.PreservePathStack,
9594
pure: opts.Pure,
9695
customProcessComposeFile: opts.CustomProcessComposeFile,
97-
allowInsecureAdds: opts.AllowInsecureAdds,
9896
}
9997

10098
lock, err := lock.GetFile(box)
@@ -103,7 +101,7 @@ func Open(opts *devopt.Opts) (*Devbox, error) {
103101
}
104102
// if lockfile has any allow insecure, we need to set the env var to ensure
105103
// all nix commands work.
106-
if opts.AllowInsecureAdds || lock.HasAllowInsecurePackages() {
104+
if lock.HasAllowInsecurePackages() {
107105
nix.AllowInsecurePackages()
108106
}
109107
box.pluginManager.ApplyOptions(
@@ -357,7 +355,7 @@ func (d *Devbox) Info(ctx context.Context, pkg string, markdown bool) (string, e
357355
)
358356
readme, err := plugin.Readme(
359357
ctx,
360-
devpkg.PackageFromString(pkg, d.lockfile),
358+
devpkg.PackageFromStringWithDefaults(pkg, d.lockfile),
361359
d.projectDir,
362360
markdown,
363361
)

internal/impl/devopt/devboxopts.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
)
66

77
type Opts struct {
8-
AllowInsecureAdds bool
98
Dir string
109
Env map[string]string
1110
PreservePathStack bool
@@ -38,6 +37,13 @@ type Credentials struct {
3837
Sub string
3938
}
4039

40+
type AddOpts struct {
41+
AllowInsecure bool
42+
Platforms []string
43+
ExcludePlatforms []string
44+
DisablePlugin bool
45+
}
46+
4147
type UpdateOpts struct {
4248
Pkgs []string
4349
IgnoreMissingPackages bool

0 commit comments

Comments
 (0)