Split sample app
- spring-shell-sample-commands and spring-shell-sample-e2e - Needed changes in e2e tests and workflow - Fixes #754
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2017-2023 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;
|
||||
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
|
||||
import org.springframework.boot.Banner.Mode;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.command.annotation.CommandScan;
|
||||
import org.springframework.shell.jline.PromptProvider;
|
||||
|
||||
/**
|
||||
* Main entry point for the application.
|
||||
*
|
||||
* <p>Creates the application context and start the REPL.</p>
|
||||
*
|
||||
* @author Eric Bottard
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@CommandScan
|
||||
public class SpringShellSample {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication application = new SpringApplication(SpringShellSample.class);
|
||||
application.setBannerMode(Mode.OFF);
|
||||
application.run(args);
|
||||
// TODO: follow up with boot why spring.main.banner-mode=off doesn't work
|
||||
// SpringApplication.run(SpringShellSample.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PromptProvider myPromptProvider() {
|
||||
return () -> new AttributedString("my-shell:>", AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
|
||||
@ShellComponent
|
||||
public class AliasCommands {
|
||||
|
||||
private final static String DESCRIPTION = "main1 with main2 as alias";
|
||||
|
||||
@ShellMethod(key = { "alias anno main1", "alias anno main2" }, group = "Alias Commands", value = DESCRIPTION)
|
||||
public String annoMain1() {
|
||||
return "Hello annoMain1";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration regMain1() {
|
||||
return CommandRegistration.builder()
|
||||
.command("alias", "reg", "main1")
|
||||
.group("Alias Commands")
|
||||
.description(DESCRIPTION)
|
||||
.withAlias()
|
||||
.command("alias", "reg", "main2")
|
||||
.group("Alias Commands")
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
return "Hello regMain1";
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2015-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.standard;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
|
||||
/**
|
||||
* Example commands for the Shell 2 Standard resolver.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
@ShellComponent()
|
||||
public class Commands {
|
||||
|
||||
@ShellMethod(value = "A command whose name looks the same as another one.", key = "help me out")
|
||||
public void helpMeOut() {
|
||||
System.out.println("You can go");
|
||||
}
|
||||
|
||||
@ShellMethod("Change Password. Shows support for bean validation.")
|
||||
public String changePassword(@Size(min = 8) String password) {
|
||||
return "Password changed";
|
||||
}
|
||||
|
||||
@ShellMethod(value = "Shows non trivial character encoding.")
|
||||
public String helloWorld() {
|
||||
return "こんにちは世界";
|
||||
}
|
||||
|
||||
@ShellMethod("Shows support for boolean parameters, with arity=0.")
|
||||
public void shutdown(@ShellOption(arity = 0) boolean force) {
|
||||
System.out.println("You passed " + force);
|
||||
}
|
||||
|
||||
@ShellMethod("Add numbers.")
|
||||
public int add(int a, int b, int c) {
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
@ShellMethod("Concat strings.")
|
||||
public String concat(String a, String b, String c) {
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
@ShellMethod("Fails with an exception. Shows enum conversion.")
|
||||
public void fail(ElementType elementType) {
|
||||
throw new IllegalArgumentException("You said " + elementType);
|
||||
}
|
||||
|
||||
@ShellMethod("Add array numbers.")
|
||||
public double addDoubles(@ShellOption(arity = 3) double[] numbers) {
|
||||
return Arrays.stream(numbers).sum();
|
||||
}
|
||||
|
||||
@ShellMethod("Get iterables.")
|
||||
public Iterable<String> iterables() {
|
||||
List<String> list = Arrays.asList("first", "second");
|
||||
Iterable<String> iterable = new Iterable<String>() {
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
};
|
||||
return iterable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.CompletionContext;
|
||||
import org.springframework.shell.CompletionProposal;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.standard.EnumValueProvider;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
import org.springframework.shell.standard.ValueProvider;
|
||||
|
||||
@ShellComponent
|
||||
public class CompleteCommands {
|
||||
|
||||
@Bean
|
||||
CommandRegistration completeCommandRegistration1() {
|
||||
return CommandRegistration.builder()
|
||||
.command("complete", "sample1")
|
||||
.description("complete sample1")
|
||||
.group("Complete Commands")
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.completion(ctx -> {
|
||||
CompletionProposal p1 = new CompletionProposal("arg1hi1");
|
||||
CompletionProposal p2 = new CompletionProposal("arg1hi2");
|
||||
return Arrays.asList(p1, p2);
|
||||
})
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg2")
|
||||
.completion(ctx -> {
|
||||
CompletionProposal p1 = new CompletionProposal("arg2hi1");
|
||||
CompletionProposal p2 = new CompletionProposal("arg2hi2");
|
||||
return Arrays.asList(p1, p2);
|
||||
})
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
String arg1 = ctx.getOptionValue("arg1");
|
||||
return String.format("hi, arg1 value is '%s'", arg1);
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@ShellMethod(value = "complete sample2", key = "complete sample2")
|
||||
public String completeCommandSample2(@ShellOption(valueProvider = FunnyValuesProvider.class) String arg1) {
|
||||
return "You said " + arg1;
|
||||
}
|
||||
|
||||
@Bean
|
||||
FunnyValuesProvider funnyValuesProvider() {
|
||||
return new FunnyValuesProvider();
|
||||
}
|
||||
|
||||
static class FunnyValuesProvider implements ValueProvider {
|
||||
|
||||
private final static String[] VALUES = new String[] {
|
||||
"hello world",
|
||||
"I am quoting \"The Daily Mail\"",
|
||||
"10 \\ 3 = 3"
|
||||
};
|
||||
|
||||
@Override
|
||||
public List<CompletionProposal> complete(CompletionContext completionContext) {
|
||||
return Arrays.stream(VALUES).map(CompletionProposal::new).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
CommandRegistration completeCommandRegistration3() {
|
||||
return CommandRegistration.builder()
|
||||
.command("complete", "sample3")
|
||||
.description("complete sample3")
|
||||
.group("Complete Commands")
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.type(MyEnums.class)
|
||||
.completion(ctx -> {
|
||||
CompletionProposal p1 = new CompletionProposal(MyEnums.E1.toString());
|
||||
CompletionProposal p2 = new CompletionProposal(MyEnums.E2.toString());
|
||||
CompletionProposal p3 = new CompletionProposal(MyEnums.E3.toString());
|
||||
return Arrays.asList(p1, p2, p3);
|
||||
})
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
String arg1 = ctx.getOptionValue("arg1");
|
||||
return String.format("You said '%s'", arg1);
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@ShellMethod(value = "complete sample4", key = "complete sample4")
|
||||
public String completeCommandSample4(@ShellOption(valueProvider = EnumValueProvider.class) MyEnums arg1) {
|
||||
return "You said " + arg1;
|
||||
}
|
||||
|
||||
static enum MyEnums {
|
||||
E1, E2, E3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
|
||||
import org.springframework.shell.component.ConfirmationInput;
|
||||
import org.springframework.shell.component.ConfirmationInput.ConfirmationInputContext;
|
||||
import org.springframework.shell.component.MultiItemSelector;
|
||||
import org.springframework.shell.component.MultiItemSelector.MultiItemSelectorContext;
|
||||
import org.springframework.shell.component.PathInput;
|
||||
import org.springframework.shell.component.PathSearch;
|
||||
import org.springframework.shell.component.PathInput.PathInputContext;
|
||||
import org.springframework.shell.component.PathSearch.PathSearchConfig;
|
||||
import org.springframework.shell.component.PathSearch.PathSearchContext;
|
||||
import org.springframework.shell.component.SingleItemSelector;
|
||||
import org.springframework.shell.component.SingleItemSelector.SingleItemSelectorContext;
|
||||
import org.springframework.shell.component.StringInput;
|
||||
import org.springframework.shell.component.StringInput.StringInputContext;
|
||||
import org.springframework.shell.component.support.SelectorItem;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ShellComponent
|
||||
public class ComponentCommands extends AbstractShellComponent {
|
||||
|
||||
@ShellMethod(key = "component string", value = "String input", group = "Components")
|
||||
public String stringInput(boolean mask) {
|
||||
StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue");
|
||||
component.setResourceLoader(getResourceLoader());
|
||||
component.setTemplateExecutor(getTemplateExecutor());
|
||||
if (mask) {
|
||||
component.setMaskCharacter('*');
|
||||
}
|
||||
StringInputContext context = component.run(StringInputContext.empty());
|
||||
return "Got value " + context.getResultValue();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "component path input", value = "Path input", group = "Components")
|
||||
public String pathInput() {
|
||||
PathInput component = new PathInput(getTerminal(), "Enter value");
|
||||
component.setResourceLoader(getResourceLoader());
|
||||
component.setTemplateExecutor(getTemplateExecutor());
|
||||
PathInputContext context = component.run(PathInputContext.empty());
|
||||
return "Got value " + context.getResultValue();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "component path search", value = "Path search", group = "Components")
|
||||
public String pathSearch(
|
||||
@ShellOption(defaultValue = ShellOption.NULL) Integer maxPathsShow,
|
||||
@ShellOption(defaultValue = ShellOption.NULL) Integer maxPathsSearch,
|
||||
@ShellOption(defaultValue = "true") boolean searchForward,
|
||||
@ShellOption(defaultValue = "false") boolean searchCaseSensitive,
|
||||
@ShellOption(defaultValue = "false") boolean searchNormalize
|
||||
) {
|
||||
PathSearchConfig config = new PathSearch.PathSearchConfig();
|
||||
if (maxPathsShow != null) {
|
||||
config.setMaxPathsShow(maxPathsShow);
|
||||
}
|
||||
if (maxPathsSearch != null) {
|
||||
config.setMaxPathsSearch(maxPathsSearch);
|
||||
}
|
||||
config.setSearchForward(searchForward);
|
||||
config.setSearchCaseSensitive(searchCaseSensitive);
|
||||
config.setSearchNormalize(searchNormalize);
|
||||
PathSearch component = new PathSearch(getTerminal(), "Enter value", config);
|
||||
component.setResourceLoader(getResourceLoader());
|
||||
component.setTemplateExecutor(getTemplateExecutor());
|
||||
PathSearchContext context = component.run(PathSearchContext.empty());
|
||||
return "Got value " + context.getResultValue();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "component confirmation", value = "Confirmation input", group = "Components")
|
||||
public String confirmationInput(boolean no) {
|
||||
ConfirmationInput component = new ConfirmationInput(getTerminal(), "Enter value", !no);
|
||||
component.setResourceLoader(getResourceLoader());
|
||||
component.setTemplateExecutor(getTemplateExecutor());
|
||||
ConfirmationInputContext context = component.run(ConfirmationInputContext.empty());
|
||||
return "Got value " + context.getResultValue();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "component single", value = "Single selector", group = "Components")
|
||||
public String singleSelector(
|
||||
@ShellOption(defaultValue = ShellOption.NULL) Boolean longKeys
|
||||
) {
|
||||
List<SelectorItem<String>> items = new ArrayList<>();
|
||||
items.add(SelectorItem.of("key1", "value1"));
|
||||
items.add(SelectorItem.of("key2", "value2"));
|
||||
if (longKeys != null && longKeys == true) {
|
||||
items.add(SelectorItem.of("key3 long long long long long", "value3"));
|
||||
items.add(SelectorItem.of("key4 long long long long long long long long long long", "value4"));
|
||||
}
|
||||
SingleItemSelector<String, SelectorItem<String>> component = new SingleItemSelector<>(getTerminal(),
|
||||
items, "testSimple", null);
|
||||
component.setResourceLoader(getResourceLoader());
|
||||
component.setTemplateExecutor(getTemplateExecutor());
|
||||
SingleItemSelectorContext<String, SelectorItem<String>> context = component
|
||||
.run(SingleItemSelectorContext.empty());
|
||||
String result = context.getResultItem().flatMap(si -> Optional.ofNullable(si.getItem())).get();
|
||||
return "Got value " + result;
|
||||
}
|
||||
|
||||
@ShellMethod(key = "component multi", value = "Multi selector", group = "Components")
|
||||
public String multiSelector(
|
||||
@ShellOption(defaultValue = ShellOption.NULL) Boolean longKeys
|
||||
) {
|
||||
List<SelectorItem<String>> items = new ArrayList<>();
|
||||
items.add(SelectorItem.of("key1", "value1"));
|
||||
items.add(SelectorItem.of("key2", "value2", false, true));
|
||||
items.add(SelectorItem.of("key3", "value3"));
|
||||
if (longKeys != null && longKeys == true) {
|
||||
items.add(SelectorItem.of("key4 long long long long long", "value4", false, true));
|
||||
items.add(SelectorItem.of("key5 long long long long long long long long long long", "value5"));
|
||||
}
|
||||
MultiItemSelector<String, SelectorItem<String>> component = new MultiItemSelector<>(getTerminal(),
|
||||
items, "testSimple", null);
|
||||
component.setResourceLoader(getResourceLoader());
|
||||
component.setTemplateExecutor(getTemplateExecutor());
|
||||
MultiItemSelectorContext<String, SelectorItem<String>> context = component
|
||||
.run(MultiItemSelectorContext.empty());
|
||||
String result = context.getResultItems().stream()
|
||||
.map(si -> si.getItem())
|
||||
.collect(Collectors.joining(","));
|
||||
return "Got value " + result;
|
||||
}
|
||||
|
||||
@ShellMethod(key = "component stringcustom", value = "String input", group = "Components")
|
||||
public String stringInputCustom(boolean mask) {
|
||||
StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue",
|
||||
new StringInputCustomRenderer());
|
||||
component.setResourceLoader(getResourceLoader());
|
||||
component.setTemplateExecutor(getTemplateExecutor());
|
||||
if (mask) {
|
||||
component.setMaskCharacter('*');
|
||||
}
|
||||
StringInputContext context = component.run(StringInputContext.empty());
|
||||
return "Got value " + context.getResultValue();
|
||||
}
|
||||
|
||||
private static class StringInputCustomRenderer implements Function<StringInputContext, List<AttributedString>> {
|
||||
|
||||
@Override
|
||||
public List<AttributedString> apply(StringInputContext context) {
|
||||
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||
builder.append(context.getName());
|
||||
builder.append(" ");
|
||||
|
||||
if (context.getResultValue() != null) {
|
||||
builder.append(context.getResultValue());
|
||||
}
|
||||
else {
|
||||
String input = context.getInput();
|
||||
if (StringUtils.hasText(input)) {
|
||||
builder.append(input);
|
||||
}
|
||||
else {
|
||||
builder.append("[Default " + context.getDefaultValue() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.asList(builder.toAttributedString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.jline.terminal.impl.DumbTerminal;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.command.CommandExecution.CommandParserExceptionsException;
|
||||
import org.springframework.shell.command.CommandParser;
|
||||
import org.springframework.shell.command.CommandParser.CommandParserException;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.component.flow.ComponentFlow;
|
||||
import org.springframework.shell.component.flow.ComponentFlow.ComponentFlowResult;
|
||||
import org.springframework.shell.component.flow.ResultMode;
|
||||
import org.springframework.shell.component.flow.SelectItem;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ShellComponent
|
||||
public class ComponentFlowCommands extends AbstractShellComponent {
|
||||
|
||||
@Autowired
|
||||
private ComponentFlow.Builder componentFlowBuilder;
|
||||
|
||||
@ShellMethod(key = "flow showcase1", value = "Showcase", group = "Flow")
|
||||
public void showcase1() {
|
||||
Map<String, String> single1SelectItems = new HashMap<>();
|
||||
single1SelectItems.put("key1", "value1");
|
||||
single1SelectItems.put("key2", "value2");
|
||||
List<SelectItem> multi1SelectItems = Arrays.asList(SelectItem.of("key1", "value1"),
|
||||
SelectItem.of("key2", "value2"), SelectItem.of("key3", "value3"));
|
||||
ComponentFlow flow = componentFlowBuilder.clone().reset()
|
||||
.withStringInput("field1")
|
||||
.name("Field1")
|
||||
.defaultValue("defaultField1Value")
|
||||
.and()
|
||||
.withStringInput("field2")
|
||||
.name("Field2")
|
||||
.and()
|
||||
.withConfirmationInput("confirmation1")
|
||||
.name("Confirmation1")
|
||||
.and()
|
||||
.withPathInput("path1")
|
||||
.name("Path1")
|
||||
.and()
|
||||
.withSingleItemSelector("single1")
|
||||
.name("Single1")
|
||||
.selectItems(single1SelectItems)
|
||||
.and()
|
||||
.withMultiItemSelector("multi1")
|
||||
.name("Multi1")
|
||||
.selectItems(multi1SelectItems)
|
||||
.and()
|
||||
.build();
|
||||
flow.run();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "flow showcase2", value = "Showcase with options", group = "Flow")
|
||||
public String showcase2(
|
||||
@ShellOption(help = "Field1 value", defaultValue = ShellOption.NULL) String field1,
|
||||
@ShellOption(help = "Field2 value", defaultValue = ShellOption.NULL) String field2,
|
||||
@ShellOption(help = "Confirmation1 value", defaultValue = ShellOption.NULL) Boolean confirmation1,
|
||||
@ShellOption(help = "Path1 value", defaultValue = ShellOption.NULL) String path1,
|
||||
@ShellOption(help = "Single1 value", defaultValue = ShellOption.NULL) String single1,
|
||||
@ShellOption(help = "Multi1 value", defaultValue = ShellOption.NULL) List<String> multi1
|
||||
) {
|
||||
Map<String, String> single1SelectItems = new HashMap<>();
|
||||
single1SelectItems.put("key1", "value1");
|
||||
single1SelectItems.put("key2", "value2");
|
||||
List<SelectItem> multi1SelectItems = Arrays.asList(SelectItem.of("key1", "value1"),
|
||||
SelectItem.of("key2", "value2"), SelectItem.of("key3", "value3"));
|
||||
List<String> multi1ResultValues = multi1 != null ? multi1 : new ArrayList<>();
|
||||
ComponentFlow flow = componentFlowBuilder.clone().reset()
|
||||
.withStringInput("field1")
|
||||
.name("Field1")
|
||||
.defaultValue("defaultField1Value")
|
||||
.resultValue(field1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withStringInput("field2")
|
||||
.name("Field2")
|
||||
.resultValue(field2)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withConfirmationInput("confirmation1")
|
||||
.name("Confirmation1")
|
||||
.resultValue(confirmation1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withPathInput("path1")
|
||||
.name("Path1")
|
||||
.resultValue(path1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withSingleItemSelector("single1")
|
||||
.name("Single1")
|
||||
.selectItems(single1SelectItems)
|
||||
.resultValue(single1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withMultiItemSelector("multi1")
|
||||
.name("Multi1")
|
||||
.selectItems(multi1SelectItems)
|
||||
.resultValues(multi1ResultValues)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.build();
|
||||
ComponentFlowResult result = flow.run();
|
||||
StringBuilder buf = new StringBuilder();
|
||||
result.getContext().stream().forEach(e -> {
|
||||
buf.append(e.getKey());
|
||||
buf.append(" = ");
|
||||
buf.append(e.getValue());
|
||||
buf.append("\n");
|
||||
});
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration showcaseRegistration() {
|
||||
return CommandRegistration.builder()
|
||||
.command("flow", "showcase3")
|
||||
.description("Showcase")
|
||||
.withOption()
|
||||
.longNames("field1")
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("field2")
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("confirmation1")
|
||||
.type(Boolean.class)
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("path1")
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("single1")
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("multi1")
|
||||
.and()
|
||||
.withTarget()
|
||||
.consumer(ctx -> {
|
||||
|
||||
String field1 = ctx.getOptionValue("field1");
|
||||
String field2 = ctx.getOptionValue("field2");
|
||||
Boolean confirmation1 = ctx.getOptionValue("confirmation1");
|
||||
String path1 = ctx.getOptionValue("path1");
|
||||
String single1 = ctx.getOptionValue("single1");
|
||||
String asdf = ctx.getOptionValue("multi1");
|
||||
List<String> multi1 = new ArrayList<>();
|
||||
if (StringUtils.hasText(asdf)) {
|
||||
multi1.add(asdf);
|
||||
}
|
||||
|
||||
Map<String, String> single1SelectItems = new HashMap<>();
|
||||
single1SelectItems.put("key1", "value1");
|
||||
single1SelectItems.put("key2", "value2");
|
||||
List<SelectItem> multi1SelectItems = Arrays.asList(SelectItem.of("key1", "value1"),
|
||||
SelectItem.of("key2", "value2"), SelectItem.of("key3", "value3"));
|
||||
ComponentFlow flow = componentFlowBuilder.clone().reset()
|
||||
.withStringInput("field1")
|
||||
.name("Field1")
|
||||
.defaultValue("defaultField1Value")
|
||||
.resultValue(field1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withStringInput("field2")
|
||||
.name("Field2")
|
||||
.resultValue(field2)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withConfirmationInput("confirmation1")
|
||||
.name("Confirmation1")
|
||||
.resultValue(confirmation1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withPathInput("path1")
|
||||
.name("Path1")
|
||||
.resultValue(path1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withSingleItemSelector("single1")
|
||||
.name("Single1")
|
||||
.selectItems(single1SelectItems)
|
||||
.resultValue(single1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.withMultiItemSelector("multi1")
|
||||
.name("Multi1")
|
||||
.selectItems(multi1SelectItems)
|
||||
.resultValues(multi1)
|
||||
.resultMode(ResultMode.ACCEPT)
|
||||
.and()
|
||||
.build();
|
||||
ComponentFlowResult result = flow.run();
|
||||
|
||||
boolean hasTty = !((ctx.getTerminal() instanceof DumbTerminal) && ctx.getTerminal().getSize().getRows() == 0);
|
||||
if (hasTty) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
result.getContext().stream().forEach(e -> {
|
||||
buf.append(e.getKey());
|
||||
buf.append(" = ");
|
||||
buf.append(e.getValue());
|
||||
buf.append("\n");
|
||||
});
|
||||
ctx.getTerminal().writer().print(buf.toString());
|
||||
ctx.getTerminal().writer().flush();
|
||||
}
|
||||
else {
|
||||
List<CommandParser.CommandParserException> errors = new ArrayList<>();
|
||||
result.getContext().stream().forEach(e -> {
|
||||
if (e.getValue() == null) {
|
||||
errors.add(CommandParserException.of(String.format("Missing option, longnames='%s'", e.getKey())));
|
||||
}
|
||||
});
|
||||
if (!result.getContext().containsKey("single1")) {
|
||||
errors.add(CommandParserException.of("Missing option, longnames='single'"));
|
||||
}
|
||||
if (!errors.isEmpty()) {
|
||||
throw CommandParserExceptionsException.of("Missing options", errors);
|
||||
}
|
||||
}
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "flow conditional", value = "Second component based on first", group = "Flow")
|
||||
public void conditional() {
|
||||
Map<String, String> single1SelectItems = new HashMap<>();
|
||||
single1SelectItems.put("Field1", "field1");
|
||||
single1SelectItems.put("Field2", "field2");
|
||||
ComponentFlow flow = componentFlowBuilder.clone().reset()
|
||||
.withSingleItemSelector("single1")
|
||||
.name("Single1")
|
||||
.selectItems(single1SelectItems)
|
||||
.next(ctx -> ctx.getResultItem().get().getItem())
|
||||
.and()
|
||||
.withStringInput("field1")
|
||||
.name("Field1")
|
||||
.defaultValue("defaultField1Value")
|
||||
.next(ctx -> null)
|
||||
.and()
|
||||
.withStringInput("field2")
|
||||
.name("Field2")
|
||||
.defaultValue("defaultField2Value")
|
||||
.next(ctx -> null)
|
||||
.and()
|
||||
.build();
|
||||
flow.run();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "flow autoselect", value = "Autoselect item", group = "Flow")
|
||||
public void autoselect(
|
||||
@ShellOption(defaultValue = "Field3") String defaultValue
|
||||
) {
|
||||
Map<String, String> single1SelectItems = IntStream.range(1, 10)
|
||||
.boxed()
|
||||
.collect(Collectors.toMap(i -> "Field" + i, i -> "field" + i));
|
||||
|
||||
ComponentFlow flow = componentFlowBuilder.clone().reset()
|
||||
.withSingleItemSelector("single1")
|
||||
.name("Single1")
|
||||
.selectItems(single1SelectItems)
|
||||
.defaultSelect(defaultValue)
|
||||
.sort((o1, o2) -> o1.getName().compareTo(o2.getName()))
|
||||
.and()
|
||||
.build();
|
||||
flow.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2017-2021 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.standard;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ShellComponent
|
||||
class ConversionCommands {
|
||||
|
||||
@ShellMethod("Shows conversion using Spring converter")
|
||||
public Object conversionExample(DomainObject object) {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DomainObject {
|
||||
private final String value;
|
||||
|
||||
DomainObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DomainObject [value=" + value + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class CustomDomainConverter implements Converter<String, DomainObject> {
|
||||
|
||||
@Override
|
||||
public DomainObject convert(String source) {
|
||||
return new DomainObject(source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2017-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.standard;
|
||||
|
||||
import org.springframework.shell.Availability;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellMethodAvailability;
|
||||
|
||||
/**
|
||||
* Showcases dynamic command availability.
|
||||
*
|
||||
* @author Eric Bottard
|
||||
*/
|
||||
@ShellComponent
|
||||
public class DynamicCommands {
|
||||
|
||||
private boolean connected;
|
||||
|
||||
private boolean authenticated;
|
||||
|
||||
public Availability authenticateAvailability() {
|
||||
return connected ? Availability.available() : Availability.unavailable("you are not connected");
|
||||
}
|
||||
|
||||
@ShellMethod(value = "Authenticate with the system", group = "Dynamic Commands")
|
||||
public void authenticate(String credentials) {
|
||||
authenticated = "sesame".equals(credentials);
|
||||
}
|
||||
|
||||
@ShellMethod(value = "Connect to the system", group = "Dynamic Commands")
|
||||
public void connect() {
|
||||
connected = true;
|
||||
}
|
||||
|
||||
@ShellMethod(value = "Disconnect from the system", group = "Dynamic Commands")
|
||||
public void disconnect() {
|
||||
connected = false;
|
||||
}
|
||||
|
||||
@ShellMethod(value = "Blow Everything up", group = "Dynamic Commands")
|
||||
@ShellMethodAvailability("dangerousAvailability")
|
||||
public String blowUp() {
|
||||
return "Boom!";
|
||||
}
|
||||
|
||||
public Availability dangerousAvailability() {
|
||||
return connected && authenticated ? Availability.available()
|
||||
: Availability.unavailable("you failed to authenticate. Try 'sesame'.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
|
||||
@Configuration
|
||||
public class FunctionCommands {
|
||||
|
||||
@Bean
|
||||
public CommandRegistration commandRegistration1() {
|
||||
return CommandRegistration.builder()
|
||||
.command("function", "command1")
|
||||
.description("function sample")
|
||||
.group("Function Commands")
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
String arg1 = ctx.getOptionValue("arg1");
|
||||
return String.format("hi, arg1 value is '%s'", arg1);
|
||||
})
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration commandRegistration2() {
|
||||
return CommandRegistration.builder()
|
||||
.command("function", "command2")
|
||||
.description("function sample")
|
||||
.group("Function Commands")
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
Boolean a = ctx.getOptionValue("a");
|
||||
Boolean b = ctx.getOptionValue("b");
|
||||
Boolean c = ctx.getOptionValue("c");
|
||||
return String.format("hi, boolean values for a, b, c are '%s' '%s' '%s'", a, b, c);
|
||||
})
|
||||
.and()
|
||||
.withOption()
|
||||
.shortNames('a')
|
||||
.type(boolean.class)
|
||||
.and()
|
||||
.withOption()
|
||||
.shortNames('b')
|
||||
.type(boolean.class)
|
||||
.and()
|
||||
.withOption()
|
||||
.shortNames('c')
|
||||
.type(boolean.class)
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration commandRegistration3() {
|
||||
return CommandRegistration.builder()
|
||||
.command("function", "command3")
|
||||
.description("function sample")
|
||||
.group("Function Commands")
|
||||
.withTarget()
|
||||
.consumer(ctx -> {
|
||||
String arg1 = ctx.getOptionValue("arg1");
|
||||
ctx.getTerminal().writer()
|
||||
.println(String.format("hi, arg1 value is '%s'", arg1));
|
||||
})
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandRegistration commandRegistration4() {
|
||||
return CommandRegistration.builder()
|
||||
.command("function", "command4")
|
||||
.description("function sample")
|
||||
.group("Function Commands")
|
||||
.withTarget()
|
||||
.consumer(ctx -> {
|
||||
ctx.getTerminal().writer()
|
||||
.println(String.format("hi, command is '%s'", ctx.getCommandRegistration().getCommand()));
|
||||
})
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.shell.command.CommandContext;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
|
||||
@ShellComponent
|
||||
public class RegisterCommands extends AbstractShellComponent {
|
||||
|
||||
private final static String GROUP = "Register Commands";
|
||||
private final PojoMethods pojoMethods = new PojoMethods();
|
||||
private final CommandRegistration registered1;
|
||||
private final CommandRegistration registered2;
|
||||
private final CommandRegistration registered3;
|
||||
|
||||
public RegisterCommands() {
|
||||
registered1 = CommandRegistration.builder()
|
||||
.command("register registered1")
|
||||
.group(GROUP)
|
||||
.description("registered1 command")
|
||||
.withTarget()
|
||||
.method(pojoMethods, "registered1")
|
||||
.and()
|
||||
.build();
|
||||
registered2 = CommandRegistration.builder()
|
||||
.command("register registered2")
|
||||
.description("registered2 command")
|
||||
.group(GROUP)
|
||||
.withTarget()
|
||||
.method(pojoMethods, "registered2")
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.and()
|
||||
.build();
|
||||
registered3 = CommandRegistration.builder()
|
||||
.command("register registered3")
|
||||
.description("registered3 command")
|
||||
.group(GROUP)
|
||||
.withTarget()
|
||||
.method(pojoMethods, "registered3")
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "register add", value = "Register commands", group = GROUP)
|
||||
public String register() {
|
||||
getCommandCatalog().register(registered1, registered2, registered3);
|
||||
registerFunctionCommand("register registered4");
|
||||
return "Registered commands registered1, registered2, registered3, registered4";
|
||||
}
|
||||
|
||||
@ShellMethod(key = "register remove", value = "Deregister commands", group = GROUP)
|
||||
public String deregister() {
|
||||
getCommandCatalog().unregister("register registered1", "register registered2", "register registered3",
|
||||
"register registered4");
|
||||
return "Deregistered commands registered1, registered2, registered3, registered4";
|
||||
}
|
||||
|
||||
private void registerFunctionCommand(String command) {
|
||||
Function<CommandContext, String> function = ctx -> {
|
||||
String arg1 = ctx.getOptionValue("arg1");
|
||||
return String.format("hi, arg1 value is '%s'", arg1);
|
||||
};
|
||||
CommandRegistration registration = CommandRegistration.builder()
|
||||
.command(command)
|
||||
.description("registered4 command")
|
||||
.group(GROUP)
|
||||
.withTarget()
|
||||
.function(function)
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.and()
|
||||
.build();
|
||||
getCommandCatalog().register(registration);
|
||||
}
|
||||
|
||||
public static class PojoMethods {
|
||||
|
||||
@ShellMethod
|
||||
public String registered1() {
|
||||
return "registered1";
|
||||
}
|
||||
|
||||
@ShellMethod
|
||||
public String registered2(String arg1) {
|
||||
return "registered2" + arg1;
|
||||
}
|
||||
|
||||
@ShellMethod
|
||||
public String registered3(@ShellOption(defaultValue = ShellOption.NULL) String arg1) {
|
||||
return "registered3" + arg1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.command.CommandResolver;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
|
||||
public class ResolvedCommands {
|
||||
|
||||
private static final String GROUP = "Resolve Commands";
|
||||
|
||||
@Configuration
|
||||
public static class ResolvedCommandsConfiguration {
|
||||
|
||||
@Bean
|
||||
Server1CommandResolver server1CommandResolver() {
|
||||
return new Server1CommandResolver();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Server2CommandResolver server2CommandResolver() {
|
||||
return new Server2CommandResolver();
|
||||
}
|
||||
}
|
||||
|
||||
@ShellComponent
|
||||
public static class ResolvedCommandsCommands {
|
||||
|
||||
private final Server1CommandResolver server1CommandResolver;
|
||||
private final Server2CommandResolver server2CommandResolver;
|
||||
|
||||
ResolvedCommandsCommands(Server1CommandResolver server1CommandResolver,
|
||||
Server2CommandResolver server2CommandResolver) {
|
||||
this.server1CommandResolver = server1CommandResolver;
|
||||
this.server2CommandResolver = server2CommandResolver;
|
||||
}
|
||||
|
||||
@ShellMethod(key = "resolve enableserver1", group = GROUP)
|
||||
public String server1Enable() {
|
||||
server1CommandResolver.enabled = true;
|
||||
return "Enabled server1";
|
||||
}
|
||||
|
||||
@ShellMethod(key = "resolve disableserver1", group = GROUP)
|
||||
public String server1Disable() {
|
||||
server1CommandResolver.enabled = false;
|
||||
return "Disabled server1";
|
||||
}
|
||||
|
||||
@ShellMethod(key = "resolve enableserver2", group = GROUP)
|
||||
public String server2Enable() {
|
||||
server2CommandResolver.enabled = true;
|
||||
return "Enabled server2";
|
||||
}
|
||||
|
||||
@ShellMethod(key = "resolve disableserver2", group = GROUP)
|
||||
public String server2Disable() {
|
||||
server2CommandResolver.enabled = false;
|
||||
return "Disabled server2";
|
||||
}
|
||||
}
|
||||
|
||||
static class Server1CommandResolver implements CommandResolver {
|
||||
|
||||
private final List<CommandRegistration> registrations = new ArrayList<>();
|
||||
boolean enabled = false;
|
||||
|
||||
Server1CommandResolver() {
|
||||
CommandRegistration resolved1 = CommandRegistration.builder()
|
||||
.command("resolve server1 command1")
|
||||
.group(GROUP)
|
||||
.description("server1 command1")
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
return "hi from server1 command1";
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
registrations.add(resolved1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommandRegistration> resolve() {
|
||||
return enabled ? registrations : Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
static class Server2CommandResolver implements CommandResolver {
|
||||
|
||||
private final List<CommandRegistration> registrations = new ArrayList<>();
|
||||
boolean enabled = false;
|
||||
|
||||
Server2CommandResolver() {
|
||||
CommandRegistration resolved1 = CommandRegistration.builder()
|
||||
.command("resolve server2 command1")
|
||||
.group(GROUP)
|
||||
.description("server2 command1")
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
return "hi from server2 command1";
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
CommandRegistration resolved2 = CommandRegistration.builder()
|
||||
.command("resolve server2 command2")
|
||||
.group(GROUP)
|
||||
.description("server2 command2")
|
||||
.withTarget()
|
||||
.function(ctx -> {
|
||||
return "hi from server2 command2";
|
||||
})
|
||||
.and()
|
||||
.build();
|
||||
registrations.add(resolved1);
|
||||
registrations.add(resolved2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommandRegistration> resolve() {
|
||||
return enabled ? registrations : Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2017 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.standard;
|
||||
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.table.*;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@ShellComponent
|
||||
public class TableCommands {
|
||||
|
||||
private static final String TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " +
|
||||
"ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
|
||||
"laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " +
|
||||
"voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat " +
|
||||
"non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
|
||||
|
||||
@ShellMethod(value = "Showcase Table rendering", group = "Tables")
|
||||
public Table table() {
|
||||
String[][] data = new String[3][3];
|
||||
TableModel model = new ArrayTableModel(data);
|
||||
TableBuilder tableBuilder = new TableBuilder(model);
|
||||
|
||||
Random r = new Random();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
data[i][j] = TEXT.substring(0, TEXT.length() / 2 + r.nextInt(TEXT.length() / 2));
|
||||
tableBuilder.on(at(i, j)).addAligner(SimpleHorizontalAligner.values()[j]);
|
||||
tableBuilder.on(at(i, j)).addAligner(SimpleVerticalAligner.values()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return tableBuilder.addFullBorder(BorderStyle.fancy_light).build();
|
||||
}
|
||||
|
||||
public static CellMatcher at(final int theRow, final int col) {
|
||||
return new CellMatcher() {
|
||||
@Override
|
||||
public boolean matches(int row, int column, TableModel model) {
|
||||
return row == theRow && column == col;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jline.utils.AttributedString;
|
||||
import org.jline.utils.AttributedStringBuilder;
|
||||
import org.jline.utils.AttributedStyle;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
import org.springframework.shell.style.FigureSettings;
|
||||
import org.springframework.shell.style.StyleSettings;
|
||||
import org.springframework.shell.style.ThemeResolver;
|
||||
|
||||
@ShellComponent
|
||||
public class ThemeCommands {
|
||||
|
||||
List<String> colorGround = Arrays.asList("fg", "bg");
|
||||
List<String> colors = Arrays.asList("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white");
|
||||
List<String> named = Arrays.asList("default", "bold", "faint", "italic", "underline", "blink", "inverse",
|
||||
"inverseneg", "conceal", "crossedout", "hidden");
|
||||
List<String> rgbRedHue = Arrays.asList("#ff0000", "#ff4000", "#ff8000", "#ffbf00", "#ffff00", "#bfff00", "#80ff00",
|
||||
"#40ff00", "#00ff00", "#00ff40", "#00ff80", "#00ffbf", "#00ffff", "#00bfff", "#0080ff", "#0040ff",
|
||||
"#0000ff", "#4000ff", "#8000ff", "#bf00ff", "#ff00ff", "#ff00bf", "#ff0080", "#ff0040", "#ff0000");
|
||||
List<String> themeTags = Arrays.asList(StyleSettings.TAG_TITLE, StyleSettings.TAG_VALUE, StyleSettings.TAG_LIST_KEY,
|
||||
StyleSettings.TAG_LIST_VALUE, StyleSettings.TAG_LEVEL_INFO, StyleSettings.TAG_LEVEL_WARN,
|
||||
StyleSettings.TAG_LEVEL_ERROR, StyleSettings.TAG_ITEM_ENABLED, StyleSettings.TAG_ITEM_DISABLED,
|
||||
StyleSettings.TAG_ITEM_SELECTED, StyleSettings.TAG_ITEM_UNSELECTED, StyleSettings.TAG_ITEM_SELECTOR);
|
||||
|
||||
@Autowired
|
||||
private ThemeResolver themeResolver;
|
||||
|
||||
@ShellMethod(key = "theme showcase values", value = "Showcase colors and styles", group = "Styles")
|
||||
public AttributedString showcaseValues() {
|
||||
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||
combinations1().stream()
|
||||
.forEach(spec -> {
|
||||
AttributedStyle style = themeResolver.resolveStyle(spec);
|
||||
AttributedString styledStr = new AttributedString(spec, style);
|
||||
builder.append(String.format("%-25s", spec));
|
||||
builder.append(" ");
|
||||
builder.append(styledStr);
|
||||
builder.append("\n");
|
||||
});
|
||||
return builder.toAttributedString();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "theme showcase rgb", value = "Showcase colors and styles with rgb", group = "Styles")
|
||||
public AttributedString showcaseRgb() {
|
||||
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||
combinations2().stream()
|
||||
.forEach(spec -> {
|
||||
AttributedStyle style = themeResolver.resolveStyle(spec);
|
||||
AttributedString styledStr = new AttributedString(spec, style);
|
||||
builder.append(String.format("%-25s", spec));
|
||||
builder.append(" ");
|
||||
builder.append(styledStr);
|
||||
builder.append("\n");
|
||||
});
|
||||
return builder.toAttributedString();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "theme style list", value = "List styles", group = "Styles")
|
||||
public AttributedString styleList() {
|
||||
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||
themeTags.stream()
|
||||
.forEach(tag -> {
|
||||
String resolvedStyle = themeResolver.resolveStyleTag(tag);
|
||||
AttributedStyle style = themeResolver.resolveStyle(resolvedStyle);
|
||||
AttributedString styledStr = new AttributedString(tag, style);
|
||||
builder.append(String.format("%-25s", tag));
|
||||
builder.append(" ");
|
||||
builder.append(styledStr);
|
||||
builder.append("\n");
|
||||
});
|
||||
return builder.toAttributedString();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "theme style resolve", value = "Resolve given style", group = "Styles")
|
||||
public AttributedString styleResolve(
|
||||
@ShellOption(value = "--spec", defaultValue = "default") String spec
|
||||
) {
|
||||
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||
AttributedStyle style = themeResolver.resolveStyle(spec);
|
||||
AttributedString styledStr = new AttributedString(spec, style);
|
||||
builder.append(styledStr);
|
||||
builder.append("\n");
|
||||
return builder.toAttributedString();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "theme expression resolve", value = "Resolve given style expression", group = "Styles")
|
||||
public AttributedString expressionResolve(
|
||||
@ShellOption(value = "--expression", defaultValue = "hi @{bold from} expression") String expression
|
||||
) {
|
||||
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||
AttributedString styledStr = themeResolver.evaluateExpression(expression);
|
||||
builder.append(styledStr);
|
||||
builder.append("\n");
|
||||
return builder.toAttributedString();
|
||||
}
|
||||
|
||||
@ShellMethod(key = "theme figure list", value = "List figures", group = "Styles")
|
||||
public AttributedString figureList() {
|
||||
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||
Stream.of(FigureSettings.tags())
|
||||
.forEach(tag -> {
|
||||
builder.append(String.format("%-25s", tag));
|
||||
builder.append(" ");
|
||||
String resolveFigureTag = themeResolver.resolveFigureTag(tag);
|
||||
combinations3().stream().forEach(spec -> {
|
||||
AttributedStyle style = themeResolver.resolveStyle(spec);
|
||||
builder.append(" ");
|
||||
builder.append(new AttributedString(resolveFigureTag, style));
|
||||
});
|
||||
builder.append("\n");
|
||||
});
|
||||
return builder.toAttributedString();
|
||||
}
|
||||
|
||||
private List<String> combinations1() {
|
||||
List<String> styles = new ArrayList<>();
|
||||
colorGround.stream().forEach(ground -> {
|
||||
colors.stream().forEach(color -> {
|
||||
named.stream().forEach(named -> {
|
||||
styles.add(String.format("%s,%s:%s", named, ground, color));
|
||||
});
|
||||
});
|
||||
});
|
||||
return styles;
|
||||
}
|
||||
|
||||
private List<String> combinations2() {
|
||||
List<String> styles = new ArrayList<>();
|
||||
rgbRedHue.stream().forEach(rgb -> {
|
||||
styles.add(String.format("inverse,fg-rgb:%s", rgb));
|
||||
});
|
||||
return styles;
|
||||
}
|
||||
|
||||
private List<String> combinations3() {
|
||||
List<String> styles = new ArrayList<>();
|
||||
Arrays.asList("fg").stream().forEach(ground -> {
|
||||
Arrays.asList("white").stream().forEach(color -> {
|
||||
named.stream().forEach(named -> {
|
||||
styles.add(String.format("%s,%s:%s", named, ground, color));
|
||||
});
|
||||
});
|
||||
});
|
||||
return styles;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
spring:
|
||||
main:
|
||||
banner-mode: off
|
||||
shell:
|
||||
## pick global default option naming
|
||||
# option:
|
||||
# naming:
|
||||
# case-type: noop
|
||||
# case-type: camel
|
||||
# case-type: snake
|
||||
# case-type: kebab
|
||||
# case-type: pascal
|
||||
config:
|
||||
env: SPRING_SHELL_SAMPLES_USER_HOME
|
||||
location: "{userconfig}/spring-shell-samples"
|
||||
history:
|
||||
name: spring-shell-samples-history.log
|
||||
command:
|
||||
help:
|
||||
grouping-mode: group
|
||||
completion:
|
||||
root-command: spring-shell-samples
|
||||
## disable console logging
|
||||
logging:
|
||||
pattern:
|
||||
console:
|
||||
## log debug from a cli
|
||||
# file:
|
||||
# name: shell.log
|
||||
# level:
|
||||
# root: debug
|
||||
# org:
|
||||
# springframework:
|
||||
# shell: debug
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2022-2023 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.shell.samples.standard.ResolvedCommands;
|
||||
import org.springframework.shell.test.ShellAssertions;
|
||||
import org.springframework.shell.test.ShellTestClient;
|
||||
import org.springframework.shell.test.ShellTestClient.BaseShellSession;
|
||||
import org.springframework.shell.test.ShellTestClient.InteractiveShellSession;
|
||||
import org.springframework.shell.test.ShellTestClient.NonInteractiveShellSession;
|
||||
import org.springframework.shell.test.autoconfigure.ShellTest;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
@ShellTest(terminalWidth = 120)
|
||||
@Import(ResolvedCommands.ResolvedCommandsConfiguration.class)
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
public class AbstractSampleTests {
|
||||
|
||||
@Autowired
|
||||
protected ShellTestClient client;
|
||||
|
||||
protected void assertScreenContainsText(BaseShellSession<?> session, String text) {
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
ShellAssertions.assertThat(session.screen()).containsText(text);
|
||||
});
|
||||
}
|
||||
|
||||
protected void assertScreenNotContainsText(BaseShellSession<?> session, String textFound, String textNotFound) {
|
||||
Condition<String> notCondition = new Condition<>(line -> line.contains(textNotFound),
|
||||
String.format("Text '%s' not found", textNotFound));
|
||||
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
ShellAssertions.assertThat(session.screen()).containsText(textFound);
|
||||
List<String> lines = session.screen().lines();
|
||||
assertThat(lines).areNot(notCondition);
|
||||
});
|
||||
}
|
||||
|
||||
protected BaseShellSession<?> createSession(String command, boolean interactive) {
|
||||
if (interactive) {
|
||||
InteractiveShellSession session = client.interactive().run();
|
||||
session.write(session.writeSequence().command(command).build());
|
||||
return session;
|
||||
}
|
||||
else {
|
||||
String[] commands = command.split(" ");
|
||||
NonInteractiveShellSession session = client.nonInterative(commands).run();
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.standard;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import org.springframework.shell.samples.AbstractSampleTests;
|
||||
import org.springframework.shell.test.ShellAssertions;
|
||||
import org.springframework.shell.test.ShellTestClient.BaseShellSession;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
public class ComponentCommandsTests extends AbstractSampleTests {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"component single,false",
|
||||
"component single,true"
|
||||
})
|
||||
void componentSingle(String command, boolean interactive) {
|
||||
BaseShellSession<?> session = createSession(command, interactive);
|
||||
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
assertThat(session.screen().lines()).anySatisfy(line -> {
|
||||
assertThat(line).containsPattern("[>❯] key1");
|
||||
});
|
||||
});
|
||||
|
||||
session.write(session.writeSequence().keyDown().build());
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
assertThat(session.screen().lines()).anySatisfy(line -> {
|
||||
assertThat(line).containsPattern("[>❯] key2");
|
||||
});
|
||||
});
|
||||
|
||||
session.write(session.writeSequence().cr().build());
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
ShellAssertions.assertThat(session.screen()).containsText("Got value value2");
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"component multi,false",
|
||||
"component multi,true"
|
||||
})
|
||||
void componentMulti(String command, boolean interactive) {
|
||||
BaseShellSession<?> session = createSession(command, interactive);
|
||||
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
assertThat(session.screen().lines()).anySatisfy(line -> {
|
||||
assertThat(line).containsPattern("[>❯] (☐|\\[ \\]) key1");
|
||||
});
|
||||
});
|
||||
|
||||
session.write(session.writeSequence().space().build());
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
assertThat(session.screen().lines()).anySatisfy(line -> {
|
||||
assertThat(line).containsPattern("[>❯] (☒|\\[x\\]) key1");
|
||||
});
|
||||
});
|
||||
|
||||
session.write(session.writeSequence().cr().build());
|
||||
await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
ShellAssertions.assertThat(session.screen()).containsText("Got value value1,value2");
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user