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:
145
modules/bonfire/command.go
Normal file
145
modules/bonfire/command.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user