Update docs
This commit is contained in:
@@ -12,3 +12,17 @@ Essentially few things needs to happen before you have a working _spring shell_
|
||||
|
||||
You will get a full working _spring shell_ application without defining any user level commands
|
||||
as some basic build-in commands are provided out of a box like `help` and `history`.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Throughout this documentation we make a references to configuring something using
|
||||
annotations which mostly relates to use of `@ShellMethod` and `@ShellOption` and
|
||||
programmatic way which relates to use of `CommandRegistration`.
|
||||
|
||||
Programmatic model is how things are actually registered even if you use annotations.
|
||||
Annotations `@ShellMethod` and `@ShellOption` are considered as legacy feature
|
||||
which we don't yet want to remove. `CommandRegistration` is a new development
|
||||
model where new features are added. We are most likely going to replace existing
|
||||
annotations with something better order to support new features in a
|
||||
`CommandRegistration` model.
|
||||
====
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
==== Customizing the Shell
|
||||
|
||||
[[overriding-or-disabling-built-in-commands]]
|
||||
===== Overriding or Disabling Built-In Commands
|
||||
|
||||
Spring Shell provides <<built-in-commands,Built-in commands>> to let people achieve everyday tasks that many if not
|
||||
all shell applications need. If you are not happy with the way they behave, though, you can disable or override them,
|
||||
as explained in this section.
|
||||
|
||||
[TIP]
|
||||
.Disabling all Built-in Commands
|
||||
=====
|
||||
If you do not need built-in commands at all, there is an easy way to "`disable`" them: don't include them.
|
||||
Either use a maven exclusion on `spring-shell-standard-commands` or, if you are selectively including Spring Shell
|
||||
dependencies, don't include that one in. The follwoing example shows how to exclude `spring-shell-standard-commands`:
|
||||
|
||||
====
|
||||
[source,xml,subs=attributes+]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.shell</groupId>
|
||||
<artifactId>{starter-artifactId}</artifactId>
|
||||
<version>{project-version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.shell</groupId>
|
||||
<artifactId>spring-shell-standard-commands</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
=====
|
||||
|
||||
[[disabling-specific-commands]]
|
||||
====== Disabling Specific Commands
|
||||
|
||||
To disable a single built-in command, set the `spring.shell.command.<command>.enabled` property to `false` in the
|
||||
application `Environment`. One way to do so is to pass extra arguments to the Boot application in your `main()`
|
||||
entry point:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public static void main(String[] args) throws Exception {
|
||||
String[] disabledCommands = {"--spring.shell.command.help.enabled=false"}; // <1>
|
||||
String[] fullArgs = StringUtils.concatenateStringArrays(args, disabledCommands);
|
||||
SpringApplication.run(MyApp.class, fullArgs);
|
||||
}
|
||||
----
|
||||
<1> This disables the integrated `help` command
|
||||
====
|
||||
|
||||
====== Overriding Specific Commands
|
||||
|
||||
If, instead of disabling a command, you would rather provide your own implementation, then you can either:
|
||||
|
||||
* Disable the command as explained <<disabling-specific-commands,earlier>> and have your implementation registered
|
||||
with the same name.
|
||||
* Have your implementing class implement the `<Command>.Command` interface. As an example, here is how
|
||||
to override the `clear` command:
|
||||
+
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public class MyClear implements Clear.Command {
|
||||
|
||||
@ShellMethod("Clear the screen, only better.")
|
||||
public void clear() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
.Please Consider Contributing your Changes
|
||||
====
|
||||
If you feel like your implementation of a standard command could be valuable to the community,
|
||||
please open a pull-request at https://github.com/spring-projects/spring-shell.
|
||||
|
||||
Alternatively, before making any changes on your own, you can open an issue with the project. Feedback is
|
||||
always welcome!
|
||||
====
|
||||
|
||||
// ==== ResultHandlers
|
||||
|
||||
// TBD
|
||||
|
||||
===== PromptProvider
|
||||
After each command invocation, the shell waits for new input from the user, displaying
|
||||
a prompt in yellow:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>
|
||||
----
|
||||
====
|
||||
|
||||
It is possible to customize this behavior by registering a bean of type `PromptProvider`.
|
||||
Such a bean may use internal state to decide what to display to the user (it may, for example,
|
||||
react to https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-functionality-events-annotation[application events])
|
||||
and can use JLine's `AttributedCharSequence` to display fancy ANSI text.
|
||||
|
||||
The following example shows how to use a `PromptProvider`:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Component
|
||||
public class CustomPromptProvider implements PromptProvider {
|
||||
|
||||
private ConnectionDetails connection;
|
||||
|
||||
@Override
|
||||
public AttributedString getPrompt() {
|
||||
if (connection != null) {
|
||||
return new AttributedString(connection.getHost() + ":>",
|
||||
AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW));
|
||||
}
|
||||
else {
|
||||
return new AttributedString("server-unknown:>",
|
||||
AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void handle(ConnectionUpdatedEvent event) {
|
||||
this.connection = event.getConnectionDetails();
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
===== Customizing Command Line Options Behavior
|
||||
|
||||
There can be exactly one shell spesific `ShellApplicationRunner` which simply extends
|
||||
Boot's `ApplicationRunner`. Default behariour is to have actual runner logic in
|
||||
various `ShellRunner` implementations where candidate will be picked up.
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
This is a breaking change in `2.1.x` as previous shell versions had an confusing
|
||||
logic how `ApplicationRunner` instances were used. These changes were made
|
||||
to have a better support for interactive and non-interactive modes in a same
|
||||
shell application as it's convenient to fully work on command-line and still
|
||||
have ability to enter interactive mode.
|
||||
|
||||
You can override bean type of `ShellApplicationRunner` if there's a need to
|
||||
customise shell running logic.
|
||||
====
|
||||
|
||||
===== Customizing Arguments Conversion
|
||||
|
||||
Conversion from text input to actual method arguments uses the standard Spring
|
||||
https://docs.spring.io/spring/docs/4.3.11.RELEASE/spring-framework-reference/htmlsingle/#core-convert[conversion] mechanism.
|
||||
Spring Shell installs a new `DefaultConversionService` (with built-in converters enabled)
|
||||
and registers to it any bean of type `Converter<S, T>`, `GenericConverter`, or
|
||||
`ConverterFactory<S, T>` that it finds in the application context.
|
||||
|
||||
This means that you can customize conversion to your custom objects
|
||||
by installing a `Converter<String, Foo>` bean in the context:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellComponent
|
||||
class ConversionCommands {
|
||||
|
||||
@ShellMethod("Shows conversion using Spring converter")
|
||||
public String conversionExample(DomainObject object) {
|
||||
return object.getClass();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DomainObject {
|
||||
private final String value;
|
||||
|
||||
DomainObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
class CustomDomainConverter implements Converter<String, DomainObject> {
|
||||
|
||||
@Override
|
||||
public DomainObject convert(String source) {
|
||||
return new DomainObject(source);
|
||||
}
|
||||
}
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
[TIP]
|
||||
.Mind your String representation
|
||||
=====
|
||||
As in the preceding example, you should have
|
||||
your `toString()` implementations return the converse of what was used
|
||||
to create the object instance. This is because, when a value fails
|
||||
validation, Spring Shell prints:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
The following constraints were not met:
|
||||
--arg <type> : <message> (You passed '<value.toString()>')
|
||||
----
|
||||
====
|
||||
|
||||
See <<validating-command-arguments>> for more information.
|
||||
=====
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
If you want to customize the `ConversionService` further, you can:
|
||||
|
||||
* Have the default one injected in your code and act upon it in some way.
|
||||
* Override it altogether with your own (custom converters need to be registered by hand).
|
||||
The `ConversionService` used by Spring Shell needs to be https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers[qualified] as `"spring-shell"`.
|
||||
====
|
||||
@@ -0,0 +1,44 @@
|
||||
[[using-shell-options-arity]]
|
||||
==== Arity
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Sometimes you want to have more fine control of how many parameters with an option
|
||||
are processed when parsing operation happens. Arity is defined as min and max
|
||||
values where min must be positive integer and max has to be more or equal to min.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-arityints]
|
||||
----
|
||||
====
|
||||
|
||||
Arity can also be defined as an `OptionArity` enum which are shortcuts
|
||||
with table shown below.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-arityenum]
|
||||
----
|
||||
====
|
||||
|
||||
.OptionArity
|
||||
|===
|
||||
|Value |min/max
|
||||
|
||||
|ZERO
|
||||
|0 / 0
|
||||
|
||||
|ZERO_OR_ONE
|
||||
|0 / 1
|
||||
|
||||
|EXACTLY_ONE
|
||||
|1 / 1
|
||||
|
||||
|ZERO_OR_MORE
|
||||
| 0 / Integer MAX
|
||||
|
||||
|ONE_OR_MORE
|
||||
|1 / Integer MAX
|
||||
|===
|
||||
@@ -0,0 +1,15 @@
|
||||
[[using-shell-options-default]]
|
||||
==== Default Value
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Having a default value for an option is somewhat related to
|
||||
<<using-shell-options-optional>> as there are cases where you
|
||||
may want to know if user defined an option and make a difference
|
||||
based on a default value.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-default]
|
||||
----
|
||||
====
|
||||
@@ -0,0 +1,35 @@
|
||||
[[using-shell-options-definition]]
|
||||
==== Definition
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Options can be defined within a target method as annotations in a method arguments
|
||||
or with programmatically with `CommandRegistration`.
|
||||
|
||||
Having a target method with argument is automatically registered with a matching
|
||||
argument name.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-without-annotation]
|
||||
----
|
||||
====
|
||||
|
||||
`@ShellOption` annotation can be used to define an option name if you
|
||||
don't want it to be same as argument name.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-with-annotation]
|
||||
----
|
||||
====
|
||||
|
||||
Programmatic way with `CommandRegistration` is to use method adding a long name.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-longarg]
|
||||
----
|
||||
====
|
||||
@@ -0,0 +1,13 @@
|
||||
[[using-shell-options-optional]]
|
||||
==== Optional Value
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Option is either required or not and it generally speaking depends on
|
||||
a command target how this behaves.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-optional]
|
||||
----
|
||||
====
|
||||
@@ -0,0 +1,12 @@
|
||||
[[using-shell-options-positional]]
|
||||
==== Positional
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Positional information is mostly related to a command target method.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-positional]
|
||||
----
|
||||
====
|
||||
@@ -0,0 +1,27 @@
|
||||
[[using-shell-options-short]]
|
||||
==== Short Format
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Short style _POSIX_ option in most is just a synonym to long format but
|
||||
adds additional feature to combine those options together. Having short
|
||||
options _a_, _b_, _c_ can be used as `-abc`.
|
||||
|
||||
Programmatically short option is defined by using short name function.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-shortarg]
|
||||
----
|
||||
====
|
||||
|
||||
Short option with combined format is powerful if type is defined as a flag
|
||||
which means type is a _boolean_. That way you can define a presense of a flags
|
||||
as `-abc`, `-abc true` or `-abc false`.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-shortargbooleans]
|
||||
----
|
||||
====
|
||||
@@ -1,5 +1,5 @@
|
||||
[[validating-command-arguments]]
|
||||
==== Validating Command Arguments
|
||||
==== Validation
|
||||
|
||||
Spring Shell integrates with the https://beanvalidation.org/[Bean Validation API] to support
|
||||
automatic and self-documenting constraints on command parameters.
|
||||
@@ -27,7 +27,10 @@ The following constraints were not met:
|
||||
----
|
||||
====
|
||||
|
||||
[NOTE]
|
||||
.Applies to All Command Implementations
|
||||
NOTE: It is important to note that bean validation applies to all command implementations, whether
|
||||
they use the "standard" API or any other API, through the use of an adapter
|
||||
====
|
||||
It is important to note that bean validation applies to all command implementations,
|
||||
whether they use the "standard" API or any other API, through the use of an adapter
|
||||
(see <<support-for-shell-1-and-jcommander,Supporting Other APIs>>)
|
||||
====
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
[[using-shell-options]]
|
||||
=== Options
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
include::using-shell-options-generic.adoc[]
|
||||
Command line arguments can be separated into options and positional parameters.
|
||||
Following sections describes features how options are defined and used.
|
||||
|
||||
include::using-shell-options-definition.adoc[]
|
||||
|
||||
include::using-shell-options-short.adoc[]
|
||||
|
||||
include::using-shell-options-arity.adoc[]
|
||||
|
||||
include::using-shell-options-positional.adoc[]
|
||||
|
||||
include::using-shell-options-optional.adoc[]
|
||||
|
||||
include::using-shell-options-default.adoc[]
|
||||
|
||||
include::using-shell-options-validation.adoc[]
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.springframework.shell.docs;
|
||||
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.command.CommandRegistration.OptionArity;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
|
||||
public class OptionSnippets {
|
||||
|
||||
class Dump1 {
|
||||
// tag::option-with-annotation[]
|
||||
public String example(@ShellOption(value = { "argx" }) String arg1) {
|
||||
return "Hello " + arg1;
|
||||
}
|
||||
// end::option-with-annotation[]
|
||||
}
|
||||
|
||||
class Dump2 {
|
||||
// tag::option-without-annotation[]
|
||||
public String example(String arg1) {
|
||||
return "Hello " + arg1;
|
||||
}
|
||||
// end::option-without-annotation[]
|
||||
}
|
||||
|
||||
public void dump1() {
|
||||
|
||||
// tag::option-registration-longarg[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-longarg[]
|
||||
|
||||
// tag::option-registration-shortarg[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.shortNames('a')
|
||||
.and()
|
||||
.withOption()
|
||||
.shortNames('b')
|
||||
.and()
|
||||
.withOption()
|
||||
.shortNames('c')
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-shortarg[]
|
||||
|
||||
// tag::option-registration-shortargbooleans[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.shortNames('a')
|
||||
.type(boolean.class)
|
||||
.and()
|
||||
.withOption()
|
||||
.shortNames('b')
|
||||
.type(boolean.class)
|
||||
.and()
|
||||
.withOption()
|
||||
.shortNames('c')
|
||||
.type(boolean.class)
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-shortargbooleans[]
|
||||
|
||||
// tag::option-registration-arityenum[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.arity(OptionArity.EXACTLY_ONE)
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-arityenum[]
|
||||
|
||||
// tag::option-registration-arityints[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.arity(0, 1)
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-arityints[]
|
||||
|
||||
// tag::option-registration-optional[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.required()
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-optional[]
|
||||
|
||||
// tag::option-registration-positional[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.position(0)
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-positional[]
|
||||
|
||||
// tag::option-registration-default[]
|
||||
CommandRegistration.builder()
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.defaultValue("defaultValue")
|
||||
.and()
|
||||
.build();
|
||||
// end::option-registration-default[]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user