package bonfire import ( "context" "errors" "fmt" "io" "strings" ) // ErrUnknownCommand is returned by Call when no command has the given name. var ErrUnknownCommand = errors.New("bonfire: unknown command") // Call runs the command named name in-process with args, writing its output // to out. Stdin is empty, so prompts take their defaults. A name that no // command has is ErrUnknownCommand. func Call(ctx context.Context, commands []Command, name string, args []string, out io.Writer) error { cmd, ok := findCommand(commands, name) if !ok { return fmt.Errorf("%w: %q", ErrUnknownCommand, name) } if out == nil { out = io.Discard } root, err := NewRootIO(name, []Command{cmd}, strings.NewReader(""), out, out) if err != nil { return err } root.SetArgs(append([]string{name}, args...)) if ctx == nil { ctx = context.Background() } return root.ExecuteContext(ctx) } // Catalog is the final command list of an application binary. The generated // main publishes it on the app so code outside the cobra root, such as the // scheduler, can run any registered command with Call. type Catalog struct { commands []Command } // NewCatalog returns a Catalog holding a copy of commands. func NewCatalog(commands []Command) *Catalog { return &Catalog{commands: append([]Command(nil), commands...)} } // Has reports whether the catalog holds a command named name. func (c *Catalog) Has(name string) bool { if c == nil { return false } _, ok := findCommand(c.commands, name) return ok } // Call runs the named catalog command in-process; see the package Call. func (c *Catalog) Call(ctx context.Context, name string, args []string, out io.Writer) error { if c == nil { return fmt.Errorf("%w: %q", ErrUnknownCommand, name) } return Call(ctx, c.commands, name, args, out) } func findCommand(commands []Command, name string) (Command, bool) { for _, c := range commands { if c.Name == name { return c, true } } return Command{}, false }