- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
146 lines
3.5 KiB
Go
146 lines
3.5 KiB
Go
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)
|
|
}
|