Files
appcli/appcli.go
2025-06-09 13:00:20 -07:00

86 lines
2.4 KiB
Go

package appcli
import (
"context"
"errors"
"gitea.auvem.com/go-toolkit/app"
"github.com/urfave/cli/v3"
)
// DepFn is a function type that returns a slice of dependencies.
type DepFn func(*app.Lifecycle, *cli.Command) ([]*app.Module, error)
// DepList is a convenience function that returns a DepFn that uses a
// predefined list of dependecies.
func DepList(deps ...*app.Module) DepFn {
return func(_ *app.Lifecycle, _ *cli.Command) ([]*app.Module, error) {
if len(deps) == 0 {
return nil, errors.New("no dependencies provided")
}
return deps, nil
}
}
// NewCommand creates a new CLI command with the specified configuration and
// and dependencies. Returns a standard *cli.Command that can be used directly
// with urfave/cli/v3 types. If any dependencies are provided, the Before method
// is overriden to ensure that all dependencies are satisfied before the command
// is executed. Requires an app.Lifecycle to be present in the context when the
// command is executed.
func NewCommand(cmdcfg *cli.Command, depfn DepFn) *cli.Command {
if depfn == nil {
return cmdcfg
}
// Override the Before method to handle dependencies
originalBefore := cmdcfg.Before
cmdcfg.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, errors.New("lifecycle not found in context, cannot run command with dependencies")
}
deps, err := depfn(lifecycle, cmd)
if err != nil {
return ctx, err
}
if err := lifecycle.Require(deps...); err != nil {
return ctx, err
}
return ctx, nil
}
return cmdcfg
}
// NewRootCommand creates a new root CLI command with the specified configuration.
// Adds verbose flag and override Before and After methods to handle dependencies.
// See NewCommand for more details.
func NewRootCommand(cmdcfg *cli.Command, depfn DepFn) *cli.Command {
cmdcfg.Flags = append(cmdcfg.Flags, &cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
Usage: "Enable verbose output",
})
return NewCommand(cmdcfg, depfn)
}
// VerboseFromCommand checks if the verbose flag is set in the command context.
func VerboseFromCommand(cmd *cli.Command) bool {
if cmd == nil {
return false
}
return cmd.Bool("verbose")
}