public static boolean isBuiltInMixin(CommandSpec mixin) { String str = mixin.userObject().toString(); return "picocli.CommandLine.AutoHelpMixin".equals(str) || "picocli.CommandLine$AutoHelpMixin".equals(str); }
public static boolean isBuiltInSubcommand(CommandSpec subcommand) { String str = subcommand.userObject().toString(); return "picocli.CommandLine.HelpCommand".equals(str) || "picocli.CommandLine$HelpCommand".equals(str); }
public List<CommandSpec> commandHierarchies() { List<CommandSpec> result = new ArrayList<CommandSpec>(); for (CommandSpec cmd : commands) { String excludeReason = null; for (CommandSpec any : commands) { if (cmd != any && isNestedCommand(cmd, any)) { // TODO Exclude if nested in shared surrounding element excludeReason = "Excluding " + cmd + ": it is nested in " + any; break; } if (isBuiltInMixin(cmd) || isBuiltInSubcommand(cmd)) { excludeReason = "Excluding built-in " + cmd.userObject(); break; } } if (excludeReason == null) { result.add(cmd); } else { logger.info(excludeReason); } } return result; } }
void visitCommandSpec(CommandSpec spec) throws NoSuchFieldException, IllegalAccessException { if (spec.userObject() != null) { if (spec.userObject() instanceof Method) { Method method = (Method) spec.userObject(); ReflectedClass cls = getOrCreateClass(method.getDeclaringClass()); cls.addMethod(method.getName(), method.getParameterTypes()); } else if (Proxy.isProxyClass(spec.userObject().getClass())) { visitAnnotatedFields(spec.userObject().getClass());
private void printCommandSpec(CommandSpec spec, String label, PrintWriter pw, String initialIndent, String indent) { pw.printf("%s%n", label); pw.printf("%sname: '%s'%n", initialIndent, spec.name()); pw.printf("%saliases: %s%n", indent, Arrays.toString(spec.aliases())); pw.printf("%suserObject: %s%n", indent, spec.userObject()); pw.printf("%shelpCommand: %s%n", indent, spec.helpCommand()); pw.printf("%sdefaultValueProvider: %s%n", indent, spec.defaultValueProvider()); pw.printf("%sversionProvider: %s%n", indent, spec.versionProvider()); pw.printf("%sversion: %s%n", indent, Arrays.toString(spec.version())); List<OptionSpec> options = new ArrayList<OptionSpec>(spec.options()); Collections.sort(options, new Comparator<OptionSpec>() { public int compare(OptionSpec o1, OptionSpec o2) { return o1.shortestName().compareTo(o2.shortestName()); } }); printOptionList(options, pw, indent); printPositionalList(spec.positionalParameters(), pw, indent); printUnmatchedArgsBindingList(spec.unmatchedArgsBindings(), pw, indent); printMixinList(spec.mixins(), pw, indent); printUsageMessage(spec.usageMessage(), pw, indent); printParser(spec.parser(), pw, indent); printResourceBundle(spec.resourceBundle(), pw, indent); printSubcommandList(spec.subcommands(), pw, indent); }
@Test public void testAddMixinParsesOptionsAndParameters() throws UnsupportedEncodingException { @Command(sortOptions = false) class Receiver { @Option(names = {"-b", "--beta"}, description = "Receiver option") private int beta; @Parameters(description = "parameters from receiver") File[] receiverFiles; } CommandLine commandLine = new CommandLine(new Receiver()); InjectsOptionsAndParameters.MixMeIn mixin = new InjectsOptionsAndParameters.MixMeIn(); commandLine.addMixin("mixin", mixin); commandLine.parse("-a", "111", "-b", "222", "a", "b"); Receiver receiver = commandLine.getCommand(); assertEquals(222, receiver.beta); assertEquals(111, mixin.alpha); assertArrayEquals(new File[] {new File("a"), new File("b")}, receiver.receiverFiles); assertArrayEquals(new File[] {new File("a"), new File("b")}, mixin.files); assertSame(mixin, commandLine.getMixins().get("mixin")); assertSame(mixin, commandLine.getCommandSpec().mixins().get("mixin").userObject()); }
private static void initSubcommands(Command cmd, CommandSpec parent, IFactory factory) { for (Class<?> sub : cmd.subcommands()) { try { if (Help.class == sub) { throw new InitializationException(Help.class.getName() + " is not a valid subcommand. Did you mean " + HelpCommand.class.getName() + "?"); } CommandLine subcommandLine = toCommandLine(factory.create(sub), factory); parent.addSubcommand(subcommandName(sub), subcommandLine); initParentCommand(subcommandLine.getCommandSpec().userObject(), parent.userObject()); } catch (InitializationException ex) { throw ex; } catch (NoSuchMethodException ex) { throw new InitializationException("Cannot instantiate subcommand " + sub.getName() + ": the class has no constructor", ex); } catch (Exception ex) { throw new InitializationException("Could not instantiate and add subcommand " + sub.getName() + ": " + ex, ex); } } if (cmd.addMethodSubcommands() && !(parent.userObject() instanceof Method)) { parent.addMethodSubcommands(factory); } } static void initParentCommand(Object subcommand, Object parent) {
/** Registers a subcommand with the specified name and all specified aliases. See also {@link #addSubcommand(String, Object)}. * * * @param name the string to recognize on the command line as a subcommand * @param command the object to initialize with command line arguments following the subcommand name. * This may be a {@code CommandLine} instance with its own (nested) subcommands * @param aliases zero or more alias names that are also recognized on the command line as this subcommand * @return this CommandLine object, to allow method chaining * @since 3.1 * @see #addSubcommand(String, Object) */ public CommandLine addSubcommand(String name, Object command, String... aliases) { CommandLine subcommandLine = toCommandLine(command, factory); subcommandLine.getCommandSpec().aliases.addAll(Arrays.asList(aliases)); getCommandSpec().addSubcommand(name, subcommandLine); CommandLine.Model.CommandReflection.initParentCommand(subcommandLine.getCommandSpec().userObject(), getCommandSpec().userObject()); return this; } /** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance.
/** Reflects on the class of the {@linkplain #userObject() user object} and registers any command methods * (class methods annotated with {@code @Command}) as subcommands. * @param factory the factory used to create instances of subcommands, converters, etc., that are registered declaratively with annotation attributes * @return this {@link CommandSpec} object for method chaining * @see #addSubcommand(String, CommandLine) * @since 3.7.0 */ public CommandSpec addMethodSubcommands(IFactory factory) { if (userObject() instanceof Method) { throw new InitializationException("Cannot discover subcommand methods of this Command Method: " + userObject()); } for (Method method : getCommandMethods(userObject().getClass(), null)) { CommandLine cmd = new CommandLine(method, factory); addSubcommand(cmd.getCommandName(), cmd); } isAddMethodSubcommands = true; return this; }
@Test public void testMixinAnnotationCanBeRetrievedByAnnotationName() { @Command class MixMeIn {} @Command class Receiver { @Mixin(name = "aMixin") MixMeIn mixMeIn; } CommandLine commandLine = new CommandLine(new Receiver(), new InnerClassFactory(this)); assertFalse("mixin was registered", commandLine.getMixins().isEmpty()); assertTrue(commandLine.getMixins().get("aMixin") instanceof MixMeIn); Receiver receiver = commandLine.getCommand(); assertNotNull(receiver.mixMeIn); assertSame(receiver.mixMeIn, commandLine.getMixins().get("aMixin")); assertSame(receiver.mixMeIn, commandLine.getCommandSpec().mixins().get("aMixin").userObject()); }
@Test public void testAddMixinMustBeValidCommand_SubCommandMethod() { @Command class ValidMixin { // valid command because it has @Command annotation } @Command class Receiver { @Command void sub(@Mixin ValidMixin mixin) { } } CommandLine commandLine = new CommandLine(new Receiver(), new InnerClassFactory(this)); CommandSpec commandSpec = commandLine.getCommandSpec().subcommands().get("sub").getCommandSpec().mixins().get("arg0"); assertEquals(ValidMixin.class, commandSpec.userObject().getClass()); commandLine.addMixin("valid", new ValidMixin()); // no exception }
@Test public void testMixinAnnotationCanBeRetrievedByFieldName() { @Command class MixMeIn {} @Command class Receiver { @Mixin MixMeIn mixMeIn; } CommandLine commandLine = new CommandLine(new Receiver(), new InnerClassFactory(this)); assertFalse("mixin was registered", commandLine.getMixins().isEmpty()); assertTrue(commandLine.getMixins().get("mixMeIn") instanceof MixMeIn); Receiver receiver = commandLine.getCommand(); assertNotNull(receiver.mixMeIn); assertSame(receiver.mixMeIn, commandLine.getMixins().get("mixMeIn")); assertSame(receiver.mixMeIn, commandLine.getCommandSpec().mixins().get("mixMeIn").userObject()); }
private static boolean isCommandMethod(CommandSpec spec) { Object userObject = spec.userObject(); return userObject instanceof Method || userObject instanceof ExecutableElement; }
public AnnotatedCommandSourceGenerator(CommandSpec commandSpec) { this(commandSpec, extractPackageName(commandSpec.userObject())); } public AnnotatedCommandSourceGenerator(CommandSpec commandSpec, String outputPackage) {
@Test public void testAnnotateMethod_mixinParameterFirst() { Method m = CommandLine.getCommandMethods(UnannotatedClassWithMixinParameters.class, "mixinFirst").get(0); CommandLine cmd = new CommandLine(m); CommandSpec spec = cmd.getCommandSpec(); assertEquals(1, spec.mixins().size()); assertEquals(1, spec.positionalParameters().size()); assertEquals(3, spec.options().size()); spec = spec.mixins().get("arg0"); assertEquals(SomeMixin.class, spec.userObject().getClass()); }
@Test public void testAnnotateMethod_positionalAndMixinParameter() { Method m = CommandLine.getCommandMethods(UnannotatedClassWithMixinParameters.class, "posAndMixin").get(0); CommandLine cmd = new CommandLine(m); CommandSpec spec = cmd.getCommandSpec(); assertEquals(1, spec.mixins().size()); assertEquals(1, spec.positionalParameters().size()); spec = spec.mixins().get("arg1"); assertEquals(SomeMixin.class, spec.userObject().getClass()); }
public static boolean isNestedCommand(CommandSpec inner, CommandSpec outer) { Object innerUserObject = inner.userObject(); Object outerUserObject = outer.userObject(); return isNested(innerUserObject, outerUserObject); }
/** Returns the annotated user object that this {@code CommandLine} instance was constructed with. * @param <T> the type of the variable that the return value is being assigned to * @return the annotated object that this {@code CommandLine} instance was constructed with * @since 0.9.7 */ @SuppressWarnings("unchecked") public <T> T getCommand() { return (T) getCommandSpec().userObject(); }
@Test public void testAnnotateMethod_positionalAndOptionsAndMixinParameter() { Method m = CommandLine.getCommandMethods(UnannotatedClassWithMixinParameters.class, "posAndOptAndMixin").get(0); CommandLine cmd = new CommandLine(m); CommandSpec spec = cmd.getCommandSpec(); assertEquals(1, spec.mixins().size()); assertEquals(1, spec.positionalParameters().size()); assertEquals(3, spec.options().size()); spec = spec.mixins().get("arg2"); assertEquals(SomeMixin.class, spec.userObject().getClass()); }
@Test public void testAnnotateMethod_mixinParameter() { Method m = CommandLine.getCommandMethods(UnannotatedClassWithMixinParameters.class, "withMixin").get(0); CommandLine cmd = new CommandLine(m); CommandSpec spec = cmd.getCommandSpec(); assertEquals(1, spec.mixins().size()); spec = spec.mixins().get("arg0"); assertEquals(SomeMixin.class, spec.userObject().getClass()); }