Skip to content

[plugins] Allow local non-compiled plugins #1224

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

Merged
merged 10 commits into from
Jul 6, 2023
Merged

Conversation

mikeland73
Copy link
Contributor

@mikeland73 mikeland73 commented Jun 28, 2023

Summary

This change allows users to add their own plugins using devbox.json include field (see example). It now supports all plugin fields (including services).

Fixed: Issue where editing plugin would not be reflected.

How was it tested?

devbox run run_test -c examples/plugins/local
MY_FOO_VAR is set to 'BAR'
devbox services up

@mikeland73 mikeland73 requested review from loreto and Lagoja June 28, 2023 02:25
@mikeland73 mikeland73 requested a review from savil June 29, 2023 19:46
@mikeland73 mikeland73 changed the title [plugins] Prototype that allows local non-compiled plugins [plugins] Allow local non-compiled plugins Jun 29, 2023
@Lagoja
Copy link
Contributor

Lagoja commented Jun 29, 2023

Pretty awesome! Env variables + services seem to be working, and updating when I make changes

I noticed that if I add additional files to add_files in the example, they don't update on subsequent devbox shell runs. Is there something special I need to do for changes to that section of the plugin to have effect?

@mikeland73
Copy link
Contributor Author

@Lagoja right now you need to delete your .devbox/local.lock file to force it to recreate. I'll fix this.

Copy link
Collaborator

