feat(build): mark scaffolded files with //summer:make and pass the app to generated commands (quick-261028-pq8)
- model, migration, command, job and admin-controller stubs start with //summer:make <kind>; registry.gen.go keeps its generated-code header - the registry scan accepts the directive and the older header - command functions may take one *backpack.App; generatedCommands takes a variadic app, so plugin.go files calling generatedCommands() still compile - scaffolded plugins keep the app from Boot and return generatedCommands(p.app) - make:command notes the nil app for an older plugin.go - docs, help text and the blog example follow
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
@@ -192,7 +193,33 @@ func MakeCommand(ctx context.Context, startDir, pluginID, name string) (Artifact
|
||||
os.Remove(path)
|
||||
return ArtifactResult{}, err
|
||||
}
|
||||
return ArtifactResult{PluginDir: plugin.Dir, Files: []string{path}, Hint: plugin.Hint}, nil
|
||||
hint := plugin.Hint
|
||||
if note := nilAppCommandHint(filepath.Join(plugin.Dir, "plugin.go"), fn); note != "" {
|
||||
hint = joinHints(hint, note)
|
||||
}
|
||||
return ArtifactResult{PluginDir: plugin.Dir, Files: []string{path}, Hint: hint}, nil
|
||||
}
|
||||
|
||||
// zeroArgGeneratedCommands matches a generatedCommands call without
|
||||
// arguments, the form plugin.go had before commands took the app.
|
||||
var zeroArgGeneratedCommands = regexp.MustCompile(`generatedCommands\(\s*\)`)
|
||||
|
||||
// nilAppCommandHint explains, for a plugin.go that calls generatedCommands()
|
||||
// without the app, that the command fn receives a nil *backpack.App.
|
||||
func nilAppCommandHint(pluginGoPath, fn string) string {
|
||||
body, err := os.ReadFile(pluginGoPath)
|
||||
if err != nil || !zeroArgGeneratedCommands.Match(body) {
|
||||
return ""
|
||||
}
|
||||
return "note: console." + fn + " receives a nil *backpack.App because plugin.go calls generatedCommands() without the app; " +
|
||||
"keep the app in Boot (p.app = app) and return generatedCommands(p.app) from Commands"
|
||||
}
|
||||
|
||||
func joinHints(a, b string) string {
|
||||
if a == "" {
|
||||
return b
|
||||
}
|
||||
return a + "\n" + b
|
||||
}
|
||||
|
||||
// MakeJob writes a typed job wrapped in conga.Job; the plugin never
|
||||
|
||||
@@ -489,7 +489,8 @@ func TestScaffoldPluginSmoke(t *testing.T) {
|
||||
for _, want := range []string{
|
||||
"generatedModels()",
|
||||
"generatedMigrations()",
|
||||
"generatedCommands()",
|
||||
"generatedCommands(p.app)",
|
||||
"p.app = app",
|
||||
"generatedJobs()",
|
||||
"generatedAdminControllers()",
|
||||
"//go:embed config",
|
||||
@@ -503,7 +504,7 @@ func TestScaffoldPluginSmoke(t *testing.T) {
|
||||
for _, want := range []string{
|
||||
"func generatedModels()",
|
||||
"func generatedMigrations()",
|
||||
"func generatedCommands()",
|
||||
"func generatedCommands(app ...*backpack.App) []bonfire.Command",
|
||||
"func generatedJobs()",
|
||||
"func generatedAdminControllers()",
|
||||
} {
|
||||
@@ -655,7 +656,7 @@ func TestScaffoldCoreArtifacts(t *testing.T) {
|
||||
"&models.Widget{}",
|
||||
"updates.CreateAlbums()",
|
||||
"updates.AddWidgetIndex()",
|
||||
"console.PurgeCommand()",
|
||||
"console.PurgeCommand(bootApp)",
|
||||
} {
|
||||
if !bytes.Contains(reg1, []byte(want)) {
|
||||
t.Fatalf("registry.gen.go missing %s:\n%s", want, reg1)
|
||||
@@ -794,6 +795,22 @@ func TestScaffoldAllArtifacts(t *testing.T) {
|
||||
if len(command.Files) != 1 || command.Files[0] != wantCommand {
|
||||
t.Fatalf("make:command files = %v, want %s", command.Files, wantCommand)
|
||||
}
|
||||
if command.Hint != "" {
|
||||
t.Fatalf("new plugin printed a make:command hint: %s", command.Hint)
|
||||
}
|
||||
cmdSrc, err := os.ReadFile(wantCommand)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Contains(cmdSrc, []byte("func PurgeCommand(app *backpack.App) bonfire.Command")) {
|
||||
t.Fatalf("purge.go does not take the app:\n%s", cmdSrc)
|
||||
}
|
||||
// Report whether the app arrived, so the built binary proves the wiring.
|
||||
reported := bytes.Replace(cmdSrc, []byte(`out.Printf("demo:purge" + "\n")`), []byte(`out.Printf("demo:purge app=%t\n", app != nil)`), 1)
|
||||
if bytes.Equal(reported, cmdSrc) {
|
||||
t.Fatalf("could not patch purge.go:\n%s", cmdSrc)
|
||||
}
|
||||
write(t, wantCommand, string(reported))
|
||||
|
||||
job, err := MakeJob(ctx, dir, "golem15.demo", "Reindex")
|
||||
if err != nil {
|
||||
@@ -877,16 +894,38 @@ func TestScaffoldAllArtifacts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
for path, kind := range map[string]string{
|
||||
wantModel: "model",
|
||||
model.Files[1]: "migration",
|
||||
wantCommand: "command",
|
||||
wantJob: "job",
|
||||
wantAdmin[0]: "admin-controller",
|
||||
} {
|
||||
body, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want := "//summer:make " + kind + "\n\npackage "; !bytes.HasPrefix(body, []byte(want)) {
|
||||
t.Fatalf("%s does not start with %q:\n%s", path, want, body)
|
||||
}
|
||||
if bytes.Contains(body, []byte("DO NOT EDIT")) {
|
||||
t.Fatalf("%s still says DO NOT EDIT:\n%s", path, body)
|
||||
}
|
||||
}
|
||||
|
||||
reg1, err := os.ReadFile(filepath.Join(pluginDir, "registry.gen.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.HasPrefix(reg1, []byte("// Code generated by summer make. DO NOT EDIT.\n")) {
|
||||
t.Fatalf("registry.gen.go lost its generated-code header:\n%s", reg1)
|
||||
}
|
||||
for _, want := range []string{
|
||||
"&models.Album{}",
|
||||
"&models.Widget{}",
|
||||
"updates.CreateAlbums()",
|
||||
"updates.AddAlbumIndex()",
|
||||
"console.PurgeCommand()",
|
||||
"console.PurgeCommand(bootApp)",
|
||||
"jobs.ReindexJob()",
|
||||
"controllers.AlbumsController()",
|
||||
} {
|
||||
@@ -922,6 +961,11 @@ func TestScaffoldAllArtifacts(t *testing.T) {
|
||||
if err := App(ctx, dir, &buf); err != nil {
|
||||
t.Fatalf("app build: %v\n%s", err, buf.String())
|
||||
}
|
||||
run := exec.CommandContext(ctx, filepath.Join(dir, "bin", "hello"), "demo:purge")
|
||||
run.Dir = dir
|
||||
if out, err := run.CombinedOutput(); err != nil || !bytes.Contains(out, []byte("demo:purge app=true")) {
|
||||
t.Fatalf("built app demo:purge: %v\n%s", err, out)
|
||||
}
|
||||
if out, err := execGo(t, dir, "build", "./...").CombinedOutput(); err != nil {
|
||||
t.Fatalf("copied workspace go build: %v\n%s", err, out)
|
||||
}
|
||||
@@ -1518,3 +1562,137 @@ func TestLocatePluginLegacyLayout(t *testing.T) {
|
||||
t.Fatalf("locatePluginDir with both layouts = %q, %v; want %s", got, err, vendorDir)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRegistryScanMarkersAndAppCommands: registry.gen.go lists files that
|
||||
// carry the //summer:make directive or the older generated-code header, and
|
||||
// a command function may take exactly one *backpack.App.
|
||||
func TestRegistryScanMarkersAndAppCommands(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
const imports = "import (\n\t\"git.golem15.com/golem15/summercms/modules/backpack\"\n\t\"git.golem15.com/golem15/summercms/modules/bonfire\"\n\t\"gorm.io/gorm\"\n)\n\n" +
|
||||
"var (\n\t_ backpack.App\n\t_ gorm.DB\n)\n\n"
|
||||
files := map[string]string{
|
||||
"legacy.go": "// Code generated by summer make. DO NOT EDIT.\n\npackage console\n\n" + imports + "func LegacyCommand() bonfire.Command { return bonfire.Command{} }\n",
|
||||
"unmarked.go": "package console\n\n" + imports + "func UnmarkedCommand() bonfire.Command { return bonfire.Command{} }\n",
|
||||
"lookalike.go": "//summer:makefile command\n\npackage console\n\n" + imports + "func LookalikeCommand() bonfire.Command { return bonfire.Command{} }\n",
|
||||
"bare.go": "//summer:make\n\npackage console\n\n" + imports + "func BareCommand() bonfire.Command { return bonfire.Command{} }\n",
|
||||
"named.go": "//summer:make command\n\npackage console\n\n" + imports + "func NamedCommand(app *backpack.App) bonfire.Command { return bonfire.Command{} }\n",
|
||||
"unnamed.go": "//summer:make command\n\npackage console\n\n" + imports + "func UnnamedCommand(*backpack.App) bonfire.Command { return bonfire.Command{} }\n",
|
||||
"value.go": "//summer:make command\n\npackage console\n\n" + imports + "func ValueCommand(app backpack.App) bonfire.Command { return bonfire.Command{} }\n",
|
||||
"two.go": "//summer:make command\n\npackage console\n\n" + imports + "func TwoCommand(app *backpack.App, n int) bonfire.Command { return bonfire.Command{} }\n",
|
||||
"twonames.go": "//summer:make command\n\npackage console\n\n" + imports + "func TwoNamesCommand(a, b *backpack.App) bonfire.Command { return bonfire.Command{} }\n",
|
||||
"other.go": "//summer:make command\n\npackage console\n\n" + imports + "func OtherCommand(db *gorm.DB) bonfire.Command { return bonfire.Command{} }\n",
|
||||
}
|
||||
for name, body := range files {
|
||||
write(t, filepath.Join(dir, name), body)
|
||||
}
|
||||
refs, err := scanGeneratedIdents(dir, "console", scanCommandFuncs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := map[string]bool{}
|
||||
for _, ref := range refs {
|
||||
got[ref.Ident] = ref.TakesApp
|
||||
}
|
||||
want := map[string]bool{
|
||||
"BareCommand": false,
|
||||
"LegacyCommand": false,
|
||||
"NamedCommand": true,
|
||||
"UnnamedCommand": true,
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("refs = %+v, want %v", refs, want)
|
||||
}
|
||||
for ident, takesApp := range want {
|
||||
if v, ok := got[ident]; !ok || v != takesApp {
|
||||
t.Fatalf("refs = %+v, want %s TakesApp=%t", refs, ident, takesApp)
|
||||
}
|
||||
}
|
||||
|
||||
// Other kinds still take no parameters at all.
|
||||
jobsDir := t.TempDir()
|
||||
write(t, filepath.Join(jobsDir, "job.go"), "//summer:make job\n\npackage jobs\n\nimport (\n\t\"git.golem15.com/golem15/summercms/modules/backpack\"\n\t\"git.golem15.com/golem15/summercms/modules/pact\"\n)\n\n"+
|
||||
"func AppJob(app *backpack.App) pact.Job { return nil }\n\nfunc PlainJob() pact.Job { return nil }\n")
|
||||
jobRefs, err := scanGeneratedIdents(jobsDir, "jobs", scanJobFuncs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(jobRefs) != 1 || jobRefs[0].Ident != "PlainJob" {
|
||||
t.Fatalf("job refs = %+v, want only PlainJob", jobRefs)
|
||||
}
|
||||
|
||||
sortRefs(refs)
|
||||
data := registryData{Package: "demo", Module: "example.com/app/plugins/acme/demo", Commands: refs}
|
||||
data.prepare()
|
||||
src, err := renderStub("registry.go", data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, line := range []string{
|
||||
"func generatedCommands(app ...*backpack.App) []bonfire.Command {",
|
||||
"var bootApp *backpack.App",
|
||||
"console.BareCommand(),",
|
||||
"console.LegacyCommand(),",
|
||||
"console.NamedCommand(bootApp),",
|
||||
"console.UnnamedCommand(bootApp),",
|
||||
} {
|
||||
if !bytes.Contains(src, []byte(line)) {
|
||||
t.Fatalf("registry.gen.go missing %s:\n%s", line, src)
|
||||
}
|
||||
}
|
||||
|
||||
// Without app-taking commands the local is not declared.
|
||||
data = registryData{Package: "demo", Module: "example.com/app/plugins/acme/demo", Commands: []registryRef{{Package: "console", Ident: "LegacyCommand"}}}
|
||||
data.prepare()
|
||||
src, err = renderStub("registry.go", data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes.Contains(src, []byte("bootApp")) {
|
||||
t.Fatalf("registry.gen.go declares bootApp without app-taking commands:\n%s", src)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMakeCommandLegacyPluginGo: a plugin.go in the older shape (no app
|
||||
// kept, generatedCommands() without arguments) still compiles after
|
||||
// make:command, and the command prints how to pass the app.
|
||||
func TestMakeCommandLegacyPluginGo(t *testing.T) {
|
||||
dir := copyHelloApp(t)
|
||||
ctx := t.Context()
|
||||
pluginDir, err := MakePlugin(ctx, dir, "golem15.demo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pluginGo := filepath.Join(pluginDir, "plugin.go")
|
||||
src, err := os.ReadFile(pluginGo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
old := string(src)
|
||||
for _, r := range []struct{ from, to string }{
|
||||
{"type Plugin struct {\n\t// app is the application, kept from Boot for the generated commands.\n\tapp *backpack.App\n}", "type Plugin struct{}"},
|
||||
{"func (p *Plugin) Boot(app *backpack.App) error {\n\tp.app = app\n\treturn nil\n}", "func (p *Plugin) Boot(*backpack.App) error { return nil }"},
|
||||
{"generatedCommands(p.app)", "generatedCommands( )"},
|
||||
} {
|
||||
if !strings.Contains(old, r.from) {
|
||||
t.Fatalf("plugin.go lacks %q:\n%s", r.from, old)
|
||||
}
|
||||
old = strings.Replace(old, r.from, r.to, 1)
|
||||
}
|
||||
write(t, pluginGo, old)
|
||||
|
||||
res, err := MakeCommand(ctx, dir, "golem15.demo", "Purge")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{"console.PurgeCommand receives a nil *backpack.App", "generatedCommands(p.app)"} {
|
||||
if !strings.Contains(res.Hint, want) {
|
||||
t.Fatalf("hint %q lacks %q", res.Hint, want)
|
||||
}
|
||||
}
|
||||
if out, err := execGo(t, pluginDir, "build", "./...").CombinedOutput(); err != nil {
|
||||
t.Fatalf("legacy plugin.go does not build: %v\n%s", err, out)
|
||||
}
|
||||
if out, err := execGo(t, pluginDir, "vet", "./...").CombinedOutput(); err != nil {
|
||||
t.Fatalf("legacy plugin.go vet: %v\n%s", err, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
registryFileName = "registry.gen.go"
|
||||
generatedMark = "Code generated by summer make"
|
||||
registryFileName = "registry.gen.go"
|
||||
// generatedMark is the header registry.gen.go carries. Files scaffolded
|
||||
// before the scaffoldDirective existed carry it too and stay listed.
|
||||
generatedMark = "Code generated by summer make"
|
||||
// scaffoldDirective, followed by a space and the artifact kind, is the
|
||||
// first line of every file a make: command writes for the developer to
|
||||
// edit. registry.gen.go lists the files that carry it.
|
||||
scaffoldDirective = "//summer:make"
|
||||
)
|
||||
|
||||
type identScanKind int
|
||||
@@ -31,6 +37,8 @@ type registryRef struct {
|
||||
Package string
|
||||
Ident string
|
||||
SortKey string
|
||||
// TakesApp marks a command function with one *backpack.App parameter.
|
||||
TakesApp bool
|
||||
}
|
||||
|
||||
type registryData struct {
|
||||
@@ -42,6 +50,8 @@ type registryData struct {
|
||||
Commands []registryRef
|
||||
Jobs []registryRef
|
||||
AdminControllers []registryRef
|
||||
// AppCommands is set when at least one command takes the app.
|
||||
AppCommands bool
|
||||
}
|
||||
|
||||
func emptyRegistry(pkg, module string) registryData {
|
||||
@@ -52,6 +62,12 @@ func emptyRegistry(pkg, module string) registryData {
|
||||
|
||||
func (d *registryData) prepare() {
|
||||
d.Imports = uniqueLeafImports(d.Module, d.Models, d.Migrations, d.Commands, d.Jobs, d.AdminControllers)
|
||||
d.AppCommands = false
|
||||
for _, ref := range d.Commands {
|
||||
if ref.TakesApp {
|
||||
d.AppCommands = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func uniqueLeafImports(module string, groups ...[]registryRef) []string {
|
||||
@@ -142,7 +158,7 @@ func scanGeneratedIdents(dir, pkg string, kind identScanKind) ([]registryRef, er
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("build: parse %s: %w", path, err)
|
||||
}
|
||||
if !isGeneratedFile(file) {
|
||||
if !isScaffoldedFile(file) {
|
||||
continue
|
||||
}
|
||||
switch kind {
|
||||
@@ -150,7 +166,7 @@ func scanGeneratedIdents(dir, pkg string, kind identScanKind) ([]registryRef, er
|
||||
refs = append(refs, structRefs(pkg, name, file)...)
|
||||
default:
|
||||
want := resultTypeFor(kind)
|
||||
refs = append(refs, funcRefs(pkg, name, file, want)...)
|
||||
refs = append(refs, funcRefs(pkg, name, file, want, kind == scanCommandFuncs)...)
|
||||
}
|
||||
}
|
||||
return refs, nil
|
||||
@@ -171,9 +187,15 @@ func resultTypeFor(kind identScanKind) string {
|
||||
}
|
||||
}
|
||||
|
||||
func isGeneratedFile(file *ast.File) bool {
|
||||
// isScaffoldedFile reports whether file carries the //summer:make directive
|
||||
// (alone or followed by a space and the kind) or the older generated-code
|
||||
// header.
|
||||
func isScaffoldedFile(file *ast.File) bool {
|
||||
for _, cg := range file.Comments {
|
||||
for _, c := range cg.List {
|
||||
if c.Text == scaffoldDirective || strings.HasPrefix(c.Text, scaffoldDirective+" ") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(c.Text, generatedMark) {
|
||||
return true
|
||||
}
|
||||
@@ -204,15 +226,22 @@ func structRefs(pkg, filename string, file *ast.File) []registryRef {
|
||||
return refs
|
||||
}
|
||||
|
||||
func funcRefs(pkg, filename string, file *ast.File, want string) []registryRef {
|
||||
// funcRefs lists the exported functions of file that return want and take
|
||||
// no parameters; with allowApp, also those whose only parameter is a
|
||||
// *backpack.App.
|
||||
func funcRefs(pkg, filename string, file *ast.File, want string, allowApp bool) []registryRef {
|
||||
var refs []registryRef
|
||||
for _, decl := range file.Decls {
|
||||
fn, ok := decl.(*ast.FuncDecl)
|
||||
if !ok || fn.Recv != nil || fn.Name == nil || !fn.Name.IsExported() || fn.Type == nil {
|
||||
continue
|
||||
}
|
||||
takesApp := false
|
||||
if fn.Type.Params != nil && len(fn.Type.Params.List) > 0 {
|
||||
continue
|
||||
if !allowApp || !isSingleAppParam(fn.Type.Params) {
|
||||
continue
|
||||
}
|
||||
takesApp = true
|
||||
}
|
||||
if fn.Type.Results == nil || len(fn.Type.Results.List) != 1 {
|
||||
continue
|
||||
@@ -221,14 +250,33 @@ func funcRefs(pkg, filename string, file *ast.File, want string) []registryRef {
|
||||
continue
|
||||
}
|
||||
refs = append(refs, registryRef{
|
||||
Package: pkg,
|
||||
Ident: fn.Name.Name,
|
||||
SortKey: strings.TrimSuffix(filename, ".go"),
|
||||
Package: pkg,
|
||||
Ident: fn.Name.Name,
|
||||
SortKey: strings.TrimSuffix(filename, ".go"),
|
||||
TakesApp: takesApp,
|
||||
})
|
||||
}
|
||||
return refs
|
||||
}
|
||||
|
||||
// isSingleAppParam reports a parameter list of exactly one *backpack.App,
|
||||
// named or not. astTypeName drops the star, so the pointer is checked here.
|
||||
func isSingleAppParam(params *ast.FieldList) bool {
|
||||
if len(params.List) != 1 || len(params.List[0].Names) > 1 {
|
||||
return false
|
||||
}
|
||||
star, ok := params.List[0].Type.(*ast.StarExpr)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
sel, ok := star.X.(*ast.SelectorExpr)
|
||||
if !ok || sel.Sel == nil {
|
||||
return false
|
||||
}
|
||||
pkg, ok := sel.X.(*ast.Ident)
|
||||
return ok && pkg.Name == "backpack" && sel.Sel.Name == "App"
|
||||
}
|
||||
|
||||
func astTypeName(expr ast.Expr) string {
|
||||
switch t := expr.(type) {
|
||||
case *ast.StarExpr:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{define "model.go"}}// Code generated by summer make. DO NOT EDIT.
|
||||
{{define "model.go"}}//summer:make model
|
||||
|
||||
package models
|
||||
|
||||
@@ -14,7 +14,7 @@ type {{.Ident}} struct {
|
||||
func ({{.Ident}}) TableName() string { return {{printf "%q" .Table}} }
|
||||
{{end}}
|
||||
|
||||
{{define "migration.go"}}// Code generated by summer make. DO NOT EDIT.
|
||||
{{define "migration.go"}}//summer:make migration
|
||||
|
||||
package updates
|
||||
|
||||
@@ -37,18 +37,21 @@ func {{.Func}}() *gormigrate.Migration {
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{define "command.go"}}// Code generated by summer make. DO NOT EDIT.
|
||||
{{define "command.go"}}//summer:make command
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||||
)
|
||||
|
||||
// {{.Func}} returns the {{.CommandName}} console command.
|
||||
func {{.Func}}() bonfire.Command {
|
||||
// {{.Func}} returns the {{.CommandName}} console command. app is the
|
||||
// application the plugin kept from Boot: it gives the command the config and
|
||||
// the services plugins publish (app.Lookup).
|
||||
func {{.Func}}(app *backpack.App) bonfire.Command {
|
||||
return bonfire.Command{
|
||||
Name: {{printf "%q" .CommandName}},
|
||||
Description: {{printf "%q" .Description}},
|
||||
@@ -60,7 +63,7 @@ func {{.Func}}() bonfire.Command {
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{define "job.go"}}// Code generated by summer make. DO NOT EDIT.
|
||||
{{define "job.go"}}//summer:make job
|
||||
|
||||
package jobs
|
||||
|
||||
@@ -84,7 +87,7 @@ func {{.Func}}() pact.Job {
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{define "admin_controller.go"}}// Code generated by summer make. DO NOT EDIT.
|
||||
{{define "admin_controller.go"}}//summer:make admin-controller
|
||||
|
||||
package controllers
|
||||
|
||||
|
||||
@@ -32,13 +32,20 @@ var langFS embed.FS
|
||||
var mailFS embed.FS
|
||||
|
||||
// Plugin is the {{.ID}} plugin.
|
||||
type Plugin struct{}
|
||||
type Plugin struct {
|
||||
// app is the application, kept from Boot for the generated commands.
|
||||
app *backpack.App
|
||||
}
|
||||
|
||||
func (p *Plugin) ID() string { return {{printf "%q" .ID}} }
|
||||
func (p *Plugin) Requires() []string { return nil }
|
||||
|
||||
func (p *Plugin) Register(*backpack.App) error { return nil }
|
||||
func (p *Plugin) Boot(*backpack.App) error { return nil }
|
||||
|
||||
func (p *Plugin) Boot(app *backpack.App) error {
|
||||
p.app = app
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) ConfigFS() fs.FS { return configFS }
|
||||
func (p *Plugin) LangFS() fs.FS { return langFS }
|
||||
@@ -47,10 +54,13 @@ func (p *Plugin) MailTemplatesFS() fs.FS { return mailFS }
|
||||
func (p *Plugin) MailTemplates() []string { return nil }
|
||||
func (p *Plugin) MailLayouts() map[string]string { return nil }
|
||||
|
||||
func (p *Plugin) Models() []any { return generatedModels() }
|
||||
func (p *Plugin) Migrations() []*gormigrate.Migration { return generatedMigrations() }
|
||||
func (p *Plugin) Commands() []bonfire.Command { return generatedCommands() }
|
||||
func (p *Plugin) Jobs() []pact.Job { return generatedJobs() }
|
||||
func (p *Plugin) Models() []any { return generatedModels() }
|
||||
func (p *Plugin) Migrations() []*gormigrate.Migration { return generatedMigrations() }
|
||||
|
||||
// Commands is collected after Boot, so p.app is set.
|
||||
func (p *Plugin) Commands() []bonfire.Command { return generatedCommands(p.app) }
|
||||
|
||||
func (p *Plugin) Jobs() []pact.Job { return generatedJobs() }
|
||||
func (p *Plugin) AdminControllers() []pact.AdminController {
|
||||
return generatedAdminControllers()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package {{.Package}}
|
||||
|
||||
import (
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||||
"git.golem15.com/golem15/summercms/modules/pact"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
@@ -35,11 +36,19 @@ func generatedMigrations() []*gormigrate.Migration {
|
||||
{{- end}}
|
||||
}
|
||||
|
||||
func generatedCommands() []bonfire.Command {
|
||||
// generatedCommands returns the plugin's console commands. Commands that
|
||||
// take a *backpack.App receive the first app passed in, or nil when none is.
|
||||
func generatedCommands(app ...*backpack.App) []bonfire.Command {
|
||||
{{- if .Commands}}
|
||||
{{- if .AppCommands}}
|
||||
var bootApp *backpack.App
|
||||
if len(app) > 0 {
|
||||
bootApp = app[0]
|
||||
}
|
||||
{{- end}}
|
||||
return []bonfire.Command{
|
||||
{{- range .Commands}}
|
||||
{{.Package}}.{{.Ident}}(),
|
||||
{{.Package}}.{{.Ident}}({{if .TakesApp}}bootApp{{end}}),
|
||||
{{- end}}
|
||||
}
|
||||
{{- else}}
|
||||
|
||||
@@ -32,13 +32,20 @@ var langFS embed.FS
|
||||
var mailFS embed.FS
|
||||
|
||||
// Plugin is the golem15.demo plugin.
|
||||
type Plugin struct{}
|
||||
type Plugin struct {
|
||||
// app is the application, kept from Boot for the generated commands.
|
||||
app *backpack.App
|
||||
}
|
||||
|
||||
func (p *Plugin) ID() string { return "golem15.demo" }
|
||||
func (p *Plugin) Requires() []string { return nil }
|
||||
|
||||
func (p *Plugin) Register(*backpack.App) error { return nil }
|
||||
func (p *Plugin) Boot(*backpack.App) error { return nil }
|
||||
|
||||
func (p *Plugin) Boot(app *backpack.App) error {
|
||||
p.app = app
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) ConfigFS() fs.FS { return configFS }
|
||||
func (p *Plugin) LangFS() fs.FS { return langFS }
|
||||
@@ -49,8 +56,11 @@ func (p *Plugin) MailLayouts() map[string]string { return nil }
|
||||
|
||||
func (p *Plugin) Models() []any { return generatedModels() }
|
||||
func (p *Plugin) Migrations() []*gormigrate.Migration { return generatedMigrations() }
|
||||
func (p *Plugin) Commands() []bonfire.Command { return generatedCommands() }
|
||||
func (p *Plugin) Jobs() []pact.Job { return generatedJobs() }
|
||||
|
||||
// Commands is collected after Boot, so p.app is set.
|
||||
func (p *Plugin) Commands() []bonfire.Command { return generatedCommands(p.app) }
|
||||
|
||||
func (p *Plugin) Jobs() []pact.Job { return generatedJobs() }
|
||||
func (p *Plugin) AdminControllers() []pact.AdminController {
|
||||
return generatedAdminControllers()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user