package main import ( "context" "fmt" "os" "strings" "git.golem15.com/golem15/summercms/bonfire" "git.golem15.com/golem15/summercms/internal/build" "git.golem15.com/golem15/summercms/internal/dev" ) func main() { root, err := bonfire.NewRoot("summer", toolCommands(), os.Stdout) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } root.SetArgs(os.Args[1:]) if err := root.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func toolCommands() []bonfire.Command { return []bonfire.Command{ buildCommand(), makePluginCommand(), makeModelCommand(), makeMigrationCommand(), makeCommandCommand(), makeJobCommand(), makeAdminControllerCommand(), addPluginCommand(), devCommand(), parityProxyCommand(), parityRecordCommand(), parityReplayCommand(), delegateCommand("migrate", "Run plugin migrations in the app binary"), delegateRollbackCommand(), delegateCommand("migrate:status", "Show per-plugin migration history in the app binary"), delegateCommand("serve", "Run the app HTTP server"), } } func buildCommand() bonfire.Command { return bonfire.Command{ Name: "build", Description: "Generate plugin imports and build the app binary", Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { dir, err := os.Getwd() if err != nil { return err } return build.App(ctx, dir, out) }, } } func makePluginCommand() bonfire.Command { return bonfire.Command{ Name: "make:plugin", Description: "Scaffold a compiling plugin module from a vendor.plugin id", Args: []bonfire.Arg{{ Name: "id", Description: "Plugin ID in vendor.plugin form", Required: true, }}, Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { id, ok := in.Argument("id") if !ok || id == "" { return fmt.Errorf("make:plugin requires a vendor.plugin id") } dir, err := os.Getwd() if err != nil { return err } created, err := build.MakePlugin(ctx, dir, id) if err != nil { return err } out.Printf("created %s\n", created) return nil }, } } func makeModelCommand() bonfire.Command { return bonfire.Command{ Name: "make:model", Description: "Generate a GORM model and create-table migration", Args: makeArtifactArgs(), Flags: []bonfire.Flag{{ Name: "no-migration", Description: "Omit the create-table migration", Bare: true, }}, Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { dir, err := os.Getwd() if err != nil { return err } id, name, err := resolveMakeArgs(in, "make:model") if err != nil { return err } result, err := build.MakeModel(ctx, dir, id, name, flagTrue(in, "no-migration")) if err != nil { return err } return printArtifact(out, result) }, } } func makeMigrationCommand() bonfire.Command { return bonfire.Command{ Name: "make:migration", Description: "Generate an ordered gormigrate stub", Args: makeArtifactArgs(), Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { dir, err := os.Getwd() if err != nil { return err } id, name, err := resolveMakeArgs(in, "make:migration") if err != nil { return err } result, err := build.MakeMigration(ctx, dir, id, name) if err != nil { return err } return printArtifact(out, result) }, } } func makeCommandCommand() bonfire.Command { return bonfire.Command{ Name: "make:command", Description: "Generate a plugin console command", Args: makeArtifactArgs(), Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { dir, err := os.Getwd() if err != nil { return err } id, name, err := resolveMakeArgs(in, "make:command") if err != nil { return err } result, err := build.MakeCommand(ctx, dir, id, name) if err != nil { return err } return printArtifact(out, result) }, } } func makeJobCommand() bonfire.Command { return bonfire.Command{ Name: "make:job", Description: "Generate a plugin job without importing River", Args: makeArtifactArgs(), Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { dir, err := os.Getwd() if err != nil { return err } id, name, err := resolveMakeArgs(in, "make:job") if err != nil { return err } result, err := build.MakeJob(ctx, dir, id, name) if err != nil { return err } return printArtifact(out, result) }, } } func makeAdminControllerCommand() bonfire.Command { return bonfire.Command{ Name: "make:admin-controller", Description: "Generate an admin controller with fields.yaml and columns.yaml", Args: makeArtifactArgs(), Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { dir, err := os.Getwd() if err != nil { return err } id, name, err := resolveMakeArgs(in, "make:admin-controller") if err != nil { return err } result, err := build.MakeAdminController(ctx, dir, id, name) if err != nil { return err } return printArtifact(out, result) }, } } func makeArtifactArgs() []bonfire.Arg { return []bonfire.Arg{ {Name: "plugin", Description: "Plugin ID in vendor.plugin form, or the artifact name when already inside the plugin"}, {Name: "name", Description: "Exported Go identifier"}, } } func resolveMakeArgs(in bonfire.Input, cmd string) (id, name string, err error) { args := in.Args() switch len(args) { case 2: return args[0], args[1], nil case 1: return "", args[0], nil default: return "", "", fmt.Errorf("%s requires , or inside a plugin directory", cmd) } } func flagTrue(in bonfire.Input, name string) bool { v, ok := in.Flag(name) if !ok { return false } switch strings.ToLower(strings.TrimSpace(v)) { case "", "true", "1", "yes": return true default: return false } } func printArtifact(out bonfire.Output, result build.ArtifactResult) error { for _, path := range result.Files { out.Printf("created %s\n", path) } if result.Hint != "" { out.Printf("%s\n", result.Hint) } return nil } func devCommand() bonfire.Command { return bonfire.Command{ Name: "dev", Description: "Watch sources and rebuild the app binary", Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { dir, err := os.Getwd() if err != nil { return err } return dev.Watch(ctx, dir, out) }, } } func addPluginCommand() bonfire.Command { return bonfire.Command{ Name: "plugin:add", Description: "Register a local plugin module in the app manifest and workspace", Args: []bonfire.Arg{{ Name: "dir", Description: "Local plugin directory", Required: true, }}, Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { pluginDir, ok := in.Argument("dir") if !ok || pluginDir == "" { return fmt.Errorf("plugin:add requires a local plugin directory") } dir, err := os.Getwd() if err != nil { return err } if err := build.AddPlugin(ctx, dir, pluginDir); err != nil { return err } out.Printf("added %s\n", pluginDir) return nil }, } }