From 0d9d1d77551da1d4e56ea4e3f69966bd009981a0 Mon Sep 17 00:00:00 2001 From: Greg Schueler Date: Fri, 27 Mar 2020 15:57:43 -0700 Subject: [PATCH 1/3] Update CommandInvoker --- .../java/org/rundeck/toolbelt/ToolBelt.java | 46 +++++----- .../org/rundeck/toolbelt/ToolBeltSpec.groovy | 89 +++++++++++++++++++ 2 files changed, 113 insertions(+), 22 deletions(-) diff --git a/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java b/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java index 31b641a..7b6a72e 100644 --- a/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java +++ b/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java @@ -403,11 +403,6 @@ public boolean isSolo() { return false; } - @Override - public boolean isDefault() { - return false; - } - public CommandSet(final CommandSet commandSet) { this.name = commandSet.name; this.commands = new HashMap<>(commandSet.commands); @@ -793,13 +788,14 @@ private void addCommandForParent(CommandSet parent, final Object instance) { isSub = true; } - boolean isHidden = false; + boolean isHidden = null != annotation1 && annotation1.isHidden(); Hidden annotation2 = aClass.getAnnotation(Hidden.class); if (null != annotation2) { isHidden = true; } - Method[] methods = aClass.getMethods(); String defInvoke = null; + + Method[] methods = aClass.getMethods(); for (Method method : methods) { Command annotation = method.getAnnotation(Command.class); if (annotation != null) { @@ -948,24 +944,36 @@ public CommandOutput defaultOutput() { } public static interface CommandInvoker { - String getName(); - - String getDescription(); + default String getName(){ + return this.getClass().getSimpleName().toLowerCase(); + } - boolean isSolo(); + default String getDescription(){ + return null; + } - boolean isDefault(); + default boolean isSolo(){ + return false; + } - boolean isHidden(); + default boolean isHidden(){ + return false; + } - Set getSynonyms(); + default Set getSynonyms(){ + return null; + } boolean run(String[] args) throws CommandRunFailure; - void getHelp(); + default void getHelp(){ + + } } - private static class MethodInvoker implements CommandInvoker { + private static class MethodInvoker + implements CommandInvoker + { private String name; private Set synonyms; Method method; @@ -973,7 +981,6 @@ private static class MethodInvoker implements CommandInvoker { private String description; private boolean solo; private boolean hidden; - private boolean isdefault; CommandContext context; MethodInvoker( @@ -1105,11 +1112,6 @@ public boolean isSolo() { return solo; } - @Override - public boolean isDefault() { - return isdefault; - } - @Override public boolean isHidden() { return hidden; diff --git a/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy b/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy index 2fdcb4c..0daf17b 100644 --- a/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy +++ b/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy @@ -488,4 +488,93 @@ class ToolBeltSpec extends Specification { 1 * myEh.handleError({ it instanceof MyError }, _) >> true } + + static class TestCH implements ToolBelt.CommandInvoker { + String[] sawArgs + boolean result + + @Override + boolean run(final String[] args) { + this.sawArgs = args + return result + } + String description; + boolean helped + + void getHelp() { + helped = true + } + } + + def "command handler handles all args"() { + given: + def sut = new TestCH() + sut.result = expect + + def output = new TestOutput() + def tool = ToolBelt.belt('test'). + add(sut). + commandOutput(output). + commandInput(new SimpleCommandInput()). + buckle() + when: + def result = tool.runMain((['testch'] + args) as String[], false) + + then: + output.output == [] + result == expect + sut.sawArgs == args + + where: + expect | args + true | [] + true | ['asdf'] + false | [] + false | ['asdf'] + } + + def "command handler description"() { + given: + def sut = new TestCH() + sut.result = true + sut.description = expect + + def output = new TestOutput() + def tool = ToolBelt.belt('test'). + add(sut). + commandOutput(output). + defaultHelpCommands(). + commandInput(new SimpleCommandInput()). + buckle() + when: + def result = tool.runMain((['help']) as String[], false) + + then: + output.output.contains('Available commands:\n') + output.output.contains(' testch - ' + expect) + + where: + value | expect + null | '' + 'asdf' | 'asdf' + } + + def "command handler help"() { + given: + def sut = new TestCH() + sut.result = true + + def output = new TestOutput() + def tool = ToolBelt.belt('test'). + add(sut). + commandOutput(output). + defaultHelpCommands(). + commandInput(new SimpleCommandInput()). + buckle() + when: + def result = tool.runMain((['testch', 'help']) as String[], false) + + then: + sut.helped + } } From 723943184a4791bae89c44e291c7eab8bf9f840a Mon Sep 17 00:00:00 2001 From: Greg Schueler Date: Fri, 27 Mar 2020 16:33:20 -0700 Subject: [PATCH 2/3] Allow CommandInvoker objects to use SubCommand annotation --- .../java/org/rundeck/toolbelt/ToolBelt.java | 16 ++++---- .../org/rundeck/toolbelt/ToolBeltSpec.groovy | 37 +++++++++++++++++-- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java b/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java index 7b6a72e..bbc07b5 100644 --- a/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java +++ b/toolbelt/src/main/java/org/rundeck/toolbelt/ToolBelt.java @@ -673,14 +673,6 @@ public static List tail(final List args) { } private void introspect(final Object instance) { - if(instance instanceof CommandInvoker){ - CommandInvoker cmd=(CommandInvoker)instance; - commands.commands.put(cmd.getName(), cmd); - if(cmd.getSynonyms()!=null && cmd.getSynonyms().size()>0){ - cmd.getSynonyms().forEach(synonym -> commands.commandSynonyms.put(synonym, cmd)); - } - return; - } introspect(commands, instance); } @@ -767,6 +759,14 @@ public InvalidPath(final String message) { } private void addCommandForParent(CommandSet parent, final Object instance) { + if(instance instanceof CommandInvoker){ + CommandInvoker cmd=(CommandInvoker)instance; + parent.commands.put(cmd.getName(), cmd); + if(cmd.getSynonyms()!=null && cmd.getSynonyms().size()>0){ + cmd.getSynonyms().forEach(synonym -> parent.commandSynonyms.put(synonym, cmd)); + } + return; + } HashMap subCommands = new HashMap<>(); HashMap subSynonyms = new HashMap<>(); //look for methods diff --git a/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy b/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy index 0daf17b..f4519c0 100644 --- a/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy +++ b/toolbelt/src/test/groovy/org/rundeck/toolbelt/ToolBeltSpec.groovy @@ -506,7 +506,7 @@ class ToolBeltSpec extends Specification { } } - def "command handler handles all args"() { + def "invoke handler handles all args"() { given: def sut = new TestCH() sut.result = expect @@ -533,7 +533,38 @@ class ToolBeltSpec extends Specification { false | ['asdf'] } - def "command handler description"() { + @SubCommand(path = ['a', 'b'], descriptions = ['xyz', 'zyd']) + static class TestCH2 extends TestCH{ + + } + def "invoke handler subcommand handles all args"() { + given: + def sut = new TestCH2() + sut.result = expect + + def output = new TestOutput() + def tool = ToolBelt.belt('test'). + add(sut). + commandOutput(output). + commandInput(new SimpleCommandInput()). + buckle() + when: + def result = tool.runMain((['a', 'b', 'testch2'] + args) as String[], false) + + then: + output.output == [] + result == expect + sut.sawArgs == args + + where: + expect | args + true | [] + true | ['asdf'] + false | [] + false | ['asdf'] + } + + def "invoke handler description"() { given: def sut = new TestCH() sut.result = true @@ -559,7 +590,7 @@ class ToolBeltSpec extends Specification { 'asdf' | 'asdf' } - def "command handler help"() { + def "invoke handler help"() { given: def sut = new TestCH() sut.result = true From cac17b1a634c17abe646807e4191f896d28ec166 Mon Sep 17 00:00:00 2001 From: Greg Schueler Date: Fri, 27 Mar 2020 16:36:29 -0700 Subject: [PATCH 3/3] cleanup: removed method --- .../main/groovy/org/rundeck/toolbelt/groovy/Toolbelt.groovy | 5 ----- 1 file changed, 5 deletions(-) diff --git a/toolbelt-groovy/src/main/groovy/org/rundeck/toolbelt/groovy/Toolbelt.groovy b/toolbelt-groovy/src/main/groovy/org/rundeck/toolbelt/groovy/Toolbelt.groovy index f2557d1..e81f998 100644 --- a/toolbelt-groovy/src/main/groovy/org/rundeck/toolbelt/groovy/Toolbelt.groovy +++ b/toolbelt-groovy/src/main/groovy/org/rundeck/toolbelt/groovy/Toolbelt.groovy @@ -112,11 +112,6 @@ class Toolbelt { return false } - @Override - boolean isDefault() { - return false - } - @Override boolean run(final String[] args) throws CommandRunFailure, InputError { Map params = [:]