Route executions through neutral snapshots
This commit is contained in:
64
execute.go
64
execute.go
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
|
||||
internalcobra "gitea.maximumdirect.net/eric/CommandKit/internal/cobra"
|
||||
commandmeta "gitea.maximumdirect.net/eric/CommandKit/internal/commandmeta"
|
||||
)
|
||||
|
||||
// Execute parses and dispatches one invocation. args excludes the executable
|
||||
@@ -19,21 +20,22 @@ func (a *App) Execute(ctx context.Context, args []string, streams Streams) Outco
|
||||
}
|
||||
streams = normalizeStreams(streams)
|
||||
current := newExecution(a, ctx, streams)
|
||||
routedSnapshot := current.snapshot
|
||||
parsed := current.parse(args)
|
||||
if parsed.Failure != nil {
|
||||
return current.present(Usage(errors.New(parsed.Failure.Message)), parsed.Path)
|
||||
}
|
||||
command, ok := a.commandAt(parsed.Path)
|
||||
if !ok || command.record == nil || command.record.payload == nil {
|
||||
payload, ok := routedSnapshot.runners[parsed.Key]
|
||||
if !ok || payload == nil {
|
||||
return current.present(current.renderHelp(parsed.Path), parsed.Path)
|
||||
}
|
||||
if parsed.HelpRequested || !command.record.payload.hasRun() {
|
||||
if _, err := command.record.payload.prepare(parsed.FlagValues, parsed.Operands, false); err != nil {
|
||||
if parsed.HelpRequested || !payload.hasRun() {
|
||||
if _, err := payload.prepare(parsed.FlagValues, parsed.Operands, false); err != nil {
|
||||
return current.present(Usage(err), parsed.Path)
|
||||
}
|
||||
return current.present(current.renderHelp(parsed.Path), parsed.Path)
|
||||
}
|
||||
run, err := command.record.payload.prepare(parsed.FlagValues, parsed.Operands, true)
|
||||
run, err := payload.prepare(parsed.FlagValues, parsed.Operands, true)
|
||||
if err != nil {
|
||||
return current.present(Usage(err), parsed.Path)
|
||||
}
|
||||
@@ -44,8 +46,8 @@ type execution struct {
|
||||
app *App
|
||||
ctx context.Context
|
||||
streams Streams
|
||||
options internalcobra.ParseOptions
|
||||
metadata *internalcobra.Command
|
||||
options commandmeta.ParseOptions
|
||||
snapshot *routingSnapshot
|
||||
session *internalcobra.Session
|
||||
}
|
||||
|
||||
@@ -70,18 +72,18 @@ func newExecution(app *App, ctx context.Context, streams Streams) *execution {
|
||||
app: app,
|
||||
ctx: ctx,
|
||||
streams: streams,
|
||||
options: internalcobra.ParseOptions{Context: ctx, Out: streams.Out, Err: streams.Err},
|
||||
options: commandmeta.ParseOptions{Context: ctx, Out: streams.Out, Err: streams.Err},
|
||||
}
|
||||
if app != nil {
|
||||
current.metadata = app.bridgeTree()
|
||||
current.session = internalcobra.Prepare(current.metadata, current.options)
|
||||
current.snapshot = app.routeSnapshot()
|
||||
current.session = internalcobra.Prepare(current.snapshot.metadata, current.options)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func (current *execution) parse(args []string) internalcobra.Result {
|
||||
func (current *execution) parse(args []string) commandmeta.Result {
|
||||
if current.app == nil {
|
||||
return internalcobra.Result{Failure: &internalcobra.Failure{Message: "cannot parse commands on a nil app"}}
|
||||
return commandmeta.Result{Failure: &commandmeta.Failure{Message: "cannot parse commands on a nil app"}}
|
||||
}
|
||||
return current.session.Parse(args)
|
||||
}
|
||||
@@ -90,10 +92,10 @@ func (current *execution) presentationSession() *internalcobra.Session {
|
||||
if current.app == nil {
|
||||
return nil
|
||||
}
|
||||
metadata := current.app.bridgeTree()
|
||||
if current.session == nil || current.session.Metadata() != metadata {
|
||||
current.metadata = metadata
|
||||
current.session = internalcobra.Prepare(metadata, current.options)
|
||||
snapshot := current.app.routeSnapshot()
|
||||
if current.session == nil || current.snapshot != snapshot {
|
||||
current.snapshot = snapshot
|
||||
current.session = internalcobra.Prepare(snapshot.metadata, current.options)
|
||||
}
|
||||
return current.session
|
||||
}
|
||||
@@ -139,34 +141,6 @@ func normalizeStreams(streams Streams) Streams {
|
||||
return streams
|
||||
}
|
||||
|
||||
func (a *App) commandAt(path []string) (Command, bool) {
|
||||
if a == nil {
|
||||
return Command{}, false
|
||||
}
|
||||
if len(path) == 0 {
|
||||
return Command{}, true
|
||||
}
|
||||
command, ok := a.commands[path[0]]
|
||||
if !ok {
|
||||
return Command{}, false
|
||||
}
|
||||
current := command.command
|
||||
for _, name := range path[1:] {
|
||||
found := false
|
||||
for _, child := range current.record.children {
|
||||
if child.record != nil && child.record.name == name {
|
||||
current = child
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return Command{}, false
|
||||
}
|
||||
}
|
||||
return current, true
|
||||
}
|
||||
|
||||
func (a *App) present(outcome Outcome, path []string, streams Streams) Outcome {
|
||||
return a.presentWithUsageLine(outcome, path, streams, a.usageLine)
|
||||
}
|
||||
@@ -222,7 +196,7 @@ func (a *App) presentWithUsageLine(outcome Outcome, path []string, streams Strea
|
||||
|
||||
func (a *App) usageLine(path []string) string {
|
||||
if a != nil {
|
||||
if usage, failure := internalcobra.UsageLine(a.bridgeTree(), path); failure == nil {
|
||||
if usage, failure := internalcobra.UsageLine(a.routeSnapshot().metadata, path); failure == nil {
|
||||
return "Usage: " + usage
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user