Index backend commands for path lookup
This commit is contained in:
@@ -71,8 +71,9 @@ func RenderHelp(root *Command, path []string) (string, *Failure) {
|
||||
if err != nil {
|
||||
return "", &Failure{Message: err.Error()}
|
||||
}
|
||||
declaration := declarationFor(nodes, selected)
|
||||
if declaration == nil || len(remaining) != 0 || !equalPath(path, pathFor(root, declaration)) {
|
||||
declaration := nodes[selected]
|
||||
selectedPath, pathOK := pathFor(selected, nodes)
|
||||
if declaration == nil || !pathOK || len(remaining) != 0 || !equalPath(path, selectedPath) {
|
||||
return "", &Failure{Message: "help path is not registered"}
|
||||
}
|
||||
selected.SetOut(buffer)
|
||||
@@ -91,8 +92,9 @@ func UsageLine(root *Command, path []string) (string, *Failure) {
|
||||
options := normalizeOptions(ParseOptions{Context: context.Background(), In: strings.NewReader(""), Out: io.Discard, Err: io.Discard})
|
||||
backendRoot, nodes := buildTree(root, options)
|
||||
selected, remaining, err := backendRoot.Find(path)
|
||||
declaration := declarationFor(nodes, selected)
|
||||
if err != nil || declaration == nil || len(remaining) != 0 || !equalPath(path, pathFor(root, declaration)) {
|
||||
declaration := nodes[selected]
|
||||
selectedPath, pathOK := pathFor(selected, nodes)
|
||||
if err != nil || declaration == nil || !pathOK || len(remaining) != 0 || !equalPath(path, selectedPath) {
|
||||
return "", &Failure{Message: "usage path is not registered"}
|
||||
}
|
||||
line := selected.UseLine()
|
||||
@@ -128,11 +130,15 @@ func Parse(root *Command, argv []string, options ParseOptions) Result {
|
||||
if selected == nil {
|
||||
return failure(result, "no command was selected")
|
||||
}
|
||||
selectedNode := declarationFor(nodes, selected)
|
||||
selectedNode := nodes[selected]
|
||||
if selectedNode == nil {
|
||||
return failure(result, "selected command is not part of the declared tree")
|
||||
}
|
||||
result.Path = pathFor(root, selectedNode)
|
||||
var pathOK bool
|
||||
result.Path, pathOK = pathFor(selected, nodes)
|
||||
if !pathOK {
|
||||
return failure(result, "selected command is not part of the declared tree")
|
||||
}
|
||||
consumed := len(leading) - len(unconsumed)
|
||||
if consumed != len(result.Path) || !equalPath(leading[:consumed], result.Path) {
|
||||
return failure(result, "command path must match a registered command exactly")
|
||||
@@ -180,8 +186,8 @@ func normalizeOptions(options ParseOptions) ParseOptions {
|
||||
return options
|
||||
}
|
||||
|
||||
func buildTree(root *Command, options ParseOptions) (*spfcobra.Command, map[*Command]*spfcobra.Command) {
|
||||
nodes := make(map[*Command]*spfcobra.Command)
|
||||
func buildTree(root *Command, options ParseOptions) (*spfcobra.Command, map[*spfcobra.Command]*Command) {
|
||||
nodes := make(map[*spfcobra.Command]*Command)
|
||||
var build func(*Command) *spfcobra.Command
|
||||
build = func(declaration *Command) *spfcobra.Command {
|
||||
backend := &spfcobra.Command{
|
||||
@@ -223,7 +229,7 @@ func buildTree(root *Command, options ParseOptions) (*spfcobra.Command, map[*Com
|
||||
// Cobra's automatic help flag is suppressed because CommandKit declares
|
||||
// and interprets the local help flag itself.
|
||||
backend.SetHelpCommand(nil)
|
||||
nodes[declaration] = backend
|
||||
nodes[backend] = declaration
|
||||
for _, child := range declaration.Children {
|
||||
backend.AddCommand(build(child))
|
||||
}
|
||||
@@ -320,15 +326,6 @@ func equalPath(left, right []string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func declarationFor(nodes map[*Command]*spfcobra.Command, selected *spfcobra.Command) *Command {
|
||||
for declaration, backend := range nodes {
|
||||
if backend == selected {
|
||||
return declaration
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func splitRoutingPrefix(argv []string) ([]string, []string) {
|
||||
for index, argument := range argv {
|
||||
if argument == "--" || (strings.HasPrefix(argument, "-") && argument != "-") {
|
||||
@@ -338,29 +335,21 @@ func splitRoutingPrefix(argv []string) ([]string, []string) {
|
||||
return append([]string(nil), argv...), nil
|
||||
}
|
||||
|
||||
func pathFor(root, selected *Command) []string {
|
||||
func pathFor(selected *spfcobra.Command, declarations map[*spfcobra.Command]*Command) ([]string, bool) {
|
||||
var reverse []string
|
||||
for current := selected; current != nil && current != root; {
|
||||
reverse = append(reverse, current.Name)
|
||||
current = parentOf(root, current)
|
||||
}
|
||||
path := make([]string, len(reverse))
|
||||
for index := range reverse {
|
||||
path[len(reverse)-index-1] = reverse[index]
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func parentOf(root, target *Command) *Command {
|
||||
for _, child := range root.Children {
|
||||
if child == target {
|
||||
return root
|
||||
for current := selected; current != nil; current = current.Parent() {
|
||||
declaration := declarations[current]
|
||||
if declaration == nil {
|
||||
return nil, false
|
||||
}
|
||||
if parent := parentOf(child, target); parent != nil {
|
||||
return parent
|
||||
if current.Parent() != nil {
|
||||
reverse = append(reverse, declaration.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
for left, right := 0, len(reverse)-1; left < right; left, right = left+1, right-1 {
|
||||
reverse[left], reverse[right] = reverse[right], reverse[left]
|
||||
}
|
||||
return reverse, true
|
||||
}
|
||||
|
||||
func failure(result Result, message string) Result {
|
||||
|
||||
Reference in New Issue
Block a user