130 lines
4.0 KiB
Go
130 lines
4.0 KiB
Go
package commandkit
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
|
|
internalcobra "gitea.maximumdirect.net/eric/CommandKit/internal/cobra"
|
|
commandmeta "gitea.maximumdirect.net/eric/CommandKit/internal/commandmeta"
|
|
"gitea.maximumdirect.net/eric/CommandKit/internal/commandpath"
|
|
)
|
|
|
|
func (a *App) parse(args []string, options commandmeta.ParseOptions) commandmeta.Result {
|
|
if a == nil {
|
|
return commandmeta.Result{Failure: &commandmeta.Failure{Message: "cannot parse commands on a nil app"}}
|
|
}
|
|
result := internalcobra.Parse(a.routeSnapshot().metadata, args, options)
|
|
return reduceReportingOccurrences(result)
|
|
}
|
|
|
|
func reduceReportingOccurrences(result commandmeta.Result) commandmeta.Result {
|
|
selection := commandmeta.ReportingSelection{}
|
|
for index, occurrence := range result.FlagOccurrences {
|
|
if !commandmeta.IsReportingFlag(occurrence.Name) {
|
|
continue
|
|
}
|
|
enabled, err := strconv.ParseBool(occurrence.RawValue)
|
|
if err != nil {
|
|
result.FlagOccurrences = result.FlagOccurrences[:index+1]
|
|
result.Reporting = selection
|
|
result.Failure = &commandmeta.Failure{
|
|
Message: fmt.Sprintf("invalid boolean value %q for %s", occurrence.RawValue, occurrence.Spelling),
|
|
Usage: true,
|
|
}
|
|
return result
|
|
}
|
|
mode := commandmeta.ReportingModeNormal
|
|
switch occurrence.Name {
|
|
case "quiet":
|
|
mode = commandmeta.ReportingModeQuiet
|
|
case "verbose":
|
|
mode = commandmeta.ReportingModeVerbose
|
|
case "debug":
|
|
mode = commandmeta.ReportingModeDebug
|
|
case "progress":
|
|
selection.Progress = enabled
|
|
selection.ProgressSet = true
|
|
continue
|
|
}
|
|
if enabled {
|
|
selection.Mode = mode
|
|
} else if selection.Mode == mode {
|
|
selection.Mode = commandmeta.ReportingModeNormal
|
|
}
|
|
}
|
|
result.Reporting = selection
|
|
return result
|
|
}
|
|
|
|
func (a *App) routeSnapshot() *routingSnapshot {
|
|
if a == nil {
|
|
return nil
|
|
}
|
|
if a.snapshot == nil {
|
|
a.snapshot = a.buildRoutingSnapshot()
|
|
}
|
|
return a.snapshot
|
|
}
|
|
|
|
func (a *App) buildRoutingSnapshot() *routingSnapshot {
|
|
root := &commandmeta.Command{Name: a.identity.Name, CoreFlags: commandmeta.ReportingFlags()}
|
|
snapshot := &routingSnapshot{
|
|
metadata: root,
|
|
runners: make(map[commandmeta.Key]commandPayload),
|
|
aliases: a.aliases,
|
|
canonical: buildCanonicalTree(a.commands),
|
|
flagAliases: a.flagAliases,
|
|
discoveryFlags: a.discoveryFlags,
|
|
}
|
|
for _, rule := range a.routingRules {
|
|
if rule.record.kind != commandAliasRule {
|
|
continue
|
|
}
|
|
snapshot.commandAliases = append(snapshot.commandAliases, commandmeta.CommandAlias{
|
|
Source: []string(rule.record.sourcePath.Clone()),
|
|
Target: []string(snapshot.aliases.Resolve(rule.record.targetPath)),
|
|
})
|
|
}
|
|
sort.Slice(snapshot.commandAliases, func(i, j int) bool {
|
|
return commandpath.FromTokens(snapshot.commandAliases[i].Source).Key() < commandpath.FromTokens(snapshot.commandAliases[j].Source).Key()
|
|
})
|
|
names := make([]string, 0, len(a.commands))
|
|
for name := range a.commands {
|
|
names = append(names, name)
|
|
}
|
|
sort.Strings(names)
|
|
var key commandmeta.Key
|
|
for _, name := range names {
|
|
root.Children = append(root.Children, bridgeCommand(a.commands[name].command, snapshot, &key))
|
|
}
|
|
return snapshot
|
|
}
|
|
|
|
func bridgeCommand(command Command, snapshot *routingSnapshot, next *commandmeta.Key) *commandmeta.Command {
|
|
record := command.record
|
|
*next = *next + 1
|
|
declaration := &commandmeta.Command{
|
|
Key: *next,
|
|
Name: record.name,
|
|
Summary: record.summary,
|
|
Description: record.description,
|
|
CoreFlags: commandmeta.ReportingFlags(),
|
|
}
|
|
if record.payload != nil {
|
|
snapshot.runners[declaration.Key] = record.payload
|
|
declaration.Runnable = record.payload.hasRun()
|
|
declaration.Flags = record.payload.bridgeFlags()
|
|
declaration.Arguments = record.payload.bridgeArguments()
|
|
}
|
|
children := append([]Command(nil), record.children...)
|
|
sort.Slice(children, func(i, j int) bool { return children[i].record.name < children[j].record.name })
|
|
for _, child := range children {
|
|
if child.record == nil || child.record.absent {
|
|
continue
|
|
}
|
|
declaration.Children = append(declaration.Children, bridgeCommand(child, snapshot, next))
|
|
}
|
|
return declaration
|
|
}
|