package appcli import ( "context" "gitea.auvem.com/go-toolkit/app" "github.com/urfave/cli/v3" ) // NewCommand wraps cmd with dependency loading in Before. The input command is // not mutated; a shallow copy is returned. func NewCommand(cmdcfg *cli.Command, depfn ...DepFn) *cli.Command { if len(depfn) == 0 { return cmdcfg } cmd := cloneCommand(cmdcfg) originalBefore := cmdcfg.Before cmd.Before = func(ctx context.Context, cmd *cli.Command) (context.Context, error) { if originalBefore != nil { var err error ctx, err = originalBefore(ctx, cmd) if err != nil { return ctx, err } } lifecycle := app.LifecycleFromContext(ctx) if lifecycle == nil { return ctx, ErrLifecycleNotInContext } deps := make([]*app.Module, 0) for _, fn := range depfn { if fn == nil { continue } modules, err := fn(lifecycle, cmd) if err != nil { return ctx, err } deps = append(deps, modules...) } if len(deps) > 0 { if err := lifecycle.Require(deps...); err != nil { return ctx, err } } return ctx, nil } return cmd } // NewRootCommand wraps a root command, adds a global --verbose / -v flag, and // applies dependency loading via [NewCommand]. func NewRootCommand(cmdcfg *cli.Command, depfn ...DepFn) *cli.Command { root := cloneCommand(cmdcfg) if !hasFlag(root, "verbose") { root.Flags = append(root.Flags, &cli.BoolFlag{ Name: "verbose", Aliases: []string{"v"}, Usage: "Enable verbose output", }) } return NewCommand(root, depfn...) } // VerboseFromCommand reports whether --verbose was set on the command or an ancestor. func VerboseFromCommand(cmd *cli.Command) bool { if cmd == nil { return false } return cmd.Bool("verbose") } func cloneCommand(src *cli.Command) *cli.Command { if src == nil { return nil } dup := *src if len(src.Flags) > 0 { dup.Flags = append([]cli.Flag(nil), src.Flags...) } if len(src.Commands) > 0 { dup.Commands = append([]*cli.Command(nil), src.Commands...) } if len(src.Arguments) > 0 { dup.Arguments = append([]cli.Argument(nil), src.Arguments...) } return &dup } func hasFlag(cmd *cli.Command, name string) bool { for _, f := range cmd.Flags { if bf, ok := f.(*cli.BoolFlag); ok && bf.Name == name { return true } } return false }