diff --git a/spring-shell-core/src/main/java/org/springframework/shell/command/CommandOption.java b/spring-shell-core/src/main/java/org/springframework/shell/command/CommandOption.java index 77d50ebc..9079d1cd 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/command/CommandOption.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/command/CommandOption.java @@ -87,6 +87,13 @@ public interface CommandOption { */ int getArityMax(); + /** + * Gets a label. + * + * @return the label + */ + String getLabel(); + /** * Gets an instance of a default {@link CommandOption}. * @@ -96,7 +103,7 @@ public interface CommandOption { * @return default command option */ public static CommandOption of(String[] longNames, Character[] shortNames, String description) { - return of(longNames, shortNames, description, null, false, null, null, null, null); + return of(longNames, shortNames, description, null, false, null, null, null, null, null); } /** @@ -110,7 +117,7 @@ public interface CommandOption { */ public static CommandOption of(String[] longNames, Character[] shortNames, String description, ResolvableType type) { - return of(longNames, shortNames, description, type, false, null, null, null, null); + return of(longNames, shortNames, description, type, false, null, null, null, null, null); } /** @@ -125,12 +132,14 @@ public interface CommandOption { * @param position the position value * @param arityMin the min arity * @param arityMax the max arity + * @param label the label * @return default command option */ public static CommandOption of(String[] longNames, Character[] shortNames, String description, - ResolvableType type, boolean required, String defaultValue, Integer position, Integer arityMin, Integer arityMax) { + ResolvableType type, boolean required, String defaultValue, Integer position, Integer arityMin, + Integer arityMax, String label) { return new DefaultCommandOption(longNames, shortNames, description, type, required, defaultValue, position, - arityMin, arityMax); + arityMin, arityMax, label); } /** @@ -147,10 +156,11 @@ public interface CommandOption { private int position; private int arityMin; private int arityMax; + private String label; public DefaultCommandOption(String[] longNames, Character[] shortNames, String description, ResolvableType type, boolean required, String defaultValue, Integer position, - Integer arityMin, Integer arityMax) { + Integer arityMin, Integer arityMax, String label) { this.longNames = longNames != null ? longNames : new String[0]; this.shortNames = shortNames != null ? shortNames : new Character[0]; this.description = description; @@ -160,6 +170,7 @@ public interface CommandOption { this.position = position != null && position > -1 ? position : -1 ; this.arityMin = arityMin != null ? arityMin : -1; this.arityMax = arityMax != null ? arityMax : -1; + this.label = label; } @Override @@ -206,5 +217,10 @@ public interface CommandOption { public int getArityMax() { return arityMax; } + + @Override + public String getLabel() { + return label; + } } } diff --git a/spring-shell-core/src/main/java/org/springframework/shell/command/CommandRegistration.java b/spring-shell-core/src/main/java/org/springframework/shell/command/CommandRegistration.java index 0a6a56f3..11444c70 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/command/CommandRegistration.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/command/CommandRegistration.java @@ -200,6 +200,14 @@ public interface CommandRegistration { */ OptionSpec arity(OptionArity arity); + /** + * Define a {@code label} for an option. + * + * @param label the label + * @return option spec for chaining + */ + OptionSpec label(String label); + /** * Return a builder for chaining. * @@ -519,6 +527,7 @@ public interface CommandRegistration { private Integer position; private Integer arityMin; private Integer arityMax; + private String label; DefaultOptionSpec(BaseBuilder builder) { this.builder = builder; @@ -611,6 +620,12 @@ public interface CommandRegistration { return this; } + @Override + public OptionSpec label(String label) { + this.label = label; + return this; + } + @Override public Builder and() { return builder; @@ -651,6 +666,10 @@ public interface CommandRegistration { public Integer getArityMax() { return arityMax; } + + public String getLabel() { + return label; + } } static class DefaultTargetSpec implements TargetSpec { @@ -820,7 +839,8 @@ public interface CommandRegistration { public List getOptions() { return optionSpecs.stream() .map(o -> CommandOption.of(o.getLongNames(), o.getShortNames(), o.getDescription(), o.getType(), - o.isRequired(), o.getDefaultValue(), o.getPosition(), o.getArityMin(), o.getArityMax())) + o.isRequired(), o.getDefaultValue(), o.getPosition(), o.getArityMin(), o.getArityMax(), + o.getLabel())) .collect(Collectors.toList()); } diff --git a/spring-shell-core/src/test/java/org/springframework/shell/command/CommandParserTests.java b/spring-shell-core/src/test/java/org/springframework/shell/command/CommandParserTests.java index f15afaac..f3c36183 100644 --- a/spring-shell-core/src/test/java/org/springframework/shell/command/CommandParserTests.java +++ b/spring-shell-core/src/test/java/org/springframework/shell/command/CommandParserTests.java @@ -327,7 +327,7 @@ public class CommandParserTests extends AbstractCommandTests { public void testBooleanWithDefault() { ResolvableType type = ResolvableType.forType(boolean.class); CommandOption option1 = CommandOption.of(new String[] { "arg1" }, new Character[0], "description", type, false, - "true", null, null, null); + "true", null, null, null, null); List options = Arrays.asList(option1); String[] args = new String[]{}; @@ -359,7 +359,7 @@ public class CommandParserTests extends AbstractCommandTests { private static CommandOption longOption(String name, ResolvableType type, boolean required, Integer position, Integer arityMin, Integer arityMax) { return CommandOption.of(new String[] { name }, new Character[0], "desc", type, required, null, position, - arityMin, arityMax); + arityMin, arityMax, null); } private static CommandOption shortOption(char name) { diff --git a/spring-shell-core/src/test/java/org/springframework/shell/command/CommandRegistrationTests.java b/spring-shell-core/src/test/java/org/springframework/shell/command/CommandRegistrationTests.java index a1b376f8..58788123 100644 --- a/spring-shell-core/src/test/java/org/springframework/shell/command/CommandRegistrationTests.java +++ b/spring-shell-core/src/test/java/org/springframework/shell/command/CommandRegistrationTests.java @@ -195,6 +195,7 @@ public class CommandRegistrationTests extends AbstractCommandTests { .shortNames('v') .type(boolean.class) .description("some arg1") + .label("mylabel") .and() .withTarget() .function(function1) @@ -205,6 +206,7 @@ public class CommandRegistrationTests extends AbstractCommandTests { assertThat(registration.getOptions()).hasSize(1); assertThat(registration.getOptions().get(0).getShortNames()).containsExactly('v'); assertThat(registration.getOptions().get(0).getType()).isEqualTo(ResolvableType.forType(boolean.class)); + assertThat(registration.getOptions().get(0).getLabel()).isEqualTo("mylabel"); } @Test diff --git a/spring-shell-samples/src/main/java/org/springframework/shell/samples/e2e/OptionTypeCommands.java b/spring-shell-samples/src/main/java/org/springframework/shell/samples/e2e/OptionTypeCommands.java new file mode 100644 index 00000000..3b53116d --- /dev/null +++ b/spring-shell-samples/src/main/java/org/springframework/shell/samples/e2e/OptionTypeCommands.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.shell.samples.e2e; + +import org.springframework.context.annotation.Bean; +import org.springframework.shell.command.CommandRegistration; +import org.springframework.shell.standard.ShellComponent; + +/** + * Commands used for e2e test. + * + * @author Janne Valkealahti + */ +@ShellComponent +public class OptionTypeCommands extends BaseE2ECommands { + + @Bean + public CommandRegistration testOptionTypeRegistration() { + return CommandRegistration.builder() + .command(REG, "option-type") + .group(GROUP) + .withOption() + .longNames("arg1") + .and() + .withOption() + .longNames("arg2") + .type(String.class) + .and() + .withOption() + .longNames("arg3") + .type(int.class) + .and() + .withOption() + .longNames("arg4") + .label("MYLABEL") + .and() + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + } + +} diff --git a/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java b/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java index e256871f..c6e27737 100644 --- a/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java +++ b/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java @@ -22,6 +22,7 @@ import java.util.stream.Stream; import org.springframework.shell.command.CommandOption; import org.springframework.shell.command.CommandRegistration; import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; /** * Model encapsulating info about {@code command}. @@ -51,7 +52,7 @@ class CommandInfoModel { List options = registration.getOptions(); List parameters = options.stream() .map(o -> { - String type = o.getType() == null ? "String" : ClassUtils.getShortName(o.getType().getRawClass()); + String type = commandOptionType(o); List arguments = Stream.concat( Stream.of(o.getLongNames()).map(a -> "--" + a), Stream.of(o.getShortNames()).map(s -> "-" + s)) @@ -67,6 +68,15 @@ class CommandInfoModel { return new CommandInfoModel(name, description, parameters); } + private static String commandOptionType(CommandOption o) { + if (StringUtils.hasText(o.getLabel())) { + return o.getLabel(); + } + else { + return o.getType() == null ? "String" : ClassUtils.getShortName(o.getType().getRawClass()); + } + } + public String getName() { return name; }