diff --git a/app.go b/app.go index 32214b9..8274231 100644 --- a/app.go +++ b/app.go @@ -210,6 +210,10 @@ func (app *appImpl) init() error { return err } for _, actConf := range actions { + if err = actConf.EnsureLoaded(); err != nil { + return err + } + if launchrConfig != nil && len(launchrConfig.ActionsNaming) > 0 { actID := actConf.ID for _, an := range launchrConfig.ActionsNaming { @@ -247,6 +251,10 @@ func (app *appImpl) exec() error { actions := app.actionMngr.AllRef() // Check the requested command to see what actions we must actually load. if app.reqCmd != "" { + aliases := app.actionMngr.AllAliasRef() + if alias, ok := aliases[app.reqCmd]; ok { + app.reqCmd = alias + } a, ok := actions[app.reqCmd] if ok { // Use only the requested action. diff --git a/docs/actions.md b/docs/actions.md index 2734acc..c2e9810 100644 --- a/docs/actions.md +++ b/docs/actions.md @@ -13,6 +13,9 @@ Action configuration files are written in `yaml`, example declaration: action: title: Verb description: Handles some logic + alias: + - "alias1" + - "alias2" arguments: - name: myArg1 title: Argument 1 diff --git a/docs/actions.schema.md b/docs/actions.schema.md index 0f42c30..996d875 100644 --- a/docs/actions.schema.md +++ b/docs/actions.schema.md @@ -8,6 +8,9 @@ Basic action definition must have `image` and `command` to run the command in th action: title: Action name description: Long description + alias: + - "alias1" + - "alias2" image: alpine:latest command: - ls diff --git a/pkg/action/cobra.go b/pkg/action/cobra.go index 33476b0..8507d20 100644 --- a/pkg/action/cobra.go +++ b/pkg/action/cobra.go @@ -28,7 +28,8 @@ func CobraImpl(a *Action, streams cli.Streams) (*cobra.Command, error) { Use: use, // Using custom args validation in ValidateInput. // @todo: maybe we need a long template for arguments description - Short: getDesc(actConf.Title, actConf.Description), + Short: getDesc(actConf.Title, actConf.Description), + Aliases: actConf.Aliases, RunE: func(cmd *cobra.Command, args []string) error { // Pass to the run environment its flags. if env, ok := a.env.(RunEnvironmentFlags); ok { diff --git a/pkg/action/manager.go b/pkg/action/manager.go index 8c108ee..b0fda66 100644 --- a/pkg/action/manager.go +++ b/pkg/action/manager.go @@ -19,6 +19,8 @@ type Manager interface { // Use it only if you need to read-only actions without allocations. It may be unsafe to read/write the map. // If you need to run actions, use Get or All, it will provide configured for run Action. AllRef() map[string]*Action + // AllAliasRef returns map of all aliased actions + AllAliasRef() map[string]string // Get returns a copy of an action from the manager with default decorators. Get(id string) (*Action, bool) // GetRef returns an original action value from the storage. @@ -49,21 +51,23 @@ type Manager interface { type DecorateWithFn = func(m Manager, a *Action) type actionManagerMap struct { - actionStore map[string]*Action - runStore map[string]RunInfo // @todo consider persistent storage - mx sync.Mutex - mxRun sync.Mutex - dwFns []DecorateWithFn - processors map[string]ValueProcessor + actionStore map[string]*Action + actionAliases map[string]string + runStore map[string]RunInfo // @todo consider persistent storage + mx sync.Mutex + mxRun sync.Mutex + dwFns []DecorateWithFn + processors map[string]ValueProcessor } // NewManager constructs a new action manager. func NewManager(withFns ...DecorateWithFn) Manager { return &actionManagerMap{ - actionStore: make(map[string]*Action), - runStore: make(map[string]RunInfo), - dwFns: withFns, - processors: make(map[string]ValueProcessor), + actionStore: make(map[string]*Action), + actionAliases: make(map[string]string), + runStore: make(map[string]RunInfo), + dwFns: withFns, + processors: make(map[string]ValueProcessor), } } @@ -75,6 +79,10 @@ func (m *actionManagerMap) Add(a *Action) { m.mx.Lock() defer m.mx.Unlock() m.actionStore[a.ID] = a + + for _, alias := range a.ActionDef().Aliases { + m.actionAliases[alias] = a.ID + } } func (m *actionManagerMap) AllRef() map[string]*Action { @@ -83,6 +91,12 @@ func (m *actionManagerMap) AllRef() map[string]*Action { return copyMap(m.actionStore) } +func (m *actionManagerMap) AllAliasRef() map[string]string { + m.mx.Lock() + defer m.mx.Unlock() + return copyMap(m.actionAliases) +} + func (m *actionManagerMap) All() map[string]*Action { ret := m.AllRef() for k, v := range ret { diff --git a/pkg/action/yaml.def.go b/pkg/action/yaml.def.go index 3bb3ea8..ed91e1d 100644 --- a/pkg/action/yaml.def.go +++ b/pkg/action/yaml.def.go @@ -135,6 +135,7 @@ func validateV1(_ *Definition) error { type DefAction struct { Title string `yaml:"title"` Description string `yaml:"description"` + Aliases []string `yaml:"alias"` Arguments ArgumentsList `yaml:"arguments"` Options OptionsList `yaml:"options"` Command StrSliceOrStr `yaml:"command"`