@savil savil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome! Any thoughts on the questions below?

],
"scripts": {
"run_test": [
"./test.sh"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! thank you for adding this run_test

Comment on lines +9 to +11
"{{ .Virtenv }}/empty-dir": "",
"{{ .Virtenv }}/some-file": "some-file.txt",
"{{ .Virtenv }}/process-compose.yaml": "process-compose.yaml"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can drop the {{ .Virtenv }}? Why do we need it?

I feel a more natural way for a user to write this is:

"create_files": {
   "empty-dir": "",
   "some-file": "some-file.txt",
 }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify: I fear its easy for the user to make a mistake with the {{ .Virtenv }} format.

If we can help it, it would be nice to enable a genuine json which is not also a go-template.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that having pure json would be nicer, but there are actually 2 different directories (Virtenv and devbox.d) that plugins write to. It would feel a bit weird to default to Virtenv and then require a template for devbox.d.

Are template variables that high a bar?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh I see.

My concern about the template variables is that its a golang-ism that I fear (fairly strongly) will confuse users who are not familiar with golang (which I'd guess is a fair %, especially if devbox gains more users).

If there are strictly two (or a finite set of) options, then how about making that part of the spec. Something like:

"create_files": {
    "virtenv": {
     "empty-dir": "",
     "some-file": "some-file.txt",
   },
   "devbox.d": {
      "process-config": "process-conf.yaml"
   }
 },

Thoughts? In our docs and examples, we can show that virtenv and devbox.d are the only two acceptable keys.

Alternate names for the keys could be:

  • internal and external, so that plugin authors know which files are internal to their plugin, versus externally editable by users.
  • plugin-owned and user-owned.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are quite a few template variables and they provide a pretty large amount of customizability so I would prefer to always allow them (even if we allow shortcuts or syntax sugar).

re: template variables being a golang-ism: this is true, but they are fairly common. (See helm for example).

I think your suggestion of having special keys in create_files is good. My main counter is I would still allow using template variables and custom paths to allow more customizability. And a (better?) possible replacement is https://github.com/jetpack-io/tyson and if we want to do that, we might regret adding special fields to create_files.

Thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, what are the other template-variables? I'm feeling pretty uncomfortable about exposing our internal plugin schema directly for external usage where we'll have to support it indefinitely.

Could we write down a spec. for this plugin's schema, so we can evaluate it independent of the implementation in this PR?

And a (better?) possible replacement is https://github.com/jetpack-io/tyson and if we want to do that, we might regret adding special fields to create_files.

Can you elaborate on this: why would using TySON be harder with a schema that has whitelisted keys for create_files? How is it different from the whitelisted keys at the top-level like version and env?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, what are the other template-variables?

plugins variables are defined here

Created file variables are defined here

I'm feeling pretty uncomfortable about exposing our internal plugin schema directly for external usage where we'll have to support it indefinitely.

Any syntax (template variables or otherwise) we'll have to maintain "forever" (in quotes because nothing is really forever, we can always force people to update). e.g. if you add special create_file fields you are essentially saying you will maintain that forever.

Could we write down a spec.

For expediency, my hope was to use our current variable set and document them as experimental/may change until 1.0.0. We obviously do not want them to change, but it seems hard to guarantee. I'm OK with documenting a subset and saying everything else is private and you should not use.

Can you elaborate on this: why would using TySON be harder with a schema that has whitelisted keys for create_files?

I think you misunderstood me. With TySON (and a simple API for plugins) we no longer need templates or special keys. You could do:

import { virtenvPath } from '@devbox/plugins';

export default {
  name: "foo",
  create_files: {
    [virtenvPath() + "/my-file.txt"]: "my-file.txt",
    [virtenvPath() + "/other.txt"]: "other.txt"
  }
}

Since the ts API is published and versioned, we could make somewhat breaking changes without breaking people's plugins.

}
},
"include": [
"path:my-plugin/my-plugin.json"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regular plugins are specified as:

> {
  "includes": [
    "plugin:nginx"
  ]
}

https://www.jetpack.io/devbox/docs/guides/plugins/#using-plugins

what do you think of an alternative key like:

  • plugin-path:
  • local-plugin:
    or..even just plugin: and if it ends in a .json then we know its a local plugin.

My concern with path is that its a bit ambiguous in terms of "path to what?", and we could someday have includes that are non-plugins...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

path is the standard nix way to refer to local urls for inputs, which is why I used it. My thought was to reuse nix path prefixes:

github:
https:
path:

I would also be OK with dropping path and just allowing relative or absolute paths. So

my/plugin/p.json
https://myplugin.com/p.json
github:user/repo

@Lagoja thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, that makes sense. I also like that we could later have "remote includes" specified as https://acme.com/code/super-tool/tree/main/hammer_plugin.json

🤔 would we ever have non-plugin includes? IIRC there was some talk of having composable devbox.json or other concepts that are "included".

If no, then path sounds great.
if yes, then plugin-path:, plugin-https:, and plugin-github: ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

includes is intended to support devbox.json composability generally and not just plugins. But we need to merge plugin json and devbox.json.

The idea would be that including a plugin or another devbox.json is the same (so no different syntax). This would be a reason to avoid using plugin as part of the protocol.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

includes is intended to support devbox.json composability generally and not just plugins. But we need to merge plugin json and devbox.json.

The idea would be that including a plugin or another devbox.json is the same (so no different syntax). This would be a reason to avoid using plugin as part of the protocol.

I see. That makes sense as a goal.

How do you anticipate distinguishing the current plugin-jsons versus devbox-json style plugin-jsons?

I suppose we can try to json.Unmarshal with current-plugin-schema and if that fails, try unmarshalling with devbox-json-style-plugin-schema.

Okay, no further concerns on this thread.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@savil the schemas are almost identical. It's a matter of union-ing them (and possibly deprecating anything that doesn't make sense).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why regular devbox.json should have create_files...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For maintainability I would prefer to have a single schema, and could imagine good use cases: e.g. you want your devbox.json to create a process compose or config file and don't want to write a separate plugin.

That said, it's not something this PR does, I would prefer to cross that bridge when we get to it.

Comment on lines 44 to 48
name, ok := m["name"].(string)
if !ok || name == "" {
return nil,
usererr.New("plugin %s is missing a required field 'name'", path)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest setting some constraints on allowable names. Maybe:

  1. specify that they must belong to [a-z][A-Z]-
  2. length limit of 32 or 64 characters
    ?

I'd worry that having no constraints would get "creatively" used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Collaborator

@savil savil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking it over, while we could have a stricter and more statically analyzable schema for the config, we'll be using golang templates for the create_files anyway. And it seems unavoidable (without a full rewrite of the plugin manager).

I'm going to approve to unblock, but perhaps lets discuss in meeting tomorrow prior to landing...

@mikeland73 mikeland73 merged commit 6c833de into main Jul 6, 2023
@mikeland73 mikeland73 deleted the landau/local-plugins branch July 6, 2023 18:04
@LucilleH
Copy link
Collaborator

LucilleH commented Jul 6, 2023

Sorry for being late to the party - I like this, and the only thing I'm thinking about is around create_files and how tyson can make this interface much nicer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants