-
-
Notifications
You must be signed in to change notification settings - Fork 575
Proposal: Plug-ins v2 and Thin Buffalo Binary #1791
Comments
Nice, that makes a lot of sense! I can see this solving PATH related problems well. |
Here is a crazy idea. Why not have a fat buffalo for development and a thin one for production? Maybe they could be managed with symlinks or a shim shell script. |
Food for thoughts from a humble user of buffalo. On the long run , the success of buffalo will depend in part on those plugins, their number, quality, and how easy they are to maintain. I am not expert in the guts of the Buffalo BIN, but the proposal seems to go in the way of an easier maintenance of plugins; which is great. |
I've written a small POC around this, for those that are interested: https://github.com/markbates/bluffalo /*
This cli package would live in the bluffalo application.
*/
package cli
import (
"context"
"github.com/markbates/bluffalo"
"github.com/markbates/bluffalo/fauxplugs/goth"
"github.com/markbates/bluffalo/fauxplugs/heroku"
"github.com/markbates/bluffalo/fauxplugs/plush"
"github.com/markbates/bluffalo/fauxplugs/pop"
)
// Main is the entry point for the bluffalo application
// this is what will be called by main.go
// It would be used by tools like `bluffalo dev` and
// `bluffalo build`.
func Main(ctx context.Context, args []string) error {
// app := actions.App()
// if err := app.Serve(); err != nil {
// return err
// }
return nil
}
// Bluffalo is the entry point for the `bluffalo` binary.
// It allows for registering plugins to enhance the `bluffalo` binary.
// bluffalo generate -h
// bluffalo generate pop ...
// bluffalo fix
// bluffalo fix plush ...
// bluffalo fix -h
func Bluffalo(ctx context.Context, args []string) error {
b, err := bluffalo.New(ctx)
if err != nil {
return err
}
b.Plugins = append(b.Plugins,
pop.New(),
goth.New(),
heroku.New(),
plush.New(),
)
return b.Main(ctx, args)
} Plugins would implement different interfaces for the different parts of the Buffalo binary that it wants to interact with, such as // Plugin is the most basic interface a plugin can implement.
type Plugin interface {
// Name is the name of the plugin.
// This will also be used for the cli sub-command
// "pop" | "heroku" | "auth" | etc...
Name() string
}
// Fixer is an optional interface a plugin can implement
// to be run with `bluffalo fix`. This should update the application
// to the current version of the plugin.
// The expectation is fixing of only one major revision.
type Fixer interface {
Fix(ctx context.Context, args []string) error
}
// Fixer is an optional interface a plugin can implement
// to be run with `bluffalo fix`
type Generator interface {
Generate(ctx context.Context, args []string) error
} Further interfaces could be added to allow a plugin to provide the templates, for example, during resource generation, while another generates the model portion. Once installed the go install ./cmd/bluffalo
cd coke
bluffalo -h
bluffalo fix -h
bluffalo fix
bluffalo fix pop
bluffalo fix plush
bluffalo generate -h
bluffalo generate goth facebook twitter |
I'd like to suggest a modification to the plugin file format that could really help CI environments and ensure the // <app>/plugins/plugins.go
package main
import _ "github.com/gobuffalo/buffalo/cli"
import _ "github.com/gobuffalo/buffalo-pop"
func main() {
cli.Run()
} The installed Other than that the buffalo tool could still have
Then the buffalo tool could support future versions of Buffalo too. To clarify, in these hypotheticals, the github.com/gobuffalo/buffalo project would have the following packages.
GQLGen uses this technique to a lesser degree, and we've been using Edit: Apparently I wasn't reading the POC comment or the sample project, the version controlled tool looks fantastic. I'm looking forward to this. |
The current plug-in system for Buffalo is slow, error prone, and confusing for many users. This is a proposal for a alternative approach to plug-ins that, hopefully, addresses these issues.
As well as proposing a major revision of plug-ins, this proposal also introduces the concept of a "thin" Buffalo binary.
In this proposal I will use
github.com/gobuffalo/pop
as a library, package, and tool, that some people may not want to use.The Fat Binary
Let's start with the
buffalo
binary. It is a "fat" binary. This means that it contains everything, from the web-server, to the generators, etc... Because of this several problems arise. The first is that this "fat" binary contains a lot of dependencies, regardless of whether the end user will ever use those features.The current binary has a hard dependency on
pop
. Thebuffalo generate resource
command, for example, generatespop
style resources. So if the app in question uses another ORM, or none at all, or if they only generate JSON, then this dependency shouldn't be present.Another problem this "fat" binary presents is that it can often be a version mismatch with the app it is being run against. If the app is
v0.12.x
but the binary isv0.15.0
, then the results of runningbuffalo generate resource
, for example, wouldn't be guaranteed to be consistent.The Plug-in Problem.
Buffalo plugins have a set of rules that must be followed for them to be consider, by Buffalo, as a plugin.
buffalo-<plugin-name>
. For example,buffalo-myplugin
.$BUFFALO_PLUGIN_PATH
$GOPATH/bin
, is tried./plugins
folder of your Buffalo applicationavailable
command that prints a JSON response listing the available commands.When a command is run, such as
buffalo db migrate
, Buffalo will try and find the plug-in (binary) and if found, it will then try and shell out the command ofmigrate
to it.This constant shelling out and searching for executables is error prone, confusing, slow, and again, has similar versioning concerns to that of the
buffalo
binary itself.Thin Binary, Fat Binary
To solve these problems, I suggest the following.
First, we make the
buffalo
binary a "thin" one. We remove anything needed for running inside of an application. For example,buffalo dev
is not required outside of an application, so why is it needed in the binary?The
buffalo
binary should only contain what it needs when running its "outside" duties, such asbuffalo new
.Instead, I propose using a similar approach to
github.com/markbates/grift
.The "thin"
buffalo
binary when a command such asbuffalo db migrate
would [hands wave wildly in the air] compile a "fat" buffalo specifically for the current application, using the versions of Buffalo, and other libraries declared in thego.mod
.The
pop
plugin would be added to the application via a standardimport
.The
buffalo-pop
plugin would register any sub-commands it may have for the new "fat" binary that is built.Other Changes
With these changes the
buffalo-plugins.toml
file will no longer be needed, as well as all of thebuffalo plugin
sub-commands.Sub-commands would be forced under their plug-in's name. So if the
buffalo-pop
plugin is registered with the name"pop"
then thebuffalo db migrate
command would becomebuffalo pop migrate
. Gone, also, would be "wrapping" another command.Interfaces would be used to allow for simplier access points into the plug-in system. For example, we might have interfaces for such things as listing any commands, or implementing a "fix" command for things like
buffalo fix
to hook into.Conclusion
I would love to hear community feedback on this proposal. Also, if there is anyone out there that would want to take lead on such a proposal, please speak up. :)
The text was updated successfully, but these errors were encountered: