Separate interactive and non-interactive commands
- Add new ShellContext concept which now is just a way to stash info about interaction mode where ShellRunner can update supported mode. - ShellMethod has a new field interactionMode which user can use to define commands between interactive/non-interactive modes which then prevents CommandRegistry to show commands at runtime. - Fixes #345
This commit is contained in:
@@ -21,14 +21,16 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.shell.CommandRegistry;
|
import org.springframework.shell.CommandRegistry;
|
||||||
import org.springframework.shell.ConfigurableCommandRegistry;
|
import org.springframework.shell.ConfigurableCommandRegistry;
|
||||||
import org.springframework.shell.MethodTargetRegistrar;
|
import org.springframework.shell.MethodTargetRegistrar;
|
||||||
|
import org.springframework.shell.context.ShellContext;
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
public class CommandRegistryAutoConfiguration {
|
public class CommandRegistryAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CommandRegistry commandRegistry(
|
public CommandRegistry commandRegistry(
|
||||||
ObjectProvider<MethodTargetRegistrar> methodTargetRegistrars) {
|
ObjectProvider<MethodTargetRegistrar> methodTargetRegistrars,
|
||||||
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
ShellContext shellContext) {
|
||||||
|
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry(shellContext);
|
||||||
methodTargetRegistrars.orderedStream().forEach(resolver -> {
|
methodTargetRegistrars.orderedStream().forEach(resolver -> {
|
||||||
resolver.register(registry);
|
resolver.register(registry);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.springframework.shell.boot;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.shell.context.DefaultShellContext;
|
||||||
|
import org.springframework.shell.context.ShellContext;
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
public class ShellContextAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ShellContext shellContext() {
|
||||||
|
return new DefaultShellContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.shell.Shell;
|
import org.springframework.shell.Shell;
|
||||||
|
import org.springframework.shell.context.ShellContext;
|
||||||
import org.springframework.shell.jline.InteractiveShellRunner;
|
import org.springframework.shell.jline.InteractiveShellRunner;
|
||||||
import org.springframework.shell.jline.NonInteractiveShellRunner;
|
import org.springframework.shell.jline.NonInteractiveShellRunner;
|
||||||
import org.springframework.shell.jline.PromptProvider;
|
import org.springframework.shell.jline.PromptProvider;
|
||||||
@@ -34,24 +35,27 @@ public class ShellRunnerAutoConfiguration {
|
|||||||
private PromptProvider promptProvider;
|
private PromptProvider promptProvider;
|
||||||
private LineReader lineReader;
|
private LineReader lineReader;
|
||||||
private Parser parser;
|
private Parser parser;
|
||||||
|
private ShellContext shellContext;
|
||||||
|
|
||||||
public ShellRunnerAutoConfiguration(Shell shell, PromptProvider promptProvider, LineReader lineReader, Parser parser) {
|
public ShellRunnerAutoConfiguration(Shell shell, PromptProvider promptProvider, LineReader lineReader,
|
||||||
|
Parser parser, ShellContext shellContext) {
|
||||||
this.shell = shell;
|
this.shell = shell;
|
||||||
this.promptProvider = promptProvider;
|
this.promptProvider = promptProvider;
|
||||||
this.lineReader = lineReader;
|
this.lineReader = lineReader;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
|
this.shellContext = shellContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(prefix = "spring.shell.interactive", value = "enabled", havingValue = "true", matchIfMissing = true)
|
@ConditionalOnProperty(prefix = "spring.shell.interactive", value = "enabled", havingValue = "true", matchIfMissing = true)
|
||||||
public InteractiveShellRunner interactiveApplicationRunner() {
|
public InteractiveShellRunner interactiveApplicationRunner() {
|
||||||
return new InteractiveShellRunner(lineReader, promptProvider, shell);
|
return new InteractiveShellRunner(lineReader, promptProvider, shell, shellContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(prefix = "spring.shell.noninteractive", value = "enabled", havingValue = "true", matchIfMissing = true)
|
@ConditionalOnProperty(prefix = "spring.shell.noninteractive", value = "enabled", havingValue = "true", matchIfMissing = true)
|
||||||
public NonInteractiveShellRunner nonInteractiveApplicationRunner() {
|
public NonInteractiveShellRunner nonInteractiveApplicationRunner() {
|
||||||
return new NonInteractiveShellRunner(shell);
|
return new NonInteractiveShellRunner(shell, shellContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
org.springframework.shell.boot.ShellContextAutoConfiguration,\
|
||||||
org.springframework.shell.boot.SpringShellAutoConfiguration,\
|
org.springframework.shell.boot.SpringShellAutoConfiguration,\
|
||||||
org.springframework.shell.boot.ShellRunnerAutoConfiguration,\
|
org.springframework.shell.boot.ShellRunnerAutoConfiguration,\
|
||||||
org.springframework.shell.boot.ApplicationRunnerAutoConfiguration,\
|
org.springframework.shell.boot.ApplicationRunnerAutoConfiguration,\
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 the original author or authors.
|
* Copyright 2017-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,12 +13,14 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.shell;
|
package org.springframework.shell;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
|
import org.springframework.shell.context.ShellContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link CommandRegistry} that supports registration of new commands.
|
* A {@link CommandRegistry} that supports registration of new commands.
|
||||||
@@ -29,11 +31,31 @@ import java.util.TreeMap;
|
|||||||
*/
|
*/
|
||||||
public class ConfigurableCommandRegistry implements CommandRegistry {
|
public class ConfigurableCommandRegistry implements CommandRegistry {
|
||||||
|
|
||||||
|
private final ShellContext shellContext;
|
||||||
private Map<String, MethodTarget> commands = new HashMap<>();
|
private Map<String, MethodTarget> commands = new HashMap<>();
|
||||||
|
|
||||||
|
public ConfigurableCommandRegistry(ShellContext shellContext) {
|
||||||
|
this.shellContext = shellContext;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, MethodTarget> listCommands() {
|
public Map<String, MethodTarget> listCommands() {
|
||||||
return new TreeMap<>(commands);
|
return commands.entrySet().stream()
|
||||||
|
.filter(e -> {
|
||||||
|
InteractionMode mim = e.getValue().getInteractionMode();
|
||||||
|
InteractionMode cim = shellContext.getInteractionMode();
|
||||||
|
if (mim == null || cim == null || mim == InteractionMode.ALL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (mim == InteractionMode.INTERACTIVE) {
|
||||||
|
return cim == InteractionMode.INTERACTIVE || cim == InteractionMode.ALL;
|
||||||
|
}
|
||||||
|
else if (mim == InteractionMode.NONINTERACTIVE) {
|
||||||
|
return cim == InteractionMode.NONINTERACTIVE || cim == InteractionMode.ALL;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(String name, MethodTarget target) {
|
public void register(String name, MethodTarget target) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015 the original author or authors.
|
* Copyright 2015-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.shell;
|
package org.springframework.shell;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -21,6 +20,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
@@ -37,6 +37,8 @@ public class MethodTarget implements Command {
|
|||||||
|
|
||||||
private final Help help;
|
private final Help help;
|
||||||
|
|
||||||
|
private final InteractionMode interactionMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If not null, returns whether or not the command is currently available. Implementations must be idempotent.
|
* If not null, returns whether or not the command is currently available. Implementations must be idempotent.
|
||||||
*/
|
*/
|
||||||
@@ -51,6 +53,10 @@ public class MethodTarget implements Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MethodTarget(Method method, Object bean, Help help, Supplier<Availability> availabilityIndicator) {
|
public MethodTarget(Method method, Object bean, Help help, Supplier<Availability> availabilityIndicator) {
|
||||||
|
this(method, bean, help, availabilityIndicator, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodTarget(Method method, Object bean, Help help, Supplier<Availability> availabilityIndicator, InteractionMode interactionMode) {
|
||||||
Assert.notNull(method, "Method cannot be null");
|
Assert.notNull(method, "Method cannot be null");
|
||||||
Assert.notNull(bean, "Bean cannot be null");
|
Assert.notNull(bean, "Bean cannot be null");
|
||||||
Assert.hasText(help.getDescription(), String.format("Help cannot be blank when trying to define command based on '%s'", method));
|
Assert.hasText(help.getDescription(), String.format("Help cannot be blank when trying to define command based on '%s'", method));
|
||||||
@@ -59,6 +65,7 @@ public class MethodTarget implements Command {
|
|||||||
this.bean = bean;
|
this.bean = bean;
|
||||||
this.help = help;
|
this.help = help;
|
||||||
this.availabilityIndicator = availabilityIndicator != null ? availabilityIndicator : () -> Availability.available();
|
this.availabilityIndicator = availabilityIndicator != null ? availabilityIndicator : () -> Availability.available();
|
||||||
|
this.interactionMode = interactionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,6 +110,10 @@ public class MethodTarget implements Command {
|
|||||||
return availabilityIndicator.get();
|
return availabilityIndicator.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InteractionMode getInteractionMode() {
|
||||||
|
return interactionMode;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.context;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of a {@link ShellContext}.
|
||||||
|
*
|
||||||
|
* @author Janne Valkealahti
|
||||||
|
*/
|
||||||
|
public class DefaultShellContext implements ShellContext {
|
||||||
|
|
||||||
|
private InteractionMode interactionMode = InteractionMode.ALL;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionMode getInteractionMode() {
|
||||||
|
return interactionMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInteractionMode(InteractionMode interactionMode) {
|
||||||
|
Assert.notNull(interactionMode, "mode cannot be null");
|
||||||
|
this.interactionMode = interactionMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration for modes shell is operating.
|
||||||
|
*
|
||||||
|
* @author Janne Valkealahti
|
||||||
|
*/
|
||||||
|
public enum InteractionMode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All possible modes.
|
||||||
|
*/
|
||||||
|
ALL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-interactive mode which is expected to exit and doesn't have any kind of
|
||||||
|
* running mode to keep shell alive.
|
||||||
|
*/
|
||||||
|
NONINTERACTIVE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactive mode which is expected to not exit and do have a running mode to
|
||||||
|
* keep shell alive.
|
||||||
|
*/
|
||||||
|
INTERACTIVE
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface defining a contract for a context which allows to loosely connect
|
||||||
|
* different components together and keep things alive between commands.
|
||||||
|
*
|
||||||
|
* @author Janne Valkealahti
|
||||||
|
*/
|
||||||
|
public interface ShellContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an interaction mode.
|
||||||
|
*
|
||||||
|
* @return a current interaction mode
|
||||||
|
*/
|
||||||
|
InteractionMode getInteractionMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an interaction mode.
|
||||||
|
*
|
||||||
|
* @param interactionMode the interaction mode
|
||||||
|
*/
|
||||||
|
void setInteractionMode(InteractionMode interactionMode);
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ import org.springframework.shell.Input;
|
|||||||
import org.springframework.shell.InputProvider;
|
import org.springframework.shell.InputProvider;
|
||||||
import org.springframework.shell.Shell;
|
import org.springframework.shell.Shell;
|
||||||
import org.springframework.shell.ShellRunner;
|
import org.springframework.shell.ShellRunner;
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
|
import org.springframework.shell.context.ShellContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Boot runner that bootstraps the shell application in interactive
|
* Default Boot runner that bootstraps the shell application in interactive
|
||||||
@@ -52,14 +54,19 @@ public class InteractiveShellRunner implements ShellRunner {
|
|||||||
|
|
||||||
private final Shell shell;
|
private final Shell shell;
|
||||||
|
|
||||||
public InteractiveShellRunner(LineReader lineReader, PromptProvider promptProvider, Shell shell) {
|
private final ShellContext shellContext;
|
||||||
|
|
||||||
|
public InteractiveShellRunner(LineReader lineReader, PromptProvider promptProvider, Shell shell,
|
||||||
|
ShellContext shellContext) {
|
||||||
this.lineReader = lineReader;
|
this.lineReader = lineReader;
|
||||||
this.promptProvider = promptProvider;
|
this.promptProvider = promptProvider;
|
||||||
this.shell = shell;
|
this.shell = shell;
|
||||||
|
this.shellContext = shellContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
shellContext.setInteractionMode(InteractionMode.INTERACTIVE);
|
||||||
InputProvider inputProvider = new JLineInputProvider(lineReader, promptProvider);
|
InputProvider inputProvider = new JLineInputProvider(lineReader, promptProvider);
|
||||||
shell.run(inputProvider);
|
shell.run(inputProvider);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import org.springframework.shell.Input;
|
|||||||
import org.springframework.shell.InputProvider;
|
import org.springframework.shell.InputProvider;
|
||||||
import org.springframework.shell.Shell;
|
import org.springframework.shell.Shell;
|
||||||
import org.springframework.shell.ShellRunner;
|
import org.springframework.shell.ShellRunner;
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
|
import org.springframework.shell.context.ShellContext;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -37,9 +39,11 @@ import org.springframework.util.StringUtils;
|
|||||||
public class NonInteractiveShellRunner implements ShellRunner {
|
public class NonInteractiveShellRunner implements ShellRunner {
|
||||||
|
|
||||||
private final Shell shell;
|
private final Shell shell;
|
||||||
|
private final ShellContext shellContext;
|
||||||
|
|
||||||
public NonInteractiveShellRunner(Shell shell) {
|
public NonInteractiveShellRunner(Shell shell, ShellContext shellContext) {
|
||||||
this.shell = shell;
|
this.shell = shell;
|
||||||
|
this.shellContext = shellContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -50,6 +54,7 @@ public class NonInteractiveShellRunner implements ShellRunner {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
shellContext.setInteractionMode(InteractionMode.NONINTERACTIVE);
|
||||||
List<String> argsToShellCommand = Arrays.asList(args.getSourceArgs());
|
List<String> argsToShellCommand = Arrays.asList(args.getSourceArgs());
|
||||||
InputProvider inputProvider = new StringInputProvider(argsToShellCommand);
|
InputProvider inputProvider = new StringInputProvider(argsToShellCommand);
|
||||||
shell.run(inputProvider);
|
shell.run(inputProvider);
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package org.springframework.shell;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.shell.context.DefaultShellContext;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
@@ -30,14 +32,14 @@ public class ConfigurableCommandRegistryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegistration() {
|
public void testRegistration() {
|
||||||
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry(new DefaultShellContext());
|
||||||
registry.register("foo", MethodTarget.of("toString", this, new Command.Help("some command")));
|
registry.register("foo", MethodTarget.of("toString", this, new Command.Help("some command")));
|
||||||
assertThat(registry.listCommands()).containsKeys("foo");
|
assertThat(registry.listCommands()).containsKeys("foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoubleRegistration() {
|
public void testDoubleRegistration() {
|
||||||
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry(new DefaultShellContext());
|
||||||
registry.register("foo", MethodTarget.of("toString", this, new Command.Help("some command")));
|
registry.register("foo", MethodTarget.of("toString", this, new Command.Help("some command")));
|
||||||
|
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2021 the original author or authors.
|
* Copyright 2017-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,6 +18,7 @@ package org.springframework.shell.standard.commands;
|
|||||||
|
|
||||||
import org.jline.utils.InfoCmp;
|
import org.jline.utils.InfoCmp;
|
||||||
|
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
import org.springframework.shell.standard.AbstractShellComponent;
|
import org.springframework.shell.standard.AbstractShellComponent;
|
||||||
import org.springframework.shell.standard.ShellComponent;
|
import org.springframework.shell.standard.ShellComponent;
|
||||||
import org.springframework.shell.standard.ShellMethod;
|
import org.springframework.shell.standard.ShellMethod;
|
||||||
@@ -47,7 +48,7 @@ public class Clear extends AbstractShellComponent {
|
|||||||
public Clear() {
|
public Clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod("Clear the shell screen.")
|
@ShellMethod(value = "Clear the shell screen.", interactionMode = InteractionMode.INTERACTIVE)
|
||||||
public void clear() {
|
public void clear() {
|
||||||
getTerminal().puts(InfoCmp.Capability.clear_screen);
|
getTerminal().puts(InfoCmp.Capability.clear_screen);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 the original author or authors.
|
* Copyright 2017-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.shell.standard.commands;
|
package org.springframework.shell.standard.commands;
|
||||||
|
|
||||||
import org.springframework.shell.ExitRequest;
|
import org.springframework.shell.ExitRequest;
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
import org.springframework.shell.standard.ShellComponent;
|
import org.springframework.shell.standard.ShellComponent;
|
||||||
import org.springframework.shell.standard.ShellMethod;
|
import org.springframework.shell.standard.ShellMethod;
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ public class Quit {
|
|||||||
*/
|
*/
|
||||||
public interface Command {}
|
public interface Command {}
|
||||||
|
|
||||||
@ShellMethod(value = "Exit the shell.", key = {"quit", "exit"})
|
@ShellMethod(value = "Exit the shell.", key = {"quit", "exit"}, interactionMode = InteractionMode.INTERACTIVE)
|
||||||
public void quit() {
|
public void quit() {
|
||||||
throw new ExitRequest();
|
throw new ExitRequest();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2021 the original author or authors.
|
* Copyright 2017-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package org.springframework.shell.standard.commands;
|
package org.springframework.shell.standard.commands;
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
import org.springframework.shell.result.ThrowableResultHandler;
|
import org.springframework.shell.result.ThrowableResultHandler;
|
||||||
import org.springframework.shell.standard.AbstractShellComponent;
|
import org.springframework.shell.standard.AbstractShellComponent;
|
||||||
import org.springframework.shell.standard.ShellComponent;
|
import org.springframework.shell.standard.ShellComponent;
|
||||||
@@ -49,7 +50,9 @@ public class Stacktrace extends AbstractShellComponent {
|
|||||||
this.throwableResultHandler = throwableResultHandler;
|
this.throwableResultHandler = throwableResultHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ShellMethod(key = ThrowableResultHandler.DETAILS_COMMAND_NAME, value = "Display the full stacktrace of the last error.")
|
@ShellMethod(key = ThrowableResultHandler.DETAILS_COMMAND_NAME,
|
||||||
|
value = "Display the full stacktrace of the last error.",
|
||||||
|
interactionMode = InteractionMode.INTERACTIVE)
|
||||||
public void stacktrace() {
|
public void stacktrace() {
|
||||||
if (throwableResultHandler.getIfAvailable().getLastError() != null) {
|
if (throwableResultHandler.getIfAvailable().getLastError() != null) {
|
||||||
throwableResultHandler.getIfAvailable().getLastError().printStackTrace(getTerminal().writer());
|
throwableResultHandler.getIfAvailable().getLastError().printStackTrace(getTerminal().writer());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015 the original author or authors.
|
* Copyright 2015-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.shell.standard;
|
package org.springframework.shell.standard;
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
@@ -22,6 +21,8 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to mark a method as invokable via Spring Shell.
|
* Used to mark a method as invokable via Spring Shell.
|
||||||
*
|
*
|
||||||
@@ -68,4 +69,14 @@ public @interface ShellMethod {
|
|||||||
*/
|
*/
|
||||||
String group() default INHERITED;
|
String group() default INHERITED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines interaction mode for a command as a hint when command should be
|
||||||
|
* available. For example presense of some commands doesn't make sense if shell
|
||||||
|
* is running as non-interactive mode and vice versa.
|
||||||
|
*
|
||||||
|
* Defaults to {@link InteractionMode#ALL}
|
||||||
|
*
|
||||||
|
* @return interaction mode
|
||||||
|
*/
|
||||||
|
InteractionMode interactionMode() default InteractionMode.ALL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2017 the original author or authors.
|
* Copyright 2015-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.shell.standard;
|
package org.springframework.shell.standard;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -76,7 +75,8 @@ public class StandardMethodTargetRegistrar implements MethodTargetRegistrar, App
|
|||||||
String group = getOrInferGroup(method);
|
String group = getOrInferGroup(method);
|
||||||
for (String key : keys) {
|
for (String key : keys) {
|
||||||
Supplier<Availability> availabilityIndicator = findAvailabilityIndicator(keys, bean, method);
|
Supplier<Availability> availabilityIndicator = findAvailabilityIndicator(keys, bean, method);
|
||||||
MethodTarget target = new MethodTarget(method, bean, new Command.Help(shellMapping.value(), group), availabilityIndicator);
|
MethodTarget target = new MethodTarget(method, bean, new Command.Help(shellMapping.value(), group),
|
||||||
|
availabilityIndicator, shellMapping.interactionMode());
|
||||||
registry.register(key, target);
|
registry.register(key, target);
|
||||||
commands.put(key, target);
|
commands.put(key, target);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 the original author or authors.
|
* Copyright 2017-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,6 +26,8 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
|||||||
import org.springframework.shell.Availability;
|
import org.springframework.shell.Availability;
|
||||||
import org.springframework.shell.ConfigurableCommandRegistry;
|
import org.springframework.shell.ConfigurableCommandRegistry;
|
||||||
import org.springframework.shell.MethodTarget;
|
import org.springframework.shell.MethodTarget;
|
||||||
|
import org.springframework.shell.context.DefaultShellContext;
|
||||||
|
import org.springframework.shell.context.InteractionMode;
|
||||||
import org.springframework.shell.standard.test1.GroupOneCommands;
|
import org.springframework.shell.standard.test1.GroupOneCommands;
|
||||||
import org.springframework.shell.standard.test2.GroupThreeCommands;
|
import org.springframework.shell.standard.test2.GroupThreeCommands;
|
||||||
import org.springframework.shell.standard.test2.GroupTwoCommands;
|
import org.springframework.shell.standard.test2.GroupTwoCommands;
|
||||||
@@ -42,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|||||||
public class StandardMethodTargetRegistrarTest {
|
public class StandardMethodTargetRegistrarTest {
|
||||||
|
|
||||||
private StandardMethodTargetRegistrar registrar = new StandardMethodTargetRegistrar();
|
private StandardMethodTargetRegistrar registrar = new StandardMethodTargetRegistrar();
|
||||||
private ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
private ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry(new DefaultShellContext());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegistrations() {
|
public void testRegistrations() {
|
||||||
@@ -256,4 +258,47 @@ public class StandardMethodTargetRegistrarTest {
|
|||||||
Assertions.assertThat(commands.get("implicit3").getGroup()).isEqualTo("Explicit Group 3 Class Level");
|
Assertions.assertThat(commands.get("implicit3").getGroup()).isEqualTo("Explicit Group 3 Class Level");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInteractionModeInteractive() {
|
||||||
|
DefaultShellContext shellContext = new DefaultShellContext();
|
||||||
|
shellContext.setInteractionMode(InteractionMode.INTERACTIVE);
|
||||||
|
registry = new ConfigurableCommandRegistry(shellContext);
|
||||||
|
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(InteractionModeCommands.class);
|
||||||
|
registrar.setApplicationContext(applicationContext);
|
||||||
|
registrar.register(registry);
|
||||||
|
|
||||||
|
assertThat(registry.listCommands().get("foo1")).isNotNull();
|
||||||
|
assertThat(registry.listCommands().get("foo2")).isNull();
|
||||||
|
assertThat(registry.listCommands().get("foo3")).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInteractionModeNonInteractive() {
|
||||||
|
DefaultShellContext shellContext = new DefaultShellContext();
|
||||||
|
shellContext.setInteractionMode(InteractionMode.NONINTERACTIVE);
|
||||||
|
registry = new ConfigurableCommandRegistry(shellContext);
|
||||||
|
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(InteractionModeCommands.class);
|
||||||
|
registrar.setApplicationContext(applicationContext);
|
||||||
|
registrar.register(registry);
|
||||||
|
|
||||||
|
assertThat(registry.listCommands().get("foo1")).isNull();
|
||||||
|
assertThat(registry.listCommands().get("foo2")).isNotNull();
|
||||||
|
assertThat(registry.listCommands().get("foo3")).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ShellComponent
|
||||||
|
public static class InteractionModeCommands {
|
||||||
|
|
||||||
|
@ShellMethod(value = "foo1", interactionMode = InteractionMode.INTERACTIVE)
|
||||||
|
public void foo1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@ShellMethod(value = "foo2", interactionMode = InteractionMode.NONINTERACTIVE)
|
||||||
|
public void foo2() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@ShellMethod(value = "foo3")
|
||||||
|
public void foo3() {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.springframework.shell.CommandRegistry;
|
|||||||
import org.springframework.shell.ConfigurableCommandRegistry;
|
import org.springframework.shell.ConfigurableCommandRegistry;
|
||||||
import org.springframework.shell.MethodTarget;
|
import org.springframework.shell.MethodTarget;
|
||||||
import org.springframework.shell.ParameterResolver;
|
import org.springframework.shell.ParameterResolver;
|
||||||
|
import org.springframework.shell.context.DefaultShellContext;
|
||||||
import org.springframework.shell.standard.ShellMethod;
|
import org.springframework.shell.standard.ShellMethod;
|
||||||
import org.springframework.shell.standard.ShellOption;
|
import org.springframework.shell.standard.ShellOption;
|
||||||
import org.springframework.shell.standard.StandardParameterResolver;
|
import org.springframework.shell.standard.StandardParameterResolver;
|
||||||
@@ -42,7 +43,7 @@ public class AbstractCompletionsTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testBasicModelGeneration() {
|
public void testBasicModelGeneration() {
|
||||||
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
ConfigurableCommandRegistry commandRegistry = new ConfigurableCommandRegistry();
|
ConfigurableCommandRegistry commandRegistry = new ConfigurableCommandRegistry(new DefaultShellContext());
|
||||||
List<ParameterResolver> parameterResolvers = new ArrayList<>();
|
List<ParameterResolver> parameterResolvers = new ArrayList<>();
|
||||||
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
StandardParameterResolver resolver = new StandardParameterResolver(new DefaultConversionService(),
|
||||||
Collections.emptySet());
|
Collections.emptySet());
|
||||||
@@ -91,7 +92,7 @@ public class AbstractCompletionsTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testBuilder() {
|
public void testBuilder() {
|
||||||
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
ConfigurableCommandRegistry commandRegistry = new ConfigurableCommandRegistry();
|
ConfigurableCommandRegistry commandRegistry = new ConfigurableCommandRegistry(new DefaultShellContext());
|
||||||
List<ParameterResolver> parameterResolvers = new ArrayList<>();
|
List<ParameterResolver> parameterResolvers = new ArrayList<>();
|
||||||
TestCompletions completions = new TestCompletions(resourceLoader, commandRegistry, parameterResolvers);
|
TestCompletions completions = new TestCompletions(resourceLoader, commandRegistry, parameterResolvers);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.shell.ConfigurableCommandRegistry;
|
import org.springframework.shell.ConfigurableCommandRegistry;
|
||||||
import org.springframework.shell.ParameterResolver;
|
import org.springframework.shell.ParameterResolver;
|
||||||
|
import org.springframework.shell.context.DefaultShellContext;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ public class BashCompletionsTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoesNotError() {
|
public void testDoesNotError() {
|
||||||
ConfigurableCommandRegistry commandRegistry = new ConfigurableCommandRegistry();
|
ConfigurableCommandRegistry commandRegistry = new ConfigurableCommandRegistry(new DefaultShellContext());
|
||||||
List<ParameterResolver> parameterResolvers = new ArrayList<>();
|
List<ParameterResolver> parameterResolvers = new ArrayList<>();
|
||||||
BashCompletions completions = new BashCompletions(context, commandRegistry, parameterResolvers);
|
BashCompletions completions = new BashCompletions(context, commandRegistry, parameterResolvers);
|
||||||
String bash = completions.generate("root-command");
|
String bash = completions.generate("root-command");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.shell.ConfigurableCommandRegistry;
|
import org.springframework.shell.ConfigurableCommandRegistry;
|
||||||
import org.springframework.shell.MethodTarget;
|
import org.springframework.shell.MethodTarget;
|
||||||
|
import org.springframework.shell.context.DefaultShellContext;
|
||||||
import org.springframework.shell.standard.StandardMethodTargetRegistrar;
|
import org.springframework.shell.standard.StandardMethodTargetRegistrar;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
@@ -32,7 +33,7 @@ public class CalculatorCommandsTest extends BaseCalculatorTest {
|
|||||||
|
|
||||||
private static final Class<CalculatorCommands> COMMAND_CLASS_UNDER_TEST = CalculatorCommands.class;
|
private static final Class<CalculatorCommands> COMMAND_CLASS_UNDER_TEST = CalculatorCommands.class;
|
||||||
|
|
||||||
private final ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry();
|
private final ConfigurableCommandRegistry registry = new ConfigurableCommandRegistry(new DefaultShellContext());
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CalculatorState state;
|
private CalculatorState state;
|
||||||
|
|||||||
Reference in New Issue
Block a user