From 0badbafa00602b57ad20b23804a76fabdbeecf62 Mon Sep 17 00:00:00 2001 From: Elijah Duffy Date: Thu, 5 Jun 2025 15:00:20 -0700 Subject: [PATCH] use DepFn to pass dependencies rather than direct module list Allows dependency modules to be built in the context of the lifecycle and command. --- appcli.go | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/appcli.go b/appcli.go index e39325e..b93a4db 100644 --- a/appcli.go +++ b/appcli.go @@ -8,14 +8,28 @@ import ( "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, depends ...*app.Module) *cli.Command { - if len(depends) == 0 { +func NewCommand(cmdcfg *cli.Command, depfn DepFn) *cli.Command { + if depfn == nil { return cmdcfg } @@ -35,7 +49,12 @@ func NewCommand(cmdcfg *cli.Command, depends ...*app.Module) *cli.Command { return ctx, errors.New("lifecycle not found in context, cannot run command with dependencies") } - if err := lifecycle.Require(depends...); err != nil { + deps, err := depfn(lifecycle, cmd) + if err != nil { + return ctx, err + } + + if err := lifecycle.Require(deps...); err != nil { return ctx, err } return ctx, nil @@ -49,9 +68,9 @@ type RootCommandOpts struct { // Command is the base command configuration. Command *cli.Command - // Dependencies are the modules that this command depends on. Note: All - // root dependencies will be inherited by all subcommands. - Dependencies []*app.Module + // DepFn is a function that returns the modules that this command depends + // on. Note: All root dependencies will be inherited by all subcommands. + DepFn DepFn } // NewRootCommand creates a new root CLI command with the specified configuration. @@ -111,7 +130,7 @@ func NewRootCommand(rootcfg *RootCommandOpts) *cli.Command { return nil } - return NewCommand(cmdcfg, rootcfg.Dependencies...) + return NewCommand(cmdcfg, rootcfg.DepFn) } // VerboseFromCommand checks if the verbose flag is set in the command context.