-
Notifications
You must be signed in to change notification settings - Fork 264
[devbox.json] Allowing including plugins explicitly via "include" field. #986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I like the functionality, but I'm unsure of the interface/schema in devbox.json (mainly due to similar concerns to the product questions you are raising). Worth chatting in person to flesh the interface out? |
I lean towards not including this in packages for now. While it might simplify the config, plugins and other
I think we might want to rename the plugin from Happy to chat about this in person to flesh out. |
suggestion: avoid calling it Alternatives: "plugin: php", or "extension: php-plugin". |
Yep, same page. This is precisely why I called them |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have one concern with the implementation on plugin/plugin.go:245
. I think it may be backwards incompatible: it may lead to undesirable overwriting of files for existing devbox-projects. WDYT?
How does a user discover which plugins are available?
- (short term) Could we have a docs page that we reference in the help notes?
- (long term) implement
devbox plugins ls
?
Including plugins works the same way current plugins. Specifically init hooks, and environment get added to existing environment. No new packages are installed.
what is the behavior a user would experience if they have includes: [ plugins: php ]
but no package php
?
internal/impl/config.go
Outdated
// path: for local files | ||
// https:// for remote files | ||
// plugin: for built-in plugins | ||
// This is similar to nix inputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind elaborating on what you mean by "similar to nix inputs": in what way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nix flake inputs are urls of this format (path, https, github, etc) so we are using the same format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, got it. Perhaps "This format is similar to nix inputs"
return err | ||
} | ||
|
||
d.pluginManager.ApplyOptions(plugin.WithAddMode()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when does this get applied now, in the flow for adding a package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I understand this one. The AddMode is replaced with Lockfile.
internal/plugin/plugin.go
Outdated
// Only create devboxDir files in add mode. | ||
if strings.Contains(filePath, devboxDirName) && !m.addMode { | ||
func (m *Manager) shouldCreateFile(pkg *lock.Package, filePath string) bool { | ||
// Only create files in devboxDir is they are not in the lockfile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 for older plugins (i.e. not in the lockfile), this code is re-creating their devbox.d
files.
- I thought users were encouraged to commit them to source-control and possibly change them.
- so, shouldn't we avoid re-generating these files for existing devbox projects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll make sure we don't overwrite them, but yeah this will cause a one time re-creation if they previously deleted/moved them. I think that's on ok tradeoff in order to migrate to a better system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it
Yeah, I was concerned about the overwriting scenario where users may have made changes.
internal/impl/generate.go
Outdated
if err := d.lockfile.Add(includes); err != nil { | ||
return err | ||
} | ||
if err := d.pluginManager.Include(d.writer, includes, d.projectDir); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'll be good for some future PR to make the plugin manager life-cycle more clear.
Suggestion:
pluginManager.New(lockfile)
function that doesapplyOptions
pluginManager.Generate(packages, includes)
- this can do
lockfile.Add(includes)
internally
- this can do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewManager
already applies options. The reason we call it separately is because of a circular dependency (see impl.Open
function)
Agree with unifying Create
and Includes
Not sure about calling lockfile.Add(includes)
internally. That feels like logic that is unrelated to plugins. Insterad, plugins should be saved to lock file and then we can pass in resolved packages directly to plugin manager, which will mean we no longer need the lockfile in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewManager already applies options. The reason we call it separately is because of a circular dependency (see impl.Open function)
Oh I see. I left a comment above about improving that so its easier to reason about.
Not sure about calling lockfile.Add(includes) internally. That feels like logic that is unrelated to plugins. Insterad, plugins should be saved to lock file and then we can pass in resolved packages directly to plugin manager, which will mean we no longer need the lockfile in there.
Yup, you're right. Lets not call lockfile.Add from within pluginManager. 👍🏾
internal/impl/generate.go
Outdated
} | ||
} | ||
|
||
for _, includes := range d.cfg.Include { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: shouldn't this be singular include
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, in addition, I'm being thrown off by d.cfg.Include
being singular....should that be plural?
Relatedly, in the devbox.json
, should the field be includes
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"include" is a verb, not a noun so I think it should be singular (e.g. tsconfig.json also uses "include" and not "includes"). @Lagoja curious if you have opinion.
For the range variable, I'll change it, maybe to included
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh its a verb! I see i see.
Okay, we can leave as is for devbox.json, and yeah I like included
for the range var 👍🏾
internal/impl/config.go
Outdated
// path: for local files | ||
// https:// for remote files | ||
// plugin: for built-in plugins | ||
// This is similar to nix inputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, got it. Perhaps "This format is similar to nix inputs"
internal/impl/generate.go
Outdated
} | ||
} | ||
|
||
for _, includes := range d.cfg.Include { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, in addition, I'm being thrown off by d.cfg.Include
being singular....should that be plural?
Relatedly, in the devbox.json
, should the field be includes
?
if err != nil { | ||
return nil, err | ||
} | ||
box.pluginManager.ApplyOptions(plugin.WithLockfile(lock)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest doing:
- remove
pluginmanager: plugin.NewManager(),
above - make this
box.pluginManager = plugin.NewManager(plugin.WithLockfile(lock))
- make
applyOptions
an internal function,
(3) would make NewManager a more genuine constructor. That would make it easier to reason about that all the pluginManager's fields are ready and methods can be applied.
internal/impl/generate.go
Outdated
if err := d.lockfile.Add(includes); err != nil { | ||
return err | ||
} | ||
if err := d.pluginManager.Include(d.writer, includes, d.projectDir); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewManager already applies options. The reason we call it separately is because of a circular dependency (see impl.Open function)
Oh I see. I left a comment above about improving that so its easier to reason about.
Not sure about calling lockfile.Add(includes) internally. That feels like logic that is unrelated to plugins. Insterad, plugins should be saved to lock file and then we can pass in resolved packages directly to plugin manager, which will mean we no longer need the lockfile in there.
Yup, you're right. Lets not call lockfile.Add from within pluginManager. 👍🏾
internal/plugin/plugin.go
Outdated
// Only create devboxDir files in add mode. | ||
if strings.Contains(filePath, devboxDirName) && !m.addMode { | ||
func (m *Manager) shouldCreateFile(pkg *lock.Package, filePath string) bool { | ||
// Only create files in devboxDir is they are not in the lockfile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it
Yeah, I was concerned about the overwriting scenario where users may have made changes.
Built in plugin functionality is already documented. Plugins are not new, they were just only included by package whereas this allows them to be included explicitly.
Maybe. There's also a world where plugins are as ubiquitous as packages, and most of them are third party. So a search might be more appropriate than an ls.
The service will fail. For other plugins the init hooks will fail. I think this is OK. The |
@savil I confirmed that files in |
Summary
This adds the ability to include plugins explicitly via:
in devbox.json. The idea is to allow including any devbox.json into an existing one. The proposed syntax is:
only plugin is implemented in this PR.
Improved existing plugin mechanism by using
lockfile
to decide isdevbox.d
directory needs to be created by keeping track of the plugin version. In the future we could allow upgrading of configs if there is version mismatch.A few design questions: (cc: @Lagoja @loreto )
packges
instead? We could introspect the include to see if it's a flake or a plugin. This would simplify the devbox.json but it might be a weird way to include other configs.builtin
to something that makes it more explicit that it extends functionality on existing nix packages. Maybeextend:php
. Another option: In the future I expect includes to contain packages which would be installed as well. So could parametrize the php plugin so it can take the top level php package as an input (but otherwise it could install its own)Edit:
After chatting with @loreto and @Lagoja we agreed to keep this design with following:
How was it tested?
In php flake example, did
devbox services up