refactor(10.2-01): nest framework packages under modules

- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
This commit is contained in:
Jakub Zych
2026-09-28 02:21:02 +02:00
parent ac1f6d14f4
commit 5e50b166ef
277 changed files with 303 additions and 303 deletions

145
modules/bonfire/command.go Normal file
View File

@@ -0,0 +1,145 @@
package bonfire
import (
"context"
"errors"
"strings"
"github.com/spf13/cobra"
)
// ErrCommandName is returned when a plugin command is missing namespace:verb.
var ErrCommandName = errors.New("bonfire: plugin command name must be namespace:verb")
// Command is a console command value collected from plugins or the tool.
type Command struct {
Name string
Description string
Flags []Flag
Args []Arg
Run func(ctx context.Context, in Input, out Output) error
}
// Flag describes a string flag passed to a command.
type Flag struct {
Name string
Shorthand string
Description string
Default string
// Bare allows --flag without a value; cobra stores "true".
Bare bool
// Repeatable registers this flag as an ordered, multi-occurrence
// string flag (Cobra StringSlice) instead of a scalar string flag
// (08-CONTEXT.md D-19; 08-PATTERNS.md "bonfire repeatable-flag gap").
// Repeated `--name=a --name=b` preserves insertion order and is read
// back through Input.Flags, never Input.Flag. Existing scalar/bare
// flags are unaffected: Repeatable defaults to false.
Repeatable bool
}
// Arg describes a positional argument.
type Arg struct {
Name string
Description string
Required bool
}
// Input is the parsed argument and flag view handed to Command.Run.
type Input interface {
Args() []string
Argument(name string) (string, bool)
Flag(name string) (string, bool)
// Flags returns the ordered, repeated values of a Repeatable flag
// (D-19). It returns nil for a scalar/bare flag or an unset repeatable
// flag; callers must use Flag for scalar flags.
Flags(name string) []string
}
type cobraInput struct {
cmd *cobra.Command
spec Command
args []string
}
func (in cobraInput) Args() []string { return in.args }
func (in cobraInput) Argument(name string) (string, bool) {
for i, arg := range in.spec.Args {
if arg.Name == name {
if i < len(in.args) {
return in.args[i], true
}
return "", false
}
}
return "", false
}
// Flags returns the ordered values of a Repeatable (Cobra StringSlice)
// flag. It returns nil if the flag was never registered as repeatable
// (wrong pflag type) or the command has no flag set (08-CONTEXT.md D-19).
func (in cobraInput) Flags(name string) []string {
if in.cmd == nil || in.cmd.Flags() == nil {
return nil
}
vals, err := in.cmd.Flags().GetStringSlice(name)
if err != nil {
return nil
}
return vals
}
func (in cobraInput) Flag(name string) (string, bool) {
if in.cmd == nil || in.cmd.Flags() == nil {
return "", false
}
if !in.cmd.Flags().Changed(name) {
val, err := in.cmd.Flags().GetString(name)
if err != nil || val == "" {
return "", false
}
return val, true
}
val, err := in.cmd.Flags().GetString(name)
if err != nil {
return "", false
}
return val, true
}
func validCommandName(name string) bool {
switch name {
case "build", "dev", "serve", "migrate":
return true
}
ns, verb, ok := strings.Cut(name, ":")
return ok && ns != "" && verb != "" && !strings.Contains(verb, " ")
}
func commandUsage(c Command) string {
parts := []string{c.Name}
for _, a := range c.Args {
if a.Required {
parts = append(parts, "<"+a.Name+">")
} else {
parts = append(parts, "["+a.Name+"]")
}
}
return strings.Join(parts, " ")
}
func positionalArgs(args []Arg) cobra.PositionalArgs {
required := 0
for _, a := range args {
if a.Required {
required++
}
}
if required == 0 {
return cobra.ArbitraryArgs
}
if required == len(args) {
return cobra.ExactArgs(required)
}
return cobra.MinimumNArgs(required)
}