A way to add a single command run mode without excluding interactive mode and script mode (Tested on spring-shell-starter::2.0.0.RELEASE).
Create a runner by analogy with ScriptShellApplicationRunner.
// Runs before ScriptShellApplicationRunner and InteractiveShellApplicationRunner
@Order(InteractiveShellApplicationRunner.PRECEDENCE - 200)
public class SingleCommandApplicationRunner implements ApplicationRunner {
private final Parser parser;
private final Shell shell;
private final ConfigurableEnvironment environment;
private final Set<String> allCommandNames;
public SingleCommandApplicationRunner(
Parser parser,
Shell shell,
ConfigurableEnvironment environment,
Set<CustomCommand> customCommands
) {
this.parser = parser;
this.shell = shell;
this.environment = environment;
this.allCommandNames = buildAllCommandNames(customCommands);
}
private Set<String> buildAllCommandNames(Collection<CustomCommand> customCommands) {
final Set<String> result = new HashSet<>();
customCommands.stream().map(CustomCommand::keys).flatMap(Collection::stream).forEach(result::add);
// default spring shell commands
result.addAll(asList("clear", "exit", "quit", "help", "script", "stacktrace"));
return result;
}
@Override
public void run(ApplicationArguments args) throws Exception {
final boolean singleCommand = haveCommand(args.getSourceArgs());
if (singleCommand) {
InteractiveShellApplicationRunner.disable(environment);
final String fullArgs = join(" ", args.getSourceArgs());
try (Reader reader = new StringReader(fullArgs);
FileInputProvider inputProvider = new FileInputProvider(reader, parser)) {
shell.run(inputProvider);
}
}
}
private boolean haveCommand(String... args) {
for (String arg : args) {
if (allCommandNames.contains(arg)) {
return true;
}
}
return false;
}
}
Register the runner as bean.
@Configuration
class ContextConfiguration {
@Autowired
private Shell shell;
@Bean
SingleCommandApplicationRunner singleCommandApplicationRunner(
Parser parser,
ConfigurableEnvironment environment,
Set<CustomCommand> customCommands
) {
return new SingleCommandApplicationRunner(parser, shell, environment, customCommands);
}
}
So that the runner starts only when the command is sent, we create an interface.
public interface CustomCommand {
Collection<String> keys();
}
Implement CustomCommand interface in each commands.
@ShellComponent
@RequiredArgsConstructor
class MyCommand implements CustomCommand {
private static final String KEY = "my-command";
@Override
public Collection<String> keys() {
return singletonList(KEY);
}
@ShellMethod(key = KEY, value = "My custom command.")
public AttributedString version() {
return "Hello, single command mode!";
}
}
Done!
Run in interactive mode:
java -jar myApp.jar
// 2021-01-14 19:28:16.911 INFO 67313 --- [main] com.nao4j.example.Application: Starting Application v1.0.0 using Java 1.8.0_275 on Apple-MacBook-Pro-15.local with PID 67313 (/Users/nao4j/example/target/myApp.jar started by nao4j in /Users/nao4j/example/target)
// 2021-01-14 19:28:16.916 INFO 67313 --- [main] com.nao4j.example.Application: No active profile set, falling back to default profiles: default
// 2021-01-14 19:28:18.227 INFO 67313 --- [main] com.nao4j.example.Application: Started Application in 2.179 seconds (JVM running for 2.796)
// shell:>my-command
// Hello, single command mode!
Run script from file script.txt (contains text "my-command"):
java -jar myApp.jar @script.txt
// 2021-01-14 19:28:16.911 INFO 67313 --- [main] com.nao4j.example.Application: Starting Application v1.0.0 using Java 1.8.0_275 on Apple-MacBook-Pro-15.local with PID 67313 (/Users/nao4j/example/target/myApp.jar started by nao4j in /Users/nao4j/example/target)
// 2021-01-14 19:28:16.916 INFO 67313 --- [main] com.nao4j.example.Application: No active profile set, falling back to default profiles: default
// 2021-01-14 19:28:18.227 INFO 67313 --- [main] com.nao4j.example.Application: Started Application in 2.179 seconds (JVM running for 2.796)
// Hello, single command mode!
Run in single command mode:
java -jar myApp.jar my-command
// 2021-01-14 19:28:16.911 INFO 67313 --- [main] com.nao4j.example.Application: Starting Application v1.0.0 using Java 1.8.0_275 on Apple-MacBook-Pro-15.local with PID 67313 (/Users/nao4j/example/target/myApp.jar started by nao4j in /Users/nao4j/example/target)
// 2021-01-14 19:28:16.916 INFO 67313 --- [main] com.nao4j.example.Application: No active profile set, falling back to default profiles: default
// 2021-01-14 19:28:18.227 INFO 67313 --- [main] com.nao4j.example.Application: Started Application in 2.179 seconds (JVM running for 2.796)
// Hello, single command mode!