Migrate docs to antora
- This is basically copy from main branch minus all terminal ui things. - Relates #971
@@ -1,5 +0,0 @@
|
||||
[appendix]
|
||||
[#appendix-debugging]
|
||||
== Debugging
|
||||
|
||||
Please find more info about debugging from https://github.com/spring-projects/spring-shell/wiki/Debugging[project wiki].
|
||||
@@ -1,43 +0,0 @@
|
||||
=== Command Catalog
|
||||
The `CommandCatalog` interface defines how command registrations exist in
|
||||
a shell application. It is possible to dynamically register and de-register
|
||||
commands, which gives flexibility for use cases where possible commands
|
||||
come and go, depending on a shell's state. Consider the following example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandCatalogSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
==== Command Resolver
|
||||
You can implement the `CommandResolver` interface and define a bean to dynamically
|
||||
resolve mappings from a command's name to its `CommandRegistration` instances. Consider
|
||||
the following example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandCatalogSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
|
||||
IMPORTANT: A current limitation of a `CommandResolver` is that it is used every time commands are resolved.
|
||||
Thus, we advise not using it if a command resolution call takes a long time, as it would
|
||||
make the shell feel sluggish.
|
||||
|
||||
==== Command Catalog Customizer
|
||||
You can use the `CommandCatalogCustomizer` interface to customize a `CommandCatalog`.
|
||||
Its main use is to modify a catalog. Also, within `spring-shell` auto-configuration, this
|
||||
interface is used to register existing `CommandRegistration` beans into a catalog.
|
||||
Consider the following example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandCatalogSnippets.java[tag=snippet3]
|
||||
----
|
||||
====
|
||||
|
||||
You can create a `CommandCatalogCustomizer` as a bean, and Spring Shell handles the rest.
|
||||
@@ -1,20 +0,0 @@
|
||||
=== Command Context
|
||||
The `CommandContext` interface gives access to a currently running
|
||||
context. You can use it to get access to options:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandContextSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
If you need to print something into a shell, you can get a `Terminal`
|
||||
and use its writer to print something:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandContextSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
@@ -1,3 +0,0 @@
|
||||
=== Command Execution
|
||||
When command parsing has done its job and command registration has been resolved, command execution
|
||||
does the hard work of running the code.
|
||||
@@ -1,3 +0,0 @@
|
||||
=== Command Parser
|
||||
Before a command can be executed, we need to parse the command and whatever options the user may have provided. Parsing
|
||||
comes between command registration and command execution.
|
||||
@@ -1,105 +0,0 @@
|
||||
[#appendix-tech-intro-registration]
|
||||
=== Command Registration
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Defining a command registration is a first step to introducing the structure of a command and its options
|
||||
and parameters. This is loosely decoupled from what happens later, such as parsing command-line input and running
|
||||
actual target code. Essentially, it is the definition of a command API that is shown to a user.
|
||||
|
||||
==== Commands
|
||||
A command in a `spring-shell` structure is defined as an array of commands. This yields a
|
||||
structure similar to the following example:
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
command1 sub1
|
||||
command2 sub1 subsub1
|
||||
command2 sub2 subsub1
|
||||
command2 sub2 subsub2
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: We do not currently support mapping commands to an explicit parent if sub-commands are defined.
|
||||
For example, `command1 sub1` and `command1 sub1 subsub1` cannot both be registered.
|
||||
|
||||
==== Interaction Mode
|
||||
Spring Shell has been designed to work on two modes: interactive (which essentially
|
||||
is a `REPL` where you have an active shell instance throughout a series of commands) and
|
||||
non-interactive (where commands are executed one by one from a command line).
|
||||
|
||||
Differentation between these modes is mostly around limitations about what can be done
|
||||
in each mode. For example, it would not be feasible to show what was a previous stacktrace
|
||||
of a command if the shell is no longer active. Generally, whether the shell is still active
|
||||
dictates the available information.
|
||||
|
||||
Also, being on an active `REPL` session may provide more information about what the user has been
|
||||
doing within an active session.
|
||||
|
||||
==== Options
|
||||
Options can be defined as long and short, where the prefixing is `--` and `-`, respectively.
|
||||
The following examples show long and short options:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
|
||||
==== Target
|
||||
The target defines the execution target of a command. It can be a method in a POJO,
|
||||
a `Consumer`, or a `Function`.
|
||||
|
||||
===== Method
|
||||
Using a `Method` in an existing POJO is one way to define a target.
|
||||
Consider the following class:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandTargetSnippets.java[tag=snippet11]
|
||||
----
|
||||
====
|
||||
|
||||
Given the existing class shown in the preceding listing, you can then register its method:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandTargetSnippets.java[tag=snippet12]
|
||||
----
|
||||
====
|
||||
|
||||
===== Function
|
||||
Using a `Function` as a target gives a lot of flexibility to handle what
|
||||
happens in a command execution, because you can handle many things manually by using
|
||||
a `CommandContext` given to a `Function`. The return type from a `Function` is
|
||||
then what gets printed into the shell as a result. Consider the following example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandTargetSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
|
||||
===== Consumer
|
||||
Using a `Consumer` is basically the same as using a `Function`, with the difference being
|
||||
that there is no return type. If you need to print something into a shell,
|
||||
you can get a reference to a `Terminal` from a context and print something
|
||||
through it. Consider the following example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandTargetSnippets.java[tag=snippet3]
|
||||
----
|
||||
====
|
||||
@@ -1,65 +0,0 @@
|
||||
[#appendix-tech-intro-searchalgorithm]
|
||||
=== Search Algorithms
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
`SearchMatch` is an interface to match _text_ with a _pattern_. Match
|
||||
results are in a returned value `SearchMatchResult`. Match result
|
||||
contains info about match positions and overall score of a match.
|
||||
|
||||
https://github.com/junegunn/fzf[fzf].
|
||||
|
||||
==== Implementations
|
||||
|
||||
*FuzzyMatchV2Search*
|
||||
|
||||
Port of _fzf FuzzyMatchV2Search_ algorithm. Does a fast fuzzy search and is good
|
||||
quickly finding paths.
|
||||
|
||||
*ExactMatchNaive*
|
||||
|
||||
Port of _fzf ExactMatchNaive_ algorithm. Simple exact match works more accurately
|
||||
if you know what to search.
|
||||
|
||||
==== SearchMatch
|
||||
|
||||
Algorithms and default syntax are hidden inside package protected classes
|
||||
as we don't want to fully open these until we know API's are good to go
|
||||
for longer support. You need to construct `SearchMatch` via its
|
||||
build-in builder.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/SearchAlgorithmsSnippets.java[tag=builder]
|
||||
----
|
||||
====
|
||||
|
||||
It's possible to configure _case sensitivity_, on what _direction_ search
|
||||
happens or if text should be _normilized_ before search happens. Normalization
|
||||
is handy when different languages have sligh variation for same type
|
||||
of characters.
|
||||
|
||||
Search algorithm is selected based on a search syntax shown in
|
||||
below table.
|
||||
|
||||
.Search syntax
|
||||
|===
|
||||
|Token |Match type |Description
|
||||
|
||||
|`hell`
|
||||
|fuzzy-match
|
||||
|Items that match `hello`
|
||||
|
||||
|`'stuff`
|
||||
|exact-match
|
||||
|Items that include `stuff`
|
||||
|===
|
||||
|
||||
==== Examples
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/SearchAlgorithmsSnippets.java[tag=simple]
|
||||
----
|
||||
====
|
||||
@@ -1,60 +0,0 @@
|
||||
[#appendix-tech-intro-theming]
|
||||
=== Theming
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Styling in a theming is provided by a use of a _AttributedString_ from `JLine`.
|
||||
Unfortunately styling in `JLine` is mostly undocumented but we try to go through
|
||||
some of its features here.
|
||||
|
||||
In `JLine` a style spec is a string having a special format. Spec can be given
|
||||
multiple times if separated by a comma. A spec will either define a color for
|
||||
foreground, background or its mode. Special format `<spec>:=<spec>` allows to
|
||||
define a default within latter spec if former for some reason is invalid.
|
||||
|
||||
If spec contains a colon its former part indicates either foreground or background
|
||||
and possible values are `foreground`, `fg`, `f`, `background`, `bg`, `b`, `foreground-rgb`,
|
||||
`fg-rgb`, `f-rgb`, `background-rgb`, `bg-rgb` or `b-rgb`. Without rbg a color value
|
||||
is name from an allowable colors `black`, `red`, `green`, `yellow`, `blue`, `magenta`,
|
||||
`cyan` or `white`. Colors have their short formats `k`, `r`, `g`, `y`, `b`, `m`, `c` and `w`
|
||||
respectively. If color is prefixed with either `!` or `bright-`, bright mode is automatically
|
||||
applied. Prefixing with `~` will resolve from JLine internal bsd color table.
|
||||
|
||||
If rgb format is expected and prefixed with either `x` or `#` a normal
|
||||
hex format is used.
|
||||
|
||||
====
|
||||
[source, text]
|
||||
----
|
||||
fg-red
|
||||
fg-r
|
||||
fg-rgb:red
|
||||
fg-rgb:xff3333
|
||||
fg-rgb:#ff3333
|
||||
----
|
||||
====
|
||||
|
||||
If spec contains special names `default`, `bold`, `faint`, `italic`, `underline`, `blink`,
|
||||
`inverse`, `inverse-neg`, `inverseneg`, `conceal`, `crossed-out`, `crossedout` or `hidden`
|
||||
a style is changed accordingly with an existing color.
|
||||
|
||||
====
|
||||
[source, text]
|
||||
----
|
||||
bold
|
||||
bold,fg:red
|
||||
----
|
||||
====
|
||||
|
||||
If spec is a number or numbers separated with semicolon, format is a plain part of an ansi
|
||||
ascii codes.
|
||||
|
||||
====
|
||||
[source, text]
|
||||
----
|
||||
31
|
||||
31;1
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: JLine special mapping format which would resolve spec starting with dot can't be
|
||||
used as we don't yet map those into Spring Shell styling names.
|
||||
@@ -1,19 +0,0 @@
|
||||
[appendix]
|
||||
[#appendix-tech-intro]
|
||||
== Techical Introduction
|
||||
This appendix contains information for developers and others who would like to know more about how Spring Shell
|
||||
works internally and what its design decisions are.
|
||||
|
||||
include::appendices-techical-intro-registration.adoc[]
|
||||
|
||||
include::appendices-techical-intro-parser.adoc[]
|
||||
|
||||
include::appendices-techical-intro-execution.adoc[]
|
||||
|
||||
include::appendices-techical-intro-commandcontext.adoc[]
|
||||
|
||||
include::appendices-techical-intro-commandcatalog.adoc[]
|
||||
|
||||
include::appendices-techical-intro-theming.adoc[]
|
||||
|
||||
include::appendices-techical-intro-searchalgorithm.adoc[]
|
||||
@@ -1,3 +0,0 @@
|
||||
include::appendices-techical-intro.adoc[]
|
||||
|
||||
include::appendices-debugging.adoc[]
|
||||
@@ -1,35 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 8, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[1.590847, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
|
||||
[2.774407, "o", "\r\n"]
|
||||
[4.560309, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[5.138757, "o", "\u001b[31mc\u001b[0m"]
|
||||
[5.267214, "o", "\u001b[31mo\u001b[0m"]
|
||||
[5.467126, "o", "\u001b[31mm\u001b[0m"]
|
||||
[5.674049, "o", "\u001b[31mp\u001b[0m"]
|
||||
[5.752663, "o", "\u001b[31mo\u001b[0m"]
|
||||
[5.917741, "o", "\u001b[31mn\u001b[0m"]
|
||||
[6.040844, "o", "\u001b[31me\u001b[0m"]
|
||||
[6.123068, "o", "\u001b[31mn\u001b[0m"]
|
||||
[6.277935, "o", "\u001b[31mt\u001b[0m"]
|
||||
[7.050283, "o", "\u001b[31m \u001b[0m"]
|
||||
[7.413917, "o", "\u001b[31mc\u001b[0m"]
|
||||
[7.568894, "o", "\u001b[31mo\u001b[0m"]
|
||||
[7.664856, "o", "\u001b[31mn\u001b[0m"]
|
||||
[7.853492, "o", "\u001b[13D\u001b[1mcomponent confirmation\u001b[0m \u001b[K"]
|
||||
[8.698242, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[8.745928, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[8.803411, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \u001b[2m(Y/n)\u001b[0m\r"]
|
||||
[13.769588, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[13.779021, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \u001b[34mtrue\u001b[0m\r\n"]
|
||||
[13.779319, "o", "Got value true\r\n"]
|
||||
[13.781245, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[15.955396, "o", "\u001b[1mcomponent confirmation\u001b[0m"]
|
||||
[16.743244, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l"]
|
||||
[16.743555, "o", "\u001b[?2004l"]
|
||||
[16.748638, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[16.754861, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \u001b[2m(Y/n)\u001b[0m\r"]
|
||||
[19.347907, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[19.355493, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \u001b[34mfalse\u001b[0m\r\n"]
|
||||
[19.356618, "o", "Got value false\r\n"]
|
||||
[19.3586, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[21.3586, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,40 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 11, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[1.590847, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
|
||||
[5.030349, "o", "\r\n"]
|
||||
[7.108752, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[7.604731, "o", "\u001b[31mf\u001b[0m"]
|
||||
[7.754184, "o", "\u001b[31ml\u001b[0m"]
|
||||
[7.98951, "o", "\u001b[31mo\u001b[0m"]
|
||||
[8.405578, "o", "\u001b[31mw\u001b[0m"]
|
||||
[8.763007, "o", "\u001b[31m \u001b[0m"]
|
||||
[8.963478, "o", "\u001b[31mc\u001b[0m"]
|
||||
[9.036017, "o", "\u001b[31mo\u001b[0m"]
|
||||
[9.353476, "o", "\u001b[31mn\u001b[0m"]
|
||||
[9.517639, "o", "\u001b[8D\u001b[1mflow conditional\u001b[0m \u001b[K"]
|
||||
[10.036978, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[10.115908, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[10.176519, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mSingle1\u001b[0m [Use arrows to move], type to filter\u001b[97C \u001b[96;1m>\u001b[0m\u001b[96;1m Field1\u001b[0m\u001b[135C Field2\u001b[2A\r"]
|
||||
[11.824714, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\u001b[2A"]
|
||||
[11.835781, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mSingle1\u001b[0m \u001b[34mfield1\u001b[0m\r\n"]
|
||||
[11.838786, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[11.844824, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField1\u001b[0m \u001b[34m[Default defaultField1Value]\u001b[0m\r"]
|
||||
[12.734384, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[12.740754, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField1\u001b[0m \u001b[34mdefaultField1Value\u001b[0m\r\n"]
|
||||
[12.74362, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[13.547149, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[14.091367, "o", "\u001b[1mflow conditional\u001b[0m"]
|
||||
[14.419251, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[14.424986, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[14.432116, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mSingle1\u001b[0m [Use arrows to move], type to filter\u001b[97C \u001b[96;1m>\u001b[0m\u001b[96;1m Field1\u001b[0m\u001b[135C Field2\u001b[2A\r"]
|
||||
[14.995304, "o", "\r\r\n Field1\r\r\n\u001b[96;1m> Field2\u001b[0m\u001b[2A\r"]
|
||||
[15.409104, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\u001b[2A"]
|
||||
[15.416729, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mSingle1\u001b[0m \u001b[34mfield2\u001b[0m\r\n"]
|
||||
[15.41833, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[15.424318, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField2\u001b[0m \u001b[34m[Default defaultField2Value]\u001b[0m\r"]
|
||||
[16.002129, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[16.007474, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField2\u001b[0m \u001b[34mdefaultField2Value\u001b[0m\r\n"]
|
||||
[16.010197, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[19.865275, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l"]
|
||||
[19.865497, "o", "\u001b[?2004l"]
|
||||
[19.868634, "o", "\u001b[31morg.jline.reader.EndOfFileException\u001b[0m\r\n\u001b[31mDetails of the error have been omitted. You can use the \u001b[1mstacktrace\u001b[22m command to print the full stacktrace.\u001b[0m\r\n"]
|
||||
[19.870354, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,42 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 15, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[1.590847, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
|
||||
[5.968022, "o", "\r\n"]
|
||||
[8.099727, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[11.261894, "o", "\u001b[1mflow showcase\u001b[0m"]
|
||||
[12.6451, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[12.721206, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[12.780227, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField1\u001b[0m \u001b[34m[Default defaultField1Value]\u001b[0m\r"]
|
||||
[14.703281, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[14.711232, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField1\u001b[0m \u001b[34mdefaultField1Value\u001b[0m\r\n"]
|
||||
[14.713588, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[14.720745, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField2\u001b[0m \r"]
|
||||
[16.084492, "o", "\u001b[9Ch\r"]
|
||||
[16.176942, "o", "\u001b[10Ci\r"]
|
||||
[16.620009, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[16.625711, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mField2\u001b[0m \u001b[34mhi\u001b[0m\r\n"]
|
||||
[16.628041, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[16.633919, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mConfirmation1\u001b[0m \u001b[2m(Y/n)\u001b[0m\r"]
|
||||
[20.090558, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[20.098654, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mConfirmation1\u001b[0m \u001b[34mtrue\u001b[0m\r\n"]
|
||||
[20.101548, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[20.105099, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mPath1\u001b[0m \r"]
|
||||
[21.53213, "o", "\u001b[8Cp\u001b[134C \u001b[32m>\u001b[0m \u001b[32mPath ok\u001b[0m\u001b[A\r"]
|
||||
[21.626297, "o", "\u001b[9Ca\r"]
|
||||
[21.896442, "o", "\u001b[10Ct\r"]
|
||||
[21.941151, "o", "\u001b[11Ch\r"]
|
||||
[23.041717, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\u001b[A"]
|
||||
[23.044506, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mPath1\u001b[0m \u001b[34mpath\u001b[0m\r\n"]
|
||||
[23.049225, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[23.05459, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mSingle1\u001b[0m [Use arrows to move], type to filter\u001b[97C \u001b[96;1m>\u001b[0m\u001b[96;1m key1\u001b[0m\u001b[137C key2\u001b[2A\r"]
|
||||
[24.520415, "o", "\r\r\n key1\r\r\n\u001b[96;1m> key2\u001b[0m\u001b[2A\r"]
|
||||
[25.431855, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\u001b[2A"]
|
||||
[25.438619, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mSingle1\u001b[0m \u001b[34mvalue2\u001b[0m\r\n"]
|
||||
[25.441975, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[25.446547, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mMulti1\u001b[0m [Use arrows to move], type to filter\u001b[98C \u001b[96;1m>\u001b[0m\u001b[96;1m \u001b[39m[ ]\u001b[0m key1\u001b[133C \u001b[1m[ ]\u001b[0m key2\u001b[133C \u001b[1m[ ]\u001b[0m key3\u001b[3A\r"]
|
||||
[26.698294, "o", "\r\r\n\u001b[2C\u001b[32m[x]\u001b[0m\u001b[A\r"]
|
||||
[28.022787, "o", "\r\r\n \r\r\n\u001b[96;1m> \u001b[0m\u001b[2A\r"]
|
||||
[28.110824, "o", "\r\r\n\r\n\u001b[2C\u001b[32m[x]\u001b[0m\u001b[2A\r"]
|
||||
[29.250629, "o", "\r\r\n\r\n\u001b[2C\u001b[1m[ ]\u001b[0m\u001b[2A\r"]
|
||||
[30.360368, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\u001b[3A"]
|
||||
[30.368273, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mMulti1\u001b[0m \u001b[34mvalue1\u001b[0m\r\n"]
|
||||
[30.370638, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,42 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 9, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[1.746447, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
|
||||
[2.881033, "o", "\r\n"]
|
||||
[4.603396, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[5.105471, "o", "\u001b[31mc\u001b[0m"]
|
||||
[5.202878, "o", "\u001b[31mo\u001b[0m"]
|
||||
[5.428705, "o", "\u001b[31mm\u001b[0m"]
|
||||
[5.630033, "o", "\u001b[31mp\u001b[0m"]
|
||||
[5.692044, "o", "\u001b[31mo\u001b[0m"]
|
||||
[5.86652, "o", "\u001b[31mn\u001b[0m"]
|
||||
[6.018765, "o", "\u001b[31me\u001b[0m"]
|
||||
[6.089776, "o", "\u001b[31mn\u001b[0m"]
|
||||
[6.251781, "o", "\u001b[31mt\u001b[0m"]
|
||||
[7.126694, "o", "\u001b[31m \u001b[0m"]
|
||||
[7.319912, "o", "\u001b[31mm\u001b[0m"]
|
||||
[7.550772, "o", "\u001b[31mu\u001b[0m"]
|
||||
[7.80087, "o", "\u001b[12D\u001b[1mcomponent multi\u001b[0m \u001b[K"]
|
||||
[8.291497, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[8.338879, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[8.398742, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mtestSimple\u001b[0m [Use arrows to move], type to filter\u001b[54C \u001b[96;1m>\u001b[0m\u001b[96;1m \u001b[39m[ ]\u001b[0m key1\u001b[93C \u001b[2m[ ]\u001b[0m \u001b[2mkey2\u001b[0m\u001b[93C \u001b[1m[ ]\u001b[0m key3\u001b[3A\r"]
|
||||
[12.265649, "o", "\u001b[35Cfiltering 'k'\u001b[K\r"]
|
||||
[12.507991, "o", "\u001b[47C\u001b[1@e\r"]
|
||||
[12.945812, "o", "\u001b[48C\u001b[1@y\r"]
|
||||
[13.35949, "o", "\u001b[49C\u001b[1@1\r\r\n\u001b[103C \u001b[K\r\r\r\n\u001b[K\r\r\n\u001b[K\u001b[3A"]
|
||||
[14.187299, "o", "\u001b[49C\u001b[P\r\r\n\u001b[103C \u001b[2m[ ]\u001b[0m \u001b[2mkey2\u001b[0m\u001b[93C \u001b[1m[ ]\u001b[0m key3\u001b[3A\r"]
|
||||
[14.356992, "o", "\u001b[48C\u001b[P\r"]
|
||||
[14.495579, "o", "\u001b[47C\u001b[P\r"]
|
||||
[14.642467, "o", "\u001b[35Ctype to filter\u001b[K\r"]
|
||||
[15.763904, "o", "\r\r\n\u001b[2C\u001b[32m[x]\u001b[0m\u001b[A\r"]
|
||||
[16.496138, "o", "\r\r\n \r\r\n\u001b[96;1m> \u001b[0m\u001b[2A\r"]
|
||||
[16.678991, "o", "\r\r\n\r\n \r\r\n\u001b[96;1m> \u001b[0m\u001b[3A\r"]
|
||||
[17.979077, "o", "\r\r\n\r\n\r\n\u001b[2C\u001b[32m[x]\u001b[0m\u001b[3A\r"]
|
||||
[18.809587, "o", "\r\r\n\r\n\r\n\u001b[2C\u001b[1m[ ]\u001b[0m\u001b[3A\r"]
|
||||
[20.452942, "o", "\r\r\n\r\n\u001b[96;1m> \u001b[0m\r\r\n \u001b[3A\r"]
|
||||
[21.705426, "o", "\r\r\n\r\n \r\r\n\u001b[96;1m> \u001b[0m\u001b[3A\r"]
|
||||
[22.207898, "o", "\r\r\n\r\n\r\n\u001b[2C\u001b[32m[x]\u001b[0m\u001b[3A\r"]
|
||||
[23.30633, "o", "\r\r\n\r\n\r\n\u001b[2C\u001b[1m[ ]\u001b[0m\u001b[3A\r"]
|
||||
[24.642701, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\u001b[3A"]
|
||||
[24.64692, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mtestSimple\u001b[0m \u001b[34mvalue1\u001b[0m\r\n"]
|
||||
[24.647546, "o", "Got value value1\r\n"]
|
||||
[24.649365, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[26.649365, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,35 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 6, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[1.276071, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
|
||||
[1.975169, "o", "\r\n"]
|
||||
[3.730642, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[4.157171, "o", "\u001b[31mc\u001b[0m"]
|
||||
[4.259876, "o", "\u001b[31mo\u001b[0m"]
|
||||
[4.480644, "o", "\u001b[31mm\u001b[0m"]
|
||||
[4.675743, "o", "\u001b[31mp\u001b[0m"]
|
||||
[4.746389, "o", "\u001b[31mo\u001b[0m"]
|
||||
[4.899817, "o", "\u001b[31mn\u001b[0m"]
|
||||
[5.064803, "o", "\u001b[31me\u001b[0m"]
|
||||
[5.151957, "o", "\u001b[31mn\u001b[0m"]
|
||||
[5.295573, "o", "\u001b[31mt\u001b[0m"]
|
||||
[5.626209, "o", "\u001b[31m \u001b[0m"]
|
||||
[5.949778, "o", "\u001b[31mp\u001b[0m"]
|
||||
[6.052068, "o", "\u001b[31ma\u001b[0m"]
|
||||
[6.270888, "o", "\u001b[31mt\u001b[0m"]
|
||||
[6.342701, "o", "\u001b[13D\u001b[1mcomponent path\u001b[0m\u001b[K"]
|
||||
[6.866598, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[6.918336, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[6.979593, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \r"]
|
||||
[8.74751, "o", "\u001b[14C/\u001b[88C \u001b[31m>\u001b[0m\u001b[31m>>\u001b[0m \u001b[31mDirectory exists\u001b[0m\u001b[A\r"]
|
||||
[10.825765, "o", "\u001b[15Ct\r\r\n\u001b[32m>\u001b[0m \u001b[32mPath ok\u001b[0m\u001b[K\u001b[A\r"]
|
||||
[10.96141, "o", "\u001b[16Cm\r"]
|
||||
[11.050615, "o", "\u001b[17Cp\r\r\n\u001b[31m>>>\u001b[0m \u001b[31mDirectory exists\u001b[0m\u001b[K\u001b[A\r"]
|
||||
[11.812886, "o", "\u001b[18C/\r"]
|
||||
[11.930461, "o", "\u001b[19Cd\r\r\n\u001b[32m>\u001b[0m \u001b[32mPath ok\u001b[0m\u001b[K\u001b[A\r"]
|
||||
[12.128981, "o", "\u001b[20Ce\r"]
|
||||
[12.176119, "o", "\u001b[21Cm\r"]
|
||||
[12.28765, "o", "\u001b[22Co\r"]
|
||||
[13.464196, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\u001b[A"]
|
||||
[13.471408, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \u001b[34m/tmp/demo\u001b[0m\r\n"]
|
||||
[13.471875, "o", "Got value /tmp/demo\r\n"]
|
||||
[13.475016, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[15.475016, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,23 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 10, "timestamp": 1666162443, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[1.881363, "o", "java -jar spring-shell-samples/build/libs/spring-shell-samples.jar"]
|
||||
[2.630692, "o", "\r\n"]
|
||||
[6.50287, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[8.347165, "o", "\u001b[1mcomponent path search\u001b[0m"]
|
||||
[9.422581, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[9.524556, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[9.612905, "o", "\u001b[32;1m?\u001b[0m \u001b[1mEnter value\u001b[0m \u001b[70C \u001b[32mℹ\u001b[0m \u001b[32mType '<path> <pattern>' to search\u001b[0m\u001b[A\r"]
|
||||
[10.889157, "o", "\u001b[14C.\r\r\n\u001b[35C\u001b[32m, 20/27\u001b[0m\u001b[42C \u001b[96;1m❯\u001b[0m\u001b[96;1m buildSrc/src\u001b[0m\u001b[70C \u001b[96;1mbuildSrc/src/main\u001b[0m\u001b[65C \u001b[96;1mbuildSrc/build.gradle\u001b[0m\u001b[61C \u001b[96;1mbuildSrc/src/main/java\u001b[0m\u001b[60C \u001b[96;1mbuildSrc/src/main/java/org\u001b[0m\u001b[6A\r"]
|
||||
[12.272435, "o", "\u001b[15C \r"]
|
||||
[12.486882, "o", "\u001b[16Cg\r\r\n\r\n\u001b[14C\u001b[96;1m/main/java/org/springframework/shell/\u001b[33;22mg\u001b[96;1mradle\u001b[0m\r\r\n\u001b[19C\u001b[96;1m/java/org/springframework/shell/\u001b[33;22mg\u001b[96;1mradle/BomPlugin.java\u001b[0m\r\r\n\u001b[11C\u001b[96;1msrc/main/java/org/springframework/shell/\u001b[33;22mg\u001b[96;1mradle/DocsPlugin.java\u001b[0m\u001b[K\r\r\n\u001b[24C\u001b[96;1m/org/springframework/shell/\u001b[33;22mg\u001b[96;1mradle/RootPlugin.java\u001b[0m\r\r\n\u001b[28C\u001b[96;1m/springframework/shell/\u001b[33;22mg\u001b[96;1mradle/ModulePlugin.java\u001b[0m\u001b[6A\r"]
|
||||
[12.707385, "o", "\u001b[17Cr\r\r\n\r\n\u001b[52C\u001b[33mr\u001b[0m\r\r\n\u001b[52C\u001b[33mr\u001b[0m\r\r\n\u001b[52C\u001b[33mr\u001b[96;1madle/Root\u001b[0m\r\r\n\u001b[52C\u001b[33mr\u001b[96;1madle/Docs\u001b[0m\r\r\n\u001b[52C\u001b[33mr\u001b[96;1madle/Samp\u001b[0m\u001b[6A\r"]
|
||||
[12.758464, "o", "\u001b[18Ca\r\r\n\r\n\u001b[53C\u001b[33ma\u001b[0m\r\r\n\u001b[53C\u001b[33ma\u001b[0m\r\r\n\u001b[53C\u001b[33ma\u001b[0m\r\r\n\u001b[53C\u001b[33ma\u001b[0m\r\r\n\u001b[53C\u001b[33ma\u001b[96;1mdle/Modu\u001b[0m\u001b[6A\r"]
|
||||
[13.035614, "o", "\u001b[19Cd\r\r\n\u001b[37C\u001b[32m19\u001b[0m\r\r\n\u001b[54C\u001b[33md\u001b[0m\r\r\n\u001b[54C\u001b[33md\u001b[0m\r\r\n\u001b[54C\u001b[33md\u001b[96;1mle/Docs\u001b[0m\r\r\n\u001b[54C\u001b[33md\u001b[96;1mle/Module\u001b[0m\u001b[K\u001b[96;1mPlugin.java\u001b[0m\r\r\n\u001b[54C\u001b[33md\u001b[96;1mle/Samp\u001b[0m\u001b[6A\r"]
|
||||
[13.132591, "o", "\u001b[20Cl\r\r\n\r\n\u001b[55C\u001b[33ml\u001b[0m\r\r\n\u001b[55C\u001b[33ml\u001b[0m\r\r\n\u001b[55C\u001b[33ml\u001b[0m\r\r\n\u001b[55C\u001b[33ml\u001b[96;1me/Samp\u001b[0m\r\r\n\u001b[55C\u001b[33ml\u001b[96;1me/Modu\u001b[0m\u001b[6A\r"]
|
||||
[13.226949, "o", "\u001b[21Ce\r\r\n\r\n\u001b[56C\u001b[33me\u001b[0m\r\r\n\u001b[56C\u001b[33me\u001b[0m\r\r\n\u001b[56C\u001b[33me\u001b[0m\r\r\n\u001b[56C\u001b[33me\u001b[0m\r\r\n\u001b[56C\u001b[33me\u001b[0m\u001b[6A\r"]
|
||||
[14.514777, "o", "\r\r\n\r\n \r\r\n\u001b[96;1m❯ \u001b[0m\u001b[3A\r"]
|
||||
[15.008775, "o", "\r\r\n\r\n\u001b[96;1m❯ \u001b[0m\r\r\n \u001b[3A\r"]
|
||||
[15.547301, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\u001b[6A"]
|
||||
[15.552903, "o", "\u001b[32;1m?\u001b[0m \u001b[1mEnter value\u001b[0m \u001b[34mbuildSrc/src/main/java/org/springframework/shell/gradle\u001b[0m\r\n"]
|
||||
[15.55352, "o", "Got value buildSrc/src/main/java/org/springframework/shell/gradle\r\n"]
|
||||
[16.475016, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[18.475016, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,38 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 8, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[2.193321, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
|
||||
[3.11524, "o", "\r\n"]
|
||||
[4.904714, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[5.372714, "o", "\u001b[31mc\u001b[0m"]
|
||||
[5.484943, "o", "\u001b[31mo\u001b[0m"]
|
||||
[5.70511, "o", "\u001b[31mm\u001b[0m"]
|
||||
[5.913092, "o", "\u001b[31mp\u001b[0m"]
|
||||
[5.992808, "o", "\u001b[31mo\u001b[0m"]
|
||||
[6.159092, "o", "\u001b[31mn\u001b[0m"]
|
||||
[6.281094, "o", "\u001b[31me\u001b[0m"]
|
||||
[6.353925, "o", "\u001b[31mn\u001b[0m"]
|
||||
[6.49373, "o", "\u001b[31mt\u001b[0m"]
|
||||
[6.677988, "o", "\u001b[31m \u001b[0m"]
|
||||
[6.825018, "o", "\u001b[31ms\u001b[0m"]
|
||||
[6.95602, "o", "\u001b[31mi\u001b[0m"]
|
||||
[7.121719, "o", "\u001b[31mn\u001b[0m"]
|
||||
[7.309007, "o", "\u001b[13D\u001b[1mcomponent single\u001b[0m \u001b[K"]
|
||||
[7.972392, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[8.019885, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[8.080156, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mtestSimple\u001b[0m [Use arrows to move], type to filter\u001b[54C \u001b[96;1m>\u001b[0m\u001b[96;1m key1\u001b[0m\u001b[97C key2\u001b[2A\r"]
|
||||
[9.181662, "o", "\r\r\n key1\r\r\n\u001b[96;1m> key2\u001b[0m\u001b[2A\r"]
|
||||
[9.701431, "o", "\r\r\n\u001b[96;1m> key1\u001b[0m\r\r\n key2\u001b[2A\r"]
|
||||
[10.380557, "o", "\r\r\n key1\r\r\n\u001b[96;1m> key2\u001b[0m\u001b[2A\r"]
|
||||
[12.157001, "o", "\u001b[35Cfiltering 'k'\u001b[K\r"]
|
||||
[14.605973, "o", "\u001b[47C\u001b[1@e\r\r\n\u001b[96;1m> key1\u001b[0m\r\r\n key2\u001b[2A\r"]
|
||||
[14.92268, "o", "\u001b[48C\u001b[1@y\r"]
|
||||
[15.320008, "o", "\u001b[49C\u001b[1@1\r\r\n\u001b[103C \u001b[K\r\r\r\n\u001b[K\u001b[2A"]
|
||||
[16.215448, "o", "\u001b[49C\u001b[P\r\r\n\u001b[103C key2\u001b[2A\r"]
|
||||
[16.559377, "o", "\u001b[48C\u001b[P\r"]
|
||||
[16.784486, "o", "\u001b[47C\u001b[P\r"]
|
||||
[17.004921, "o", "\u001b[35Ctype to filter\u001b[K\r"]
|
||||
[17.790542, "o", "\r\r\n key1\r\r\n\u001b[96;1m> key2\u001b[0m\u001b[2A\r"]
|
||||
[18.340142, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K\r\r\n\u001b[K\r\r\n\u001b[K\u001b[2A"]
|
||||
[18.347511, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mtestSimple\u001b[0m \u001b[34mvalue2\u001b[0m\r\n"]
|
||||
[18.34852, "o", "Got value value2\r\n"]
|
||||
[18.35067, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[20.35067, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,30 +0,0 @@
|
||||
{"version": 2, "width": 85, "height": 6, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
|
||||
[1.262977, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
|
||||
[2.045105, "o", "\r\n"]
|
||||
[3.846992, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[4.717927, "o", "\u001b[31mc\u001b[0m"]
|
||||
[4.824399, "o", "\u001b[31mo\u001b[0m"]
|
||||
[5.014061, "o", "\u001b[31mm\u001b[0m"]
|
||||
[5.703137, "o", "\u001b[31mp\u001b[0m"]
|
||||
[5.802386, "o", "\u001b[31mo\u001b[0m"]
|
||||
[6.434988, "o", "\u001b[31mn\u001b[0m"]
|
||||
[6.653321, "o", "\u001b[31me\u001b[0m"]
|
||||
[6.756821, "o", "\u001b[31mn\u001b[0m"]
|
||||
[7.293975, "o", "\u001b[31mt\u001b[0m"]
|
||||
[7.409984, "o", "\u001b[31m \u001b[0m"]
|
||||
[7.604973, "o", "\u001b[31ms\u001b[0m"]
|
||||
[7.775599, "o", "\u001b[31mt\u001b[0m"]
|
||||
[7.928792, "o", "\u001b[31mr\u001b[0m"]
|
||||
[7.979401, "o", "\u001b[31mi\u001b[0m"]
|
||||
[8.051232, "o", "\u001b[31mn\u001b[0m"]
|
||||
[8.15451, "o", "\u001b[15D\u001b[1mcomponent string\u001b[0m\u001b[K"]
|
||||
[8.892861, "o", "\r\r\n\u001b[?1l\u001b>\u001b[?1000l\u001b[?2004l"]
|
||||
[8.951185, "o", "\u001b[?1h\u001b=\u001b[?25l"]
|
||||
[9.013964, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \u001b[34m[Default myvalue]\u001b[0m\r"]
|
||||
[10.304694, "o", "\u001b[14Ch\u001b[K\r"]
|
||||
[10.533832, "o", "\u001b[15Ci\r"]
|
||||
[11.088255, "o", "\u001b[?1l\u001b>\u001b[?12;25h\u001b[K"]
|
||||
[11.097044, "o", "\u001b[32;1m?\u001b[0m \u001b[97;1mEnter value\u001b[0m \u001b[34mhi\u001b[0m\r\n"]
|
||||
[11.097492, "o", "Got value hi\r\n"]
|
||||
[11.100226, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
[13.100226, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
|
||||
@@ -1,27 +0,0 @@
|
||||
$ $JAVA_HOME/bin/java -jar demo-0.0.1-SNAPSHOT.jar
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
:: Spring Boot :: (v{spring-boot-version})
|
||||
|
||||
2022-09-13T18:42:12.818+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Starting DemoApplication using Java 17.0.4 on ...
|
||||
2022-09-13T18:42:12.821+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: No active profile set, falling back to 1 default profile: "default"
|
||||
2022-09-13T18:42:13.606+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Started DemoApplication in 1.145 seconds (process running for 1.578)
|
||||
shell:>help
|
||||
AVAILABLE COMMANDS
|
||||
|
||||
Built-In Commands
|
||||
help: Display help about available commands
|
||||
stacktrace: Display the full stacktrace of the last error.
|
||||
clear: Clear the shell screen.
|
||||
quit, exit: Exit the shell.
|
||||
history: Display or save the history of previously run commands
|
||||
version: Show version info
|
||||
script: Read and execute commands from a file.
|
||||
@@ -1,26 +0,0 @@
|
||||
$JAVA_HOME/bin/java -jar demo-0.0.1-SNAPSHOT.jar help
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
:: Spring Boot :: (v{spring-boot-version})
|
||||
|
||||
2022-09-13T18:42:12.818+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Starting DemoApplication using Java 17.0.4 on ...
|
||||
2022-09-13T18:42:12.821+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: No active profile set, falling back to 1 default profile: "default"
|
||||
2022-09-13T18:42:13.606+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Started DemoApplication in 1.145 seconds (process running for 1.578)
|
||||
AVAILABLE COMMANDS
|
||||
|
||||
Built-In Commands
|
||||
help: Display help about available commands
|
||||
stacktrace: Display the full stacktrace of the last error.
|
||||
clear: Clear the shell screen.
|
||||
quit, exit: Exit the shell.
|
||||
history: Display or save the history of previously run commands
|
||||
version: Show version info
|
||||
script: Read and execute commands from a file.
|
||||
@@ -1,155 +0,0 @@
|
||||
== Getting Started
|
||||
To see what Spring Shell has to offer, we can write a trivial _hello world_
|
||||
shell application that has a simple argument.
|
||||
|
||||
IMPORTANT: _Spring Shell_ is based on _Spring Boot_ {spring-boot-version} and
|
||||
_Spring Framework_ {spring-version} and thus requires _JDK 17_.
|
||||
|
||||
=== Creating a Project
|
||||
|
||||
For the purpose of this tutorial, we create a simple Spring Boot application by
|
||||
using https://start.spring.io where you can choose _Spring Shell_ dependency.
|
||||
This minimal application depends only on `spring-boot-starter` and
|
||||
`spring-shell-starter`.
|
||||
|
||||
NOTE: _Spring Shell_ version on `start.spring.io` is usually latest release.
|
||||
|
||||
With _maven_ you're expected to have something like:
|
||||
|
||||
====
|
||||
[source, xml, subs=attributes+]
|
||||
----
|
||||
<properties>
|
||||
<spring-shell.version>{project-version}</spring-shell.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.shell</groupId>
|
||||
<artifactId>spring-shell-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.shell</groupId>
|
||||
<artifactId>spring-shell-dependencies</artifactId>
|
||||
<version>${spring-shell.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
----
|
||||
====
|
||||
|
||||
With _gradle_ you're expected to have something like:
|
||||
|
||||
====
|
||||
[source, groovy, subs=attributes+]
|
||||
----
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter'
|
||||
implementation 'org.springframework.shell:spring-shell-starter'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.shell:spring-shell-dependencies:{project-version}"
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
CAUTION: Given that Spring Shell starts the REPL (Read-Eval-Print-Loop) because this
|
||||
dependency is present, you need to either skip tests when you build (`-DskipTests`)
|
||||
throughout this tutorial or remove the sample integration test that was generated
|
||||
by https://start.spring.io. If you do not remove it, the integration test creates
|
||||
the Spring `ApplicationContext` and, depending on your build tool, stays stuck in
|
||||
the eval loop or crashes with a NPE.
|
||||
|
||||
Once compiled it can be run either in interactive mode:
|
||||
|
||||
====
|
||||
[source, text, subs=attributes+]
|
||||
----
|
||||
include::code/getting-started-run-interactive.out[]
|
||||
----
|
||||
====
|
||||
|
||||
Or in non-interactive mode:
|
||||
|
||||
====
|
||||
[source, text, subs=attributes+]
|
||||
----
|
||||
include::code/getting-started-run-noninteractive.out[]
|
||||
----
|
||||
====
|
||||
|
||||
TIP: Check out <<using-shell-customization-logging>> making logging to work
|
||||
better with shell apps.
|
||||
|
||||
[[using-spring-shell-your-first-command]]
|
||||
=== Your First Command
|
||||
|
||||
Now we can add our first command. To do so, create a new class (named whatever you want) and
|
||||
annotate it with `@ShellComponent` which is a variation of `@Component` that is used to restrict
|
||||
the set of classes that are scanned for candidate commands.
|
||||
|
||||
Then we can create a `helloWorld` method that takes `String` as an argument and
|
||||
returns it with "Hello world". Add `@ShellMethod` and optionally change command name
|
||||
using `key` parameter. You can use `@ShellOption` to define argument default value
|
||||
if it's not given when running a command.
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
import org.springframework.shell.standard.ShellMethod;
|
||||
import org.springframework.shell.standard.ShellOption;
|
||||
|
||||
@ShellComponent
|
||||
public class MyCommands {
|
||||
|
||||
@ShellMethod(key = "hello-world")
|
||||
public String helloWorld(
|
||||
@ShellOption(defaultValue = "spring") String arg
|
||||
) {
|
||||
return "Hello world " + arg;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
New _hello-world_ command becomes visible to _help_:
|
||||
|
||||
====
|
||||
[source, text]
|
||||
----
|
||||
My Commands
|
||||
hello-world:
|
||||
----
|
||||
====
|
||||
|
||||
And you can run it:
|
||||
|
||||
====
|
||||
[source, text]
|
||||
----
|
||||
shell:>hello-world
|
||||
Hello world spring
|
||||
|
||||
shell:>hello-world --arg boot
|
||||
Hello world boot
|
||||
----
|
||||
====
|
||||
|
||||
The rest of this document delves deeper into the whole Spring Shell programming model.
|
||||
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.5 KiB |
@@ -1,24 +0,0 @@
|
||||
= Spring Shell Reference Documentation
|
||||
Eric Bottard; Janne Valkealahti; Jay Bryant; Corneil du Plessis
|
||||
:doctype: book
|
||||
:hide-uri-scheme:
|
||||
:icons: font
|
||||
:experimental: // For kbd: macro
|
||||
:spring-shell-starter: spring-shell-starter
|
||||
|
||||
*{project-version}*
|
||||
|
||||
(C) 2017 - 2023 VMware, Inc.
|
||||
|
||||
_Copies of this document may be made for your own use and for distribution to
|
||||
others, provided that you do not charge any fee for such copies and further
|
||||
provided that each copy contains this Copyright Notice, whether distributed in
|
||||
print or electronically._
|
||||
|
||||
include::introduction.adoc[]
|
||||
|
||||
include::getting-started.adoc[]
|
||||
|
||||
include::using-shell.adoc[]
|
||||
|
||||
include::appendices.adoc[]
|
||||
@@ -1,14 +0,0 @@
|
||||
== What is Spring Shell?
|
||||
Not all applications need a fancy web user interface.
|
||||
Sometimes, interacting with an application through an interactive terminal is
|
||||
the most appropriate way to get things done.
|
||||
|
||||
Spring Shell lets you create such a runnable application, where the
|
||||
user enters textual commands that are run until the program terminates.
|
||||
The Spring Shell project provides the infrastructure to create such a REPL (Read, Eval,
|
||||
Print Loop) application, letting you concentrate on implementing commands by using
|
||||
the familiar Spring programming model.
|
||||
|
||||
Spring Shell includes advanced features (such as parsing, tab completion, colorization of
|
||||
output, fancy ASCII-art table display, input conversion, and validation), freeing you
|
||||
to focus on core command logic.
|
||||
@@ -1,18 +0,0 @@
|
||||
[[using-shell-basics-reading]]
|
||||
=== Reading Docs
|
||||
|
||||
Throughout this documentation, we make references to configuring something by using
|
||||
annotations or programmatic examples.
|
||||
|
||||
NOTE: There are two annotation models, <<commands-registration-annotation, annotations>>
|
||||
referred to new annotation model, <<commands-registration-legacyannotation, legacy annotations>>
|
||||
referred to old legacy annotation model.
|
||||
|
||||
Old legacy annotation model mostly relates to use of `@ShellMethod` and `@ShellOption` and
|
||||
new annotation model relates to use of `@Command`.
|
||||
|
||||
The programmatic model is how things are actually registered, even if you use annotations.
|
||||
|
||||
NOTE: Currently whole documentation structure is in transit to provide better
|
||||
structure how things can be used using different ways to provide configurations.
|
||||
So pardon a for little confusion now and there during a transit.
|
||||
@@ -1,16 +0,0 @@
|
||||
[[using-shell-basics]]
|
||||
== Basics
|
||||
This section covers the basics of Spring Shell. Before going on to define actual commands and options,
|
||||
we need to go through some of the fundamental concepts of Spring Shell.
|
||||
|
||||
Essentially, a few things needs to happen before you have a working Spring Shell application:
|
||||
|
||||
- Create a Spring Boot application.
|
||||
- Define commands and options.
|
||||
- Package the application.
|
||||
- Run the application, either interactively or non-interactively.
|
||||
|
||||
You can get a full working Spring Shell application without defining any user-level commands
|
||||
as some basic built-in commands (such as `help` and `history`) are provided.
|
||||
|
||||
include::using-shell-basics-reading.adoc[]
|
||||
@@ -1,75 +0,0 @@
|
||||
[[using-shell-building]]
|
||||
== Building
|
||||
|
||||
This section covers how to build a Spring Shell application.
|
||||
|
||||
[[native]]
|
||||
=== Native Support
|
||||
|
||||
Support for compiling _Spring Shell_ application into a _GraalVM_ binary
|
||||
mostly comes from _Spring Framework_ and _Spring Boot_ where feature is
|
||||
called _AOT_. Ahead of Time means that application context is prepared
|
||||
during the compilation time to being ready for _GraalVM_ generation.
|
||||
|
||||
Building atop of _AOT_ features from a framework _Spring Shell_ has its
|
||||
own _GraalVM_ configuration providing hints what should exist in
|
||||
a binary. Usually trouble comes from a 3rd party libraries which doesn't
|
||||
yet contain _GraalVM_ related configurations or those configurations
|
||||
are incomplete.
|
||||
|
||||
IMPORTANT: It is requred to use _GraalVM Reachability Metadata Repository_ which
|
||||
provides some missing hints for 3rd party libraries. Also you need to have
|
||||
_GraalVM_ installed and `JAVA_HOME` pointing to that.
|
||||
|
||||
For _gradle_ add graalvm's native plugin and configure metadata repository.
|
||||
|
||||
====
|
||||
[source, groovy, subs=attributes+]
|
||||
----
|
||||
plugins {
|
||||
id 'org.graalvm.buildtools.native' version '0.9.16'
|
||||
}
|
||||
|
||||
graalvmNative {
|
||||
metadataRepository {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
When gradle build is run with `./gradlew nativeCompile` you should get binary
|
||||
under `build/native/nativeCompile` directory.
|
||||
|
||||
For `maven` use `spring-boot-starter-parent` as parent and you'll get `native`
|
||||
profile which can be used to do a compilation. You need to configure metadata repository
|
||||
|
||||
====
|
||||
[source, xml, subs=attributes+]
|
||||
----
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
<artifactId>native-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<metadataRepository>
|
||||
<enabled>true</enabled>
|
||||
</metadataRepository>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: If you rely on `spring-boot-starter-parent` it manages `native-maven-plugin`
|
||||
version which is kept up to date.
|
||||
|
||||
When maven build is run with `./mvnw package -Pnative` you should get binary
|
||||
under `target` directory.
|
||||
|
||||
If everything went well this binary can be run as is instead of executing
|
||||
boot application jar via jvm.
|
||||
@@ -1,147 +0,0 @@
|
||||
[[dynamic-command-availability]]
|
||||
=== Dynamic Command Availability
|
||||
|
||||
Registered commands do not always make sense, due to the internal state of the application.
|
||||
For example, there may be a `download` command, but it only works once the user has used `connect` on a remote
|
||||
server. Now, if the user tries to use the `download` command, the shell should explain that
|
||||
the command exists but that it is not available at the time.
|
||||
Spring Shell lets you do that, even letting you provide a short explanation of the reason for
|
||||
the command not being available.
|
||||
|
||||
There are three possible ways for a command to indicate availability.
|
||||
They all use a no-arg method that returns an instance of `Availability`.
|
||||
Consider the following example:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellComponent
|
||||
public class MyCommands {
|
||||
|
||||
private boolean connected;
|
||||
|
||||
@ShellMethod("Connect to the server.")
|
||||
public void connect(String user, String password) {
|
||||
[...]
|
||||
connected = true;
|
||||
}
|
||||
|
||||
@ShellMethod("Download the nuclear codes.")
|
||||
public void download() {
|
||||
[...]
|
||||
}
|
||||
|
||||
public Availability downloadAvailability() {
|
||||
return connected
|
||||
? Availability.available()
|
||||
: Availability.unavailable("you are not connected");
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The `connect` method is used to connect to the server (details omitted), altering the state
|
||||
of the command through the `connected` boolean when done.
|
||||
The `download` command as marked as unavailable until the user has connected, thanks to the presence
|
||||
of a method named exactly as the `download` command method with the `Availability` suffix in its name.
|
||||
The method returns an instance of `Availability`, constructed with one of the two factory methods.
|
||||
If the command is not available, an explanation has to be provided.
|
||||
Now, if the user tries to invoke the command while not being connected, here is what happens:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>download
|
||||
Command 'download' exists but is not currently available because you are not connected.
|
||||
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
|
||||
----
|
||||
====
|
||||
|
||||
Information about currently unavailable commands is also used in the integrated help. See <<built-in-commands-help>>.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
The reason provided when the command is not available should read nicely if appended after "`Because`".
|
||||
|
||||
You should not start the sentence with a capital or add a final period
|
||||
====
|
||||
|
||||
If naming the availability method after the name of the command method does not suit you, you
|
||||
can provide an explicit name by using the `@ShellMethodAvailability` annotation:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Download the nuclear codes.")
|
||||
@ShellMethodAvailability("availabilityCheck") // <1>
|
||||
public void download() {
|
||||
[...]
|
||||
}
|
||||
|
||||
public Availability availabilityCheck() { // <1>
|
||||
return connected
|
||||
? Availability.available()
|
||||
: Availability.unavailable("you are not connected");
|
||||
}
|
||||
----
|
||||
<1> the names have to match
|
||||
====
|
||||
|
||||
Finally, it is often the case that several commands in the same class share the same internal state and, thus,
|
||||
should all be available or unavailable as a group. Instead of having to stick the `@ShellMethodAvailability`
|
||||
on all command methods, Spring Shell lets you flip things around and put the `@ShellMethodAvailabilty`
|
||||
annotation on the availability method, specifying the names of the commands that it controls:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Download the nuclear codes.")
|
||||
public void download() {
|
||||
[...]
|
||||
}
|
||||
|
||||
@ShellMethod("Disconnect from the server.")
|
||||
public void disconnect() {
|
||||
[...]
|
||||
}
|
||||
|
||||
@ShellMethodAvailability({"download", "disconnect"})
|
||||
public Availability availabilityCheck() {
|
||||
return connected
|
||||
? Availability.available()
|
||||
: Availability.unavailable("you are not connected");
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[TIP]
|
||||
=====
|
||||
The default value for the `@ShellMethodAvailability.value()` attribute is `*`. This special
|
||||
wildcard matches all command names. This makes it easy to turn all commands of a single class on or off
|
||||
with a single availability method:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@ShellComponent
|
||||
public class Toggles {
|
||||
@ShellMethodAvailability
|
||||
public Availability availabilityOnWeekdays() {
|
||||
return Calendar.getInstance().get(DAY_OF_WEEK) == SUNDAY
|
||||
? Availability.available()
|
||||
: Availability.unavailable("today is not Sunday");
|
||||
}
|
||||
|
||||
@ShellMethod
|
||||
public void foo() {}
|
||||
|
||||
@ShellMethod
|
||||
public void bar() {}
|
||||
}
|
||||
----
|
||||
====
|
||||
=====
|
||||
|
||||
TIP: Spring Shell does not impose many constraints on how to write commands and how to organize classes.
|
||||
However, it is often good practice to put related commands in the same class, and the availability indicators
|
||||
can benefit from that.
|
||||
@@ -1,4 +0,0 @@
|
||||
[[built-in-commands-clear]]
|
||||
==== Clear
|
||||
The `clear` command does what you would expect and clears the screen, resetting the prompt
|
||||
in the top left corner.
|
||||
@@ -1,8 +0,0 @@
|
||||
[[built-in-commands-completion]]
|
||||
==== Completion
|
||||
|
||||
The `completion` command set lets you create script files that can be used
|
||||
with am OS shell implementations to provide completion. This is very useful when
|
||||
working with non-interactive mode.
|
||||
|
||||
Currently, the only implementation is for bash, which works with `bash` sub-command.
|
||||
@@ -1,6 +0,0 @@
|
||||
[[built-in-commands-exit]]
|
||||
==== Exit
|
||||
|
||||
The `quit` command (also aliased as `exit`) requests the shell to quit, gracefully
|
||||
closing the Spring application context. If not overridden, a JLine `History` bean writes a history of all
|
||||
commands to disk, so that they are available again on the next launch.
|
||||
@@ -1,178 +0,0 @@
|
||||
[[built-in-commands-help]]
|
||||
==== Help
|
||||
|
||||
Running a shell application often implies that the user is in a graphically limited
|
||||
environment. Also, while we are nearly always connected in the era of mobile phones,
|
||||
accessing a web browser or any other rich UI application (such as a PDF viewer) may not always
|
||||
be possible. This is why it is important that the shell commands are correctly self-documented, and this is where the `help`
|
||||
command comes in.
|
||||
|
||||
Typing `help` + `ENTER` lists all the commands known to the shell (including <<dynamic-command-availability,unavailable>> commands)
|
||||
and a short description of what they do, similar to the following:
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
my-shell:>help
|
||||
AVAILABLE COMMANDS
|
||||
|
||||
Built-In Commands
|
||||
exit: Exit the shell.
|
||||
help: Display help about available commands
|
||||
stacktrace: Display the full stacktrace of the last error.
|
||||
clear: Clear the shell screen.
|
||||
quit: Exit the shell.
|
||||
history: Display or save the history of previously run commands
|
||||
completion bash: Generate bash completion script
|
||||
version: Show version info
|
||||
script: Read and execute commands from a file.
|
||||
----
|
||||
====
|
||||
|
||||
Typing `help <command>` shows more detailed information about a command, including the available parameters, their
|
||||
type, whether they are mandatory or not, and other details.
|
||||
|
||||
The following listing shows the `help` command applied to itself:
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
my-shell:>help help
|
||||
NAME
|
||||
help - Display help about available commands
|
||||
|
||||
SYNOPSIS
|
||||
help --command String
|
||||
|
||||
OPTIONS
|
||||
--command or -C String
|
||||
The command to obtain help for.
|
||||
[Optional]
|
||||
----
|
||||
====
|
||||
|
||||
Help is templated and can be customized if needed. Settings are under `spring.shell.command.help` where you can use
|
||||
`enabled` to disable command, `grouping-mode` taking `group` or `flat` if you want to hide groups by flattening
|
||||
a structure, `command-template` to define your template for output of a command help, `commands-template` to define
|
||||
output of a command list.
|
||||
|
||||
If `spring.shell.command.help.grouping-mode=flat` is set, then help would show:
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
my-shell:>help help
|
||||
AVAILABLE COMMANDS
|
||||
|
||||
exit: Exit the shell.
|
||||
help: Display help about available commands
|
||||
stacktrace: Display the full stacktrace of the last error.
|
||||
clear: Clear the shell screen.
|
||||
quit: Exit the shell.
|
||||
history: Display or save the history of previously run commands
|
||||
completion bash: Generate bash completion script
|
||||
version: Show version info
|
||||
script: Read and execute commands from a file.
|
||||
----
|
||||
====
|
||||
|
||||
Output from `help` and `help <commmand>` are both templated with a default implementation
|
||||
which can be changed.
|
||||
|
||||
Option `spring.shell.command.help.commands-template` defaults to
|
||||
`classpath:template/help-commands-default.stg` and is passed `GroupsInfoModel`
|
||||
as a model.
|
||||
|
||||
Option `spring.shell.command.help.command-template` defaults to
|
||||
`classpath:template/help-command-default.stg` and is passed `CommandInfoModel`
|
||||
as a model.
|
||||
|
||||
[[groupsinfomodel-variables]]
|
||||
.GroupsInfoModel Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`showGroups`
|
||||
|`true` if showing groups is enabled. Otherwise, false.
|
||||
|
||||
|`groups`
|
||||
|The commands variables (see <<groupcommandinfomodel-variables>>).
|
||||
|
||||
|`commands`
|
||||
|The commands variables (see <<commandinfomodel-variables>>).
|
||||
|
||||
|`hasUnavailableCommands`
|
||||
|`true` if there is unavailable commands. Otherwise, false.
|
||||
|===
|
||||
|
||||
[[groupcommandinfomodel-variables]]
|
||||
.GroupCommandInfoModel Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`group`
|
||||
|The name of a group, if set. Otherwise, empty.
|
||||
|
||||
|`commands`
|
||||
|The commands, if set. Otherwise, empty. Type is a multi value, see <<commandinfomodel-variables>>.
|
||||
|===
|
||||
|
||||
[[commandinfomodel-variables]]
|
||||
.CommandInfoModel Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`name`
|
||||
|The name of a command, if set. Otherwise, null. Type is string and contains full command.
|
||||
|
||||
|`names`
|
||||
|The names of a command, if set. Otherwise, null. Type is multi value essentially `name` splitted.
|
||||
|
||||
|`aliases`
|
||||
|The possible aliases, if set. Type is multi value with strings.
|
||||
|
||||
|`description`
|
||||
|The description of a command, if set. Otherwise, null.
|
||||
|
||||
|`parameters`
|
||||
|The parameters variables, if set. Otherwise empty. Type is a multi value, see <<commandparameterinfomodel-variables>>.
|
||||
|
||||
|`availability`
|
||||
|The availability variables (see <<commandavailabilityinfomodel-variables>>).
|
||||
|===
|
||||
|
||||
[[commandparameterinfomodel-variables]]
|
||||
.CommandParameterInfoModel Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`type`
|
||||
|The type of a parameter if set. Otherwise, null.
|
||||
|
||||
|`arguments`
|
||||
|The arguments, if set. Otherwise, null. Type is multi value with strings.
|
||||
|
||||
|`required`
|
||||
|`true` if required. Otherwise, false.
|
||||
|
||||
|`description`
|
||||
|The description of a parameter, if set. Otherwise, null.
|
||||
|
||||
|`defaultValue`
|
||||
|The default value of a parameter, if set. Otherwise, null.
|
||||
|
||||
|`hasDefaultValue`
|
||||
|`true` if defaultValue exists. Otherwise, false.
|
||||
|===
|
||||
|
||||
[[commandavailabilityinfomodel-variables]]
|
||||
.CommandAvailabilityInfoModel Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`available`
|
||||
|`true` if available. Otherwise, false.
|
||||
|
||||
|`reason`
|
||||
|The reason if not available if set. Otherwise, null.
|
||||
|===
|
||||
@@ -1,16 +0,0 @@
|
||||
[[built-in-commands-history]]
|
||||
==== History
|
||||
|
||||
The `history` command shows the history of commands that has been executed.
|
||||
|
||||
There are a few configuration options that you can use to configure behavior
|
||||
of a history. History is kept in a log file, which is enabled by default and can
|
||||
be turned off by setting `spring.shell.history.enabled`. The name of a log file
|
||||
is resolved from `spring.application.name` and defaults to `spring-shell.log`,
|
||||
which you can change by setting `spring.shell.history.name`.
|
||||
|
||||
By default, a log file is generated to a current working directory, which you can dictate
|
||||
by setting `spring.shell.config.location`. This property can contain
|
||||
a placeholder (`{userconfig}`), which resolves to a common shared config directory.
|
||||
|
||||
TIP: Run the Spring Shell application to see how the sample application works as it uses these options.
|
||||
@@ -1,7 +0,0 @@
|
||||
[[built-in-commands-script]]
|
||||
==== Script
|
||||
|
||||
The `script` command accepts a local file as an argument and replays commands found there, one at a time.
|
||||
|
||||
Reading from the file behaves exactly like inside the interactive shell, so lines starting with `//` are considered
|
||||
to be comments and are ignored, while lines ending with `\` trigger line continuation.
|
||||
@@ -1,9 +0,0 @@
|
||||
[[built-in-commands-stacktrace]]
|
||||
==== Stacktrace
|
||||
|
||||
When an exception occurs inside command code, it is caught by the shell and a simple, one-line message is displayed
|
||||
so as not to overflow the user with too much information.
|
||||
There are cases, though, when understanding what exactly happened is important (especially if the exception has a nested cause).
|
||||
|
||||
To this end, Spring Shell remembers the last exception that occurred, and the user can later use the `stacktrace`
|
||||
command to print all the details on the console.
|
||||
@@ -1,37 +0,0 @@
|
||||
[[built-in-commands-version]]
|
||||
==== Version
|
||||
|
||||
The `version` command shows existing build and git info by integrating into
|
||||
Boot's `BuildProperties` and `GitProperties` if those exist in the shell application.
|
||||
By default, only version information is shown, and you can enable other information through configuration
|
||||
options.
|
||||
|
||||
The relevant settings are under `spring.shell.command.version`, where you can use `enabled` to
|
||||
disable a command and, optionally, define your own template with `template`. You can use the
|
||||
`show-build-artifact`, `show-build-group`, `show-build-name`, `show-build-time`,
|
||||
`show-build-version`, `show-git-branch`, `show-git-commit-id`,
|
||||
`show-git-short-commit-id` and `show-git-commit-time` commands to control
|
||||
fields in a default template.
|
||||
|
||||
The template defaults to `classpath:template/version-default.st`, and you can define
|
||||
your own, as the following example shows:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
<buildVersion>
|
||||
----
|
||||
====
|
||||
|
||||
This setting would output something like the following:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
X.X.X
|
||||
----
|
||||
====
|
||||
|
||||
You can add the following attributes to the default template rendering: `buildVersion`, `buildGroup`,
|
||||
`buildGroup`, `buildName`, `buildTime`, `gitShortCommitId`, `gitCommitId`,
|
||||
`gitBranch`, and `gitCommitTime`.
|
||||
@@ -1,18 +0,0 @@
|
||||
[[built-in-commands]]
|
||||
=== Built-In Commands
|
||||
|
||||
include::using-shell-commands-builtin-help.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin-clear.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin-exit.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin-stacktrace.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin-script.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin-history.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin-completion.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin-version.adoc[]
|
||||
@@ -1,87 +0,0 @@
|
||||
[[dynamic-command-exitcode-annotation]]
|
||||
==== @ExceptionResolver
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
`@ShellComponent` classes can have `@ExceptionResolver` methods to handle exceptions from component
|
||||
methods. These are meant for annotated methods.
|
||||
|
||||
The exception may match against a top-level exception being propagated (e.g. a direct IOException
|
||||
being thrown) or against a nested cause within a wrapper exception (e.g. an IOException wrapped
|
||||
inside an IllegalStateException). This can match at arbitrary cause levels.
|
||||
|
||||
For matching exception types, preferably declare the target exception as a method argument, as
|
||||
the preceding example(s) shows. When multiple exception methods match, a root exception match is
|
||||
generally preferred to a cause exception match. More specifically, the ExceptionDepthComparator
|
||||
is used to sort exceptions based on their depth from the thrown exception type.
|
||||
|
||||
Alternatively, the annotation declaration may narrow the exception types to match, as the
|
||||
following example shows:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-type-in-annotation]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-type-in-method]
|
||||
----
|
||||
====
|
||||
|
||||
`@ExceptionResolver` can also return `String` which is used as an output to console. You can
|
||||
use `@ExitCode` annotation to define return code.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-exitcode-annotation]
|
||||
----
|
||||
====
|
||||
|
||||
`@ExceptionResolver` with `void` return type is automatically handled as handled exception.
|
||||
You can then also define `@ExitCode` and use `Terminal` if you need to write something
|
||||
into console.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-void]
|
||||
----
|
||||
====
|
||||
|
||||
===== Method Arguments
|
||||
`@ExceptionResolver` methods support the following arguments:
|
||||
|
||||
[Attributes]
|
||||
|===
|
||||
|Method argument |Description
|
||||
|
||||
|Exception type
|
||||
|For access to the raised exception. This is any type of `Exception` or `Throwable`.
|
||||
|
||||
|Terminal
|
||||
|For access to underlying `JLine` terminal to i.e. get its terminal writer.
|
||||
|
||||
|===
|
||||
|
||||
===== Return Values
|
||||
`@ExceptionResolver` methods support the following return values:
|
||||
|
||||
[Attributes]
|
||||
|===
|
||||
|Return value |Description
|
||||
|
||||
|String
|
||||
|Plain text to return to a shell. Exit code 1 is used in this case.
|
||||
|
||||
|CommandHandlingResult
|
||||
|Plain `CommandHandlingResult` having message and exit code.
|
||||
|
||||
|void
|
||||
|A method with a void return type is considered to have fully handled the exception. Usually
|
||||
you would define `Terminal` as a method argument and write response using _terminal writer_
|
||||
from it. As exception is fully handled, Exit code 0 is used in this case.
|
||||
|===
|
||||
@@ -1,34 +0,0 @@
|
||||
[[dynamic-command-exitcode-mappings]]
|
||||
==== Exit Code Mappings
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Default behaviour of an exit codes is as:
|
||||
|
||||
- Errors from a command option parsing will result code of `2`
|
||||
- Any generic error will result result code of `1`
|
||||
- Obviously in any other case result code is `0`
|
||||
|
||||
Every `CommandRegistration` can define its own mappings between _Exception_ and _exit code_.
|
||||
Essentially we're bound to functionality in `Spring Boot` regarding _exit code_ and simply
|
||||
integrate into that.
|
||||
|
||||
Assuming there is an exception show below which would be thrown from a command:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ExitCodeSnippets.java[tag=my-exception-class]
|
||||
----
|
||||
====
|
||||
|
||||
It is possible to define a mapping function between `Throwable` and exit code. You can also
|
||||
just configure a _class_ to _exit code_ which is just a syntactic sugar within configurations.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ExitCodeSnippets.java[tag=example1]
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Exit codes cannot be customized with annotation based configuration
|
||||
@@ -1,55 +0,0 @@
|
||||
[[dynamic-command-exitcode-resolving]]
|
||||
==== Exception Resolving
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Unhandled exceptions will bubble up into shell's `ResultHandlerService` and then eventually
|
||||
handled by some instance of `ResultHandler`. Chain of `ExceptionResolver` implementations
|
||||
can be used to resolve exceptions and gives you flexibility to return message to get written
|
||||
into console together with exit code which are wrapped within `CommandHandlingResult`.
|
||||
`CommandHandlingResult` may contain a _message_ and/or _exit code_.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-resolver-class]
|
||||
----
|
||||
====
|
||||
|
||||
`CommandExceptionResolver` implementations can be defined globally as bean.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-resolver-class-as-bean]
|
||||
----
|
||||
====
|
||||
|
||||
or defined per `CommandRegistration` if it's applicable only for a particular command itself.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=example1]
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Resolvers defined with a command are handled before global resolvers.
|
||||
|
||||
|
||||
Use you own exception types which can also be an instance of boot's `ExitCodeGenerator` if
|
||||
you want to define exit code there.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-class]
|
||||
----
|
||||
====
|
||||
|
||||
Some build in `CommandExceptionResolver` beans are registered to handle common
|
||||
exceptions thrown from command parsing. These are registered with _order_
|
||||
presedence defined in `CommandExceptionResolver.DEFAULT_PRECEDENCE`.
|
||||
As these beans are used in a given order, `@Order` annotation or `Ordered`
|
||||
interface from can be used just like in any other spring app. This
|
||||
is generally useful if you need to control your own beans to get used
|
||||
either before or after a defaults.
|
||||
@@ -1,19 +0,0 @@
|
||||
[[dynamic-command-exitcode]]
|
||||
=== Exception Handling
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Exceptions happen from a user code wether it is intentional or not. This section describes
|
||||
how `spring-shell` handles exceptions and gives instructions and best practices how to
|
||||
work with it.
|
||||
|
||||
Many command line applications when applicable return an _exit code_ which running environment
|
||||
can use to differentiate if command has been executed successfully or not. In a `spring-shell`
|
||||
this mostly relates when a command is run on a non-interactive mode meaning one command
|
||||
is always executed once with an instance of a `spring-shell`. Take a note that _exit code_
|
||||
always relates to non-interactive shell.
|
||||
|
||||
include::using-shell-commands-exceptionhandling-resolving.adoc[]
|
||||
|
||||
include::using-shell-commands-exceptionhandling-mappings.adoc[]
|
||||
|
||||
include::using-shell-commands-exceptionhandling-annotation.adoc[]
|
||||
@@ -1,41 +0,0 @@
|
||||
[[commands-helpoptions]]
|
||||
=== Help Options
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_Spring Shell_ has a build-in `help` command but not all favour getting command help
|
||||
from it as you always need to call it with arguments for target command. It's
|
||||
common in many cli frameworks for every command having options _--help_ and _-h_
|
||||
to print out command help.
|
||||
|
||||
Default functionality is that every command will get modified to have options
|
||||
_--help_ and _-h_, which if present in a given command will automatically
|
||||
short circuit command execution into a existing `help` command regardless
|
||||
what other command-line options is typed.
|
||||
|
||||
Below example shows its default settings.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationHelpOptionsSnippets.java[tag=defaults]
|
||||
----
|
||||
====
|
||||
|
||||
It is possible to change default behaviour via configuration options.
|
||||
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
shell:
|
||||
help:
|
||||
enabled: true
|
||||
long-names: help
|
||||
short-names: h
|
||||
command: help
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Commands defined programmationally or via annotations will automatically add
|
||||
help options. With annotation model you can only turn things off globally, programmatic
|
||||
model gives option to modify settings per command.
|
||||
@@ -1,27 +0,0 @@
|
||||
[[commands-hidden]]
|
||||
=== Hidden Command
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
It is possible to _hide_ a command which is convenient in cases where it is not yet ready for
|
||||
prime time, is meant for debugging purposes or you have any other reason you dont want to
|
||||
advertise its presense.
|
||||
|
||||
Hidden command can be executed if you know it and its options. It is effectively removed
|
||||
from:
|
||||
|
||||
* Help listing
|
||||
* Help page for command return "unknown command"
|
||||
* Command completion in interactive mode
|
||||
* Bash completion
|
||||
|
||||
Below is an example how to define command as _hidden_. It shows available builder methods
|
||||
to define _hidden_ state.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationHiddenSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Defining hidden commands is not supported with annotation based configuration
|
||||
@@ -1,24 +0,0 @@
|
||||
[[commands-interactionmode]]
|
||||
=== Interaction Mode
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Command registration can define `InteractionMode` which is used to hide commands
|
||||
depending which mode shell is executing. More about that in <<using-shell-execution-interactionmode>>.
|
||||
|
||||
You can define it with `CommandRegisration`.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationInteractionModeSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
Or with `@ShellMethod`.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationInteractionModeSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
@@ -1,54 +0,0 @@
|
||||
[[organizing-commands]]
|
||||
=== Organizing Commands
|
||||
|
||||
When your shell starts to provide a lot of functionality, you may end up
|
||||
with a lot of commands, which could be confusing for your users. By typing `help`,
|
||||
they would see a daunting list of commands, organized in alphabetical order,
|
||||
which may not always be the best way to show the available commands.
|
||||
|
||||
To alleviate this possible confusion, Spring Shell provides the ability to group commands together,
|
||||
with reasonable defaults. Related commands would then end up in the same group (for example, `User Management Commands`)
|
||||
and be displayed together in the help screen and other places.
|
||||
|
||||
By default, commands are grouped according to the class they are implemented in,
|
||||
turning the camelCase class name into separate words (so `URLRelatedCommands` becomes `URL Related Commands`).
|
||||
This is a sensible default, as related commands are often already in the class anyway,
|
||||
because they need to use the same collaborating objects.
|
||||
|
||||
If, however, this behavior does not suit you, you can override the group for a
|
||||
command in the following ways, in order of priority:
|
||||
|
||||
. Specify a `group()` in the `@ShellMethod` annotation.
|
||||
. Place a `@ShellCommandGroup` on the class in which the command is defined. This applies
|
||||
the group for all commands defined in that class (unless overridden, as explained earlier).
|
||||
. Place a `@ShellCommandGroup` on the package (through `package-info.java`)
|
||||
in which the command is defined. This applies to all the commands defined in the
|
||||
package (unless overridden at the method or class level, as explained earlier).
|
||||
|
||||
The following listing shows an example:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
public class UserCommands {
|
||||
@ShellMethod(value = "This command ends up in the 'User Commands' group")
|
||||
public void foo() {}
|
||||
|
||||
@ShellMethod(value = "This command ends up in the 'Other Commands' group",
|
||||
group = "Other Commands")
|
||||
public void bar() {}
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
@ShellCommandGroup("Other Commands")
|
||||
public class SomeCommands {
|
||||
@ShellMethod(value = "This one is in 'Other Commands'")
|
||||
public void wizz() {}
|
||||
|
||||
@ShellMethod(value = "And this one is 'Yet Another Group'",
|
||||
group = "Yet Another Group")
|
||||
public void last() {}
|
||||
}
|
||||
----
|
||||
====
|
||||
@@ -1,52 +0,0 @@
|
||||
[[commands-registration-annotation]]
|
||||
==== Annotation
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
`@Command` annotation when used on a method marks it as a candidate for command registration.
|
||||
In below example a command `example` is defined.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandAnnotationSnippets.java[tag=command-anno-in-method]
|
||||
----
|
||||
====
|
||||
|
||||
`@Command` annotation can be placed on a class which either defines defaults or shared settings
|
||||
for `@Command` methods defined in a same class. In below example a command `parent example` is
|
||||
defined.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandAnnotationSnippets.java[tag=command-anno-in-class]
|
||||
----
|
||||
====
|
||||
|
||||
Using a `@Command` will not automatically register command targets, instead it is required to use
|
||||
`@EnableCommand` and/or `@CommandScan` annotations. This model is familiar from other parts
|
||||
of Spring umbrella and provides better flexibility for a user being inclusive rather than exclusive
|
||||
for command targets.
|
||||
|
||||
You can define target classes using `@EnableCommand`. It will get picked from all _Configuration_
|
||||
classes.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandAnnotationSnippets.java[tag=enablecommand-with-class]
|
||||
----
|
||||
====
|
||||
|
||||
You can define target classes using `@CommandScan`. It will get picked from all _Configuration_
|
||||
classes.
|
||||
|
||||
TIP: Define `@CommandScan` in Spring Boot `App` class on a top level and it will automatically
|
||||
scan all command targets from all packages and classes under `App`.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandAnnotationSnippets.java[tag=commandscan-no-args]
|
||||
----
|
||||
====
|
||||
@@ -1,51 +0,0 @@
|
||||
[[commands-registration-legacyannotation]]
|
||||
==== Legacy Annotation
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
When you use the standard API, methods on beans are turned into executable commands, provided that:
|
||||
|
||||
* The bean class bears the `@ShellComponent` annotation. (This is used to restrict the set of beans
|
||||
that are considered.)
|
||||
* The method bears the `@ShellMethod` annotation.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
The `@ShellComponent` is a stereotype annotation that is itself meta-annotated with `@Component`. As a result,
|
||||
you can use it in addition to the filtering mechanism to declare beans (for example, by using `@ComponentScan`).
|
||||
|
||||
You can customize the name of the created bean by using the `value` attribute of the annotation.
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/AnnotationRegistrationSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
The only required attribute of the `@ShellMethod` annotation is its `value` attribute, which should have
|
||||
a short, one-sentence, description of what the command does. This lets your users
|
||||
get consistent help about your commands without having to leave the shell (see <<built-in-commands-help>>).
|
||||
|
||||
NOTE: The description of your command should be short -- no more than one or two sentences. For better
|
||||
consistency, it should start with a capital letter and end with a period.
|
||||
|
||||
By default, you need not specify the key for your command (that is, the word(s) that should be used
|
||||
to invoke it in the shell). The name of the method is used as the command key, turning camelCase names into
|
||||
dashed, gnu-style, names (for example, `sayHello()` becomes `say-hello`).
|
||||
|
||||
You can, however, explicitly set the command key, by using the `key` attribute of the annotation:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/AnnotationRegistrationSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: The `key` attribute accepts multiple values.
|
||||
If you set multiple keys for a single method, the command is registered with those different aliases.
|
||||
|
||||
TIP: The command key can contain pretty much any character, including spaces. When coming up with names though,
|
||||
keep in mind that consistency is often appreciated by users. That is, you should avoid mixing dashed-names with
|
||||
spaced names and other inconsistencies.
|
||||
@@ -1,41 +0,0 @@
|
||||
[[commands-registration-programmatic]]
|
||||
==== Programmatic
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
In the programmatic model, `CommandRegistration` can be defined as a `@Bean`
|
||||
and it will be automatically registered.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=plain]
|
||||
----
|
||||
====
|
||||
|
||||
If all your commands have something in common, an instance of
|
||||
a _CommandRegistration.BuilderSupplier_ is created which can
|
||||
be autowired. Default implementation of this supplier returns
|
||||
a new builder so you don't need to worry about its internal state.
|
||||
|
||||
IMPORTANT: Commands registered programmatically automatically
|
||||
add _help options_ mentioned in <<commands-helpoptions>>.
|
||||
|
||||
If bean of this supplier type is defined then auto-configuration
|
||||
will back off giving you an option to redefine default functionality.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=fromsupplier]
|
||||
----
|
||||
====
|
||||
|
||||
`CommandRegistrationCustomizer` beans can be defined if you want to centrally
|
||||
modify builder instance given you by supplier mentioned above.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=customizer]
|
||||
----
|
||||
====
|
||||
@@ -1,21 +0,0 @@
|
||||
=== Registration
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
There are two different ways to define a command: through an annotation model and
|
||||
through a programmatic model. In the annotation model, you define your methods
|
||||
in a class and annotate the class and the methods with specific annotations.
|
||||
In the programmatic model, you use a more low level approach, defining command
|
||||
registrations (either as beans or by dynamically registering with a command catalog).
|
||||
|
||||
Starting from _3.1.x_ a better support for defining commands using
|
||||
<<commands-registration-annotation, annotations>> were added. Firstly because eventually standard
|
||||
package providing <<commands-registration-legacyannotation, legacy annotations>> will get deprecated
|
||||
and removed. Secondly so that we're able to provide same set of features than using underlying
|
||||
`CommandRegistration`. Creating new a annotation model allows us to rethink and modernise that
|
||||
part without breaking existing applications.
|
||||
|
||||
include::using-shell-commands-registration-programmatic.adoc[]
|
||||
|
||||
include::using-shell-commands-registration-annotation.adoc[]
|
||||
|
||||
include::using-shell-commands-registration-legacyannotation.adoc[]
|
||||
@@ -1,27 +0,0 @@
|
||||
=== Writing
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
When something needs to get written into your console you can always
|
||||
use JDK's `System.out` which then goes directly into JDK's own streams.
|
||||
Other recommended way is to use JLine's `Terminal` and get _writer_
|
||||
instance from there.
|
||||
|
||||
If using target endpoints, i.e. _consumer_ which is not expected
|
||||
to return anything given `CommandContext` contains reference to
|
||||
`Terminal` and writer can be accessed from there.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/WritingSnippets.java[tag=reg-terminal-writer]
|
||||
----
|
||||
====
|
||||
|
||||
It's possible to autowire `Terminal` to get access to its writer.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/WritingSnippets.java[tag=anno-terminal-writer]
|
||||
----
|
||||
====
|
||||
@@ -1,24 +0,0 @@
|
||||
== Commands
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
In this section, we go through an actual command registration and leave command options
|
||||
and execution for later in a documentation. You can find more detailed info in
|
||||
<<appendix-tech-intro-registration>>.
|
||||
|
||||
include::using-shell-commands-registration.adoc[]
|
||||
|
||||
include::using-shell-commands-organize.adoc[]
|
||||
|
||||
include::using-shell-commands-availability.adoc[]
|
||||
|
||||
include::using-shell-commands-exceptionhandling.adoc[]
|
||||
|
||||
include::using-shell-commands-hidden.adoc[]
|
||||
|
||||
include::using-shell-commands-helpoptions.adoc[]
|
||||
|
||||
include::using-shell-commands-interactionmode.adoc[]
|
||||
|
||||
include::using-shell-commands-builtin.adoc[]
|
||||
|
||||
include::using-shell-commands-writing.adoc[]
|
||||
@@ -1,64 +0,0 @@
|
||||
== Completion
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Spring Shell can provide completion proposals for both interactive shell
|
||||
and a command-line. There are differences however as when shell is in
|
||||
interactive mode we have an active instance of a shell meaning it's
|
||||
easier to provide more programmatic ways to provide completion hints.
|
||||
When shell is purely run as a command-line tool a completion can only
|
||||
be accomplished with integration into OS level shell's like _bash_.
|
||||
|
||||
=== Interactive
|
||||
|
||||
Hints for completions are calculated with _function_ or _interface_ style
|
||||
methods which takes `CompletionContext` and returns a list of
|
||||
`CompletionProposal` instances. `CompletionContext` gives you various
|
||||
information about a current context like command registration and option.
|
||||
|
||||
NOTE: Generic resolvers can be registered as a beans if those are useful
|
||||
for all commands and scenarious. For example existing completion
|
||||
implementation `RegistrationOptionsCompletionResolver` handles completions
|
||||
for a option names.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CompletionSnippets.java[tag=resolver-1]
|
||||
----
|
||||
====
|
||||
|
||||
Option values with builder based command registration can be
|
||||
defined per option.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CompletionSnippets.java[tag=builder-1]
|
||||
----
|
||||
====
|
||||
|
||||
Option values with annotation based command registration are handled
|
||||
via `ValueProvider` interface which can be defined with `@ShellOption`
|
||||
annotation.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CompletionSnippets.java[tag=provider-1]
|
||||
----
|
||||
====
|
||||
|
||||
Actual `ValueProvider` with annotation based command needs to be
|
||||
registered as a _Bean_.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CompletionSnippets.java[tag=anno-method]
|
||||
----
|
||||
====
|
||||
|
||||
=== Command-Line
|
||||
|
||||
Command-line completion currently only support _bash_ and is documented
|
||||
in a built-in `completion` command <<built-in-commands-completion>>.
|
||||
@@ -1,37 +0,0 @@
|
||||
[[using-shell-components-flow]]
|
||||
=== Flow
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
When you use <<using-shell-components-ui>> to build something that involves
|
||||
use of a multiple components, your implementation may become a bit cluttered.
|
||||
To ease these use cases, we added a
|
||||
`ComponentFlow` that can hook multiple component executions together
|
||||
as a "`flow`".
|
||||
|
||||
The following listings show examples of flows and their output in a shell:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/FlowComponentSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
image::images/component-flow-showcase-1.svg[text input]
|
||||
|
||||
Normal execution order of a components is same as defined with a builder. It's
|
||||
possible to conditionally choose where to jump in a flow by using a `next`
|
||||
function and returning target _component id_. If this returned id is aither _null_
|
||||
or doesn't exist flow is essentially stopped right there.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/FlowComponentSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
|
||||
image::images/component-flow-conditional-1.svg[text input]
|
||||
|
||||
TIP: The result from running a flow returns `ComponentFlowResult`, which you can
|
||||
use to do further actions.
|
||||
@@ -1,31 +0,0 @@
|
||||
[[using-shell-components-ui-confirmation]]
|
||||
==== Confirmation
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
The confirmation component asks a user for a simple confirmation. It is essentially a
|
||||
yes-or-no question.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet5]
|
||||
----
|
||||
====
|
||||
|
||||
The following image shows the typical output from a confirmation component:
|
||||
|
||||
image::images/component-confirmation-1.svg[text input]
|
||||
|
||||
The context object is `ConfirmationInputContext`. The following table describes its context variables:
|
||||
|
||||
[[confirmationinputcontext-template-variables]]
|
||||
.ConfirmationInputContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`defaultValue`
|
||||
|The default value -- either `true` or `false`.
|
||||
|
||||
|`model`
|
||||
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|
||||
|===
|
||||
@@ -1,34 +0,0 @@
|
||||
[[using-shell-components-ui-multiselect]]
|
||||
==== Multi Select
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
The multi select component asks a user to select multiple items from a list.
|
||||
The following listing shows an example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet7]
|
||||
----
|
||||
====
|
||||
|
||||
The following image shows a typical multi-select component:
|
||||
|
||||
image::images/component-multi-select-1.svg[text input]
|
||||
|
||||
The context object is `MultiItemSelectorContext`. The following table describes its context variables:
|
||||
|
||||
[[multiitemselectorcontext-template-variables]]
|
||||
.MultiItemSelectorContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`values`
|
||||
|The values returned when the component exists.
|
||||
|
||||
|`rows`
|
||||
|The visible items, where rows contain maps of name, selected, on-row, and enabled items.
|
||||
|
||||
|`model`
|
||||
|The parent context variables (see <<selectorcomponentcontext-template-variables>>).
|
||||
|===
|
||||
@@ -1,27 +0,0 @@
|
||||
[[using-shell-components-ui-pathinput]]
|
||||
==== Path Input
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
The path input component asks a user for a `Path` and gives additional information about a path itself.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet4]
|
||||
----
|
||||
====
|
||||
|
||||
The following image shows typical output from a path input component:
|
||||
|
||||
image::images/component-path-input-1.svg[text input]
|
||||
|
||||
The context object is `PathInputContext`. The following table describes its context variables:
|
||||
|
||||
[[pathinputcontext-template-variables]]
|
||||
.PathInputContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`model`
|
||||
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|
||||
|===
|
||||
@@ -1,35 +0,0 @@
|
||||
[[using-shell-components-ui-pathsearch]]
|
||||
==== Path Search
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
The path search component asks base directory for scan and optional search expression.
|
||||
Results are shown in a single select list where user can pick a path.
|
||||
`PathSearchConfig` can be used to customise component behaviour.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet9]
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Logic for search is passed as is into algorithms documented
|
||||
in <<appendix-tech-intro-searchalgorithm>>.
|
||||
|
||||
The following image shows typical output from a path search component:
|
||||
|
||||
image::images/component-path-search-1.svg[text input]
|
||||
|
||||
The context object is `PathSearchContext`. The following table describes its context variables:
|
||||
|
||||
[[pathsearchcontext-template-variables]]
|
||||
.PathSearchContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`pathViewItems`
|
||||
|The items available for rendering search results.
|
||||
|
||||
|`model`
|
||||
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|
||||
|===
|
||||
@@ -1,102 +0,0 @@
|
||||
[[using-shell-components-ui-render]]
|
||||
==== Component Render
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
You can implement component rendering in either of two ways: fully
|
||||
programmatically or by using a _ANTLR Stringtemplate_.
|
||||
Strictly speaking, there is a simple `Function` renderer interface
|
||||
that takes `Context` as an input and outputs a list of `AttributedString`.
|
||||
This lets you choose between templating and code.
|
||||
|
||||
Templating is a good choice if you do not need to do anything complex or
|
||||
you just want to slightly modify existing component layouts. Rendering
|
||||
through code then gives you flexibility to do whatever you need.
|
||||
|
||||
The programmatic way to render is to create a `Function`:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
Then you can hook it to a component:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet2]
|
||||
----
|
||||
====
|
||||
|
||||
Components have their own context but usually share some functionality
|
||||
from a parent component types. The following tables show those context variables:
|
||||
|
||||
[[textcomponentcontext-template-variables]]
|
||||
.TextComponentContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`resultValue`
|
||||
|The value after a component renders its result.
|
||||
|
||||
|`name`
|
||||
|The name of a component -- that is, its title.
|
||||
|
||||
|`message`
|
||||
|The possible message set for a component.
|
||||
|
||||
|`messageLevel`
|
||||
|The level of a message -- one of `INFO`, `WARN`, or `ERROR`.
|
||||
|
||||
|`hasMessageLevelInfo`
|
||||
|Return `true` if level is `INFO`. Otherwise, false.
|
||||
|
||||
|`hasMessageLevelWarn`
|
||||
|Return `true` if level is `WARN`. Otherwise, false.
|
||||
|
||||
|`hasMessageLevelError`
|
||||
|Return `true` if level is `ERROR`. Otherwise, false.
|
||||
|
||||
|`input`
|
||||
|The raw user input.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
[[selectorcomponentcontext-template-variables]]
|
||||
.SelectorComponentContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`name`
|
||||
|The name of a component -- that is, its title.
|
||||
|
||||
|`input`
|
||||
|The raw user input -- mostly used for filtering.
|
||||
|
||||
|`itemStates`
|
||||
|The full list of item states.
|
||||
|
||||
|`itemStateView`
|
||||
|The visible list of item states.
|
||||
|
||||
|`isResult`
|
||||
|Return `true` if the context is in a result mode.
|
||||
|
||||
|`cursorRow`
|
||||
|The current cursor row in a selector.
|
||||
|
||||
|===
|
||||
|
||||
|
||||
[[componentcontext-template-variables]]
|
||||
.ComponentContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`terminalWidth`
|
||||
|The width of terminal, type is _Integer_ and defaults to _NULL_ if not set.
|
||||
|
||||
|===
|
||||
@@ -1,45 +0,0 @@
|
||||
[[using-shell-components-ui-singleselect]]
|
||||
==== Single Select
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
A single select component asks a user to choose one item from a list. It is similar to a simple
|
||||
dropbox implementation. The following listing shows an example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet6]
|
||||
----
|
||||
====
|
||||
|
||||
The following image shows typical output for a single select component:
|
||||
|
||||
image::images/component-single-select-1.svg[text input]
|
||||
|
||||
The context object is `SingleItemSelectorContext`. The following table describes its context variables:
|
||||
|
||||
[[singleitemselectorcontext-template-variables]]
|
||||
.SingleItemSelectorContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`value`
|
||||
|The returned value when the component exists.
|
||||
|
||||
|`rows`
|
||||
|The visible items, where rows contains maps of name and selected items.
|
||||
|
||||
|`model`
|
||||
|The parent context variables (see <<selectorcomponentcontext-template-variables>>).
|
||||
|===
|
||||
|
||||
You can pre-select an item by defining it to get exposed. This is
|
||||
useful if you know the default and lets the user merely press `Enter` to make a choice.
|
||||
The following listing sets a default:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet8]
|
||||
----
|
||||
====
|
||||
@@ -1,43 +0,0 @@
|
||||
[[using-shell-components-ui-stringinput]]
|
||||
==== String Input
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
The string input component asks a user for simple text input, optionally masking values
|
||||
if the content contains something sensitive. The following listing shows an example:
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/UiComponentSnippets.java[tag=snippet3]
|
||||
----
|
||||
====
|
||||
|
||||
The following image shows typical output from a string input component:
|
||||
|
||||
image::images/component-text-input-1.svg[text input]
|
||||
|
||||
The context object is `StringInputContext`. The following table lists its context variables:
|
||||
|
||||
[[stringinputcontext-template-variables]]
|
||||
.StringInputContext Template Variables
|
||||
|===
|
||||
|Key |Description
|
||||
|
||||
|`defaultValue`
|
||||
|The default value, if set. Otherwise, null.
|
||||
|
||||
|`maskedInput`
|
||||
|The masked input value
|
||||
|
||||
|`maskedResultValue`
|
||||
|The masked result value
|
||||
|
||||
|`maskCharacter`
|
||||
|The mask character, if set. Otherwise, null.
|
||||
|
||||
|`hasMaskCharacter`
|
||||
|`true` if a mask character is set. Otherwise, false.
|
||||
|
||||
|`model`
|
||||
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|
||||
|===
|
||||
@@ -1,36 +0,0 @@
|
||||
[[using-shell-components-ui]]
|
||||
=== Flow Components
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Starting from version 2.1.x, a new component model provides an
|
||||
easier way to create higher-level user interaction for the usual use cases,
|
||||
such as asking for input in various forms. These usually are just plain text
|
||||
input or choosing something from a list.
|
||||
|
||||
Templates for built-in components are in the
|
||||
`org/springframework/shell/component` classpath.
|
||||
|
||||
Built-in components generally follow this logic:
|
||||
|
||||
. Enter a run loop for user input.
|
||||
. Generate component-related context.
|
||||
. Render the runtime status of a component state.
|
||||
. Exit.
|
||||
. Render the final status of a component state.
|
||||
|
||||
NOTE: <<using-shell-components-flow>> gives better interface for defining the flow of
|
||||
components that are better suited for defining interactive command flows.
|
||||
|
||||
include::using-shell-components-ui-render.adoc[]
|
||||
|
||||
include::using-shell-components-ui-stringinput.adoc[]
|
||||
|
||||
include::using-shell-components-ui-pathinput.adoc[]
|
||||
|
||||
include::using-shell-components-ui-pathsearch.adoc[]
|
||||
|
||||
include::using-shell-components-ui-confirmation.adoc[]
|
||||
|
||||
include::using-shell-components-ui-singleselect.adoc[]
|
||||
|
||||
include::using-shell-components-ui-multiselect.adoc[]
|
||||
@@ -1,11 +0,0 @@
|
||||
[[using-shell-components]]
|
||||
== Components
|
||||
|
||||
Components are a set of features which are either build-in or something
|
||||
you can re-use or extend for your own needs. Components in question are
|
||||
either built-in _commands_ or UI side components providing higher level
|
||||
features within commands itself.
|
||||
|
||||
include::using-shell-components-flow.adoc[]
|
||||
|
||||
include::using-shell-components-ui.adoc[]
|
||||
@@ -1,44 +0,0 @@
|
||||
[[using-shell-customization-commandnotfound]]
|
||||
=== Command Not Found
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
On default a missing command is handled via `CommandNotFoundResultHandler`
|
||||
and outputs a simple message:
|
||||
|
||||
====
|
||||
[source, text]
|
||||
----
|
||||
shell:>missing
|
||||
No command found for 'missing'
|
||||
----
|
||||
====
|
||||
|
||||
Internally `CommandNotFoundResultHandler` is using `CommandNotFoundMessageProvider`
|
||||
which is a simple function taking a `ProviderContext` and returning a text
|
||||
message. Below is an example what a custom message provider might look like.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandNotFoundSnippets.java[tag=custom-provider]
|
||||
----
|
||||
====
|
||||
|
||||
It's possible to change this implementation by defining it as a bean.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandNotFoundSnippets.java[tag=provider-bean-1]
|
||||
----
|
||||
====
|
||||
|
||||
`CommandNotFoundResultHandler` is a functional interface so it can
|
||||
be writter as a lambda.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/CommandNotFoundSnippets.java[tag=provider-bean-2]
|
||||
----
|
||||
====
|
||||
@@ -1,23 +0,0 @@
|
||||
[[using-shell-customization-contextclose]]
|
||||
=== Context Close
|
||||
|
||||
Command execution logic happens via Spring Boot's `ApplicationRunner` beans.
|
||||
Normally Spring `ApplicationContext` closes automatically after these runner
|
||||
beans has been processed unless there is something what keeps it alive like
|
||||
use of `@EnableScheduling` or generally speaking there are threads which
|
||||
don't die automatically.
|
||||
|
||||
It is possible to add configuration property `spring.shell.context.close`
|
||||
which registers `ApplicationListener` for `ApplicationReadyEvent` and requests
|
||||
context close after shell has completed its execution logic.
|
||||
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
shell:
|
||||
context:
|
||||
close: true
|
||||
----
|
||||
|
||||
NOTE: This setting is not enabled by default.
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
[[using-shell-customization-logging]]
|
||||
=== Logging
|
||||
|
||||
On default a _Spring Boot_ application will log messages into a console which
|
||||
at minimum is annoying and may also mix output from a shell commands.
|
||||
Fortunately there is a simple way to instruct logging changes via boot properties.
|
||||
|
||||
Completely silence console logging by defining its pattern as an empty value.
|
||||
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
logging:
|
||||
pattern:
|
||||
console:
|
||||
----
|
||||
====
|
||||
|
||||
If you need log from a shell then write those into a file.
|
||||
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
logging:
|
||||
file:
|
||||
name: shell.log
|
||||
----
|
||||
====
|
||||
|
||||
If you need different log levels.
|
||||
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
logging:
|
||||
level:
|
||||
org:
|
||||
springframework:
|
||||
shell: debug
|
||||
----
|
||||
====
|
||||
|
||||
Passing contiguration properties as command line options is not supported but
|
||||
you can use any other ways supported by boot, for example.
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
$ java -Dlogging.level.root=debug -jar demo.jar
|
||||
$ LOGGING_LEVEL_ROOT=debug java -jar demo.jar
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: In a GraalVM image settings are locked during compilation which means
|
||||
you can't change log levels at runtime.
|
||||
@@ -1,23 +0,0 @@
|
||||
[[using-shell-customization-singlecommand]]
|
||||
=== Single Command
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
If your shell application is made for exactly a single purpose having only one
|
||||
command it may be beneficial to configure it for this. Property
|
||||
`spring.shell.noninteractive.primary-command` if defined will disable all other
|
||||
runners than `NonInteractiveShellRunner` and configures it to use
|
||||
defined _Primary Command_.
|
||||
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
shell:
|
||||
noninteractive:
|
||||
primary-command: mycommand
|
||||
----
|
||||
====
|
||||
|
||||
For example if you have a command `mycommand` with option `arg`
|
||||
it had to be executed with `<shellapp> mycommand --arg hi`, but with above
|
||||
setting it can be executed with `<shellapp> --arg hi`.
|
||||
@@ -1,68 +0,0 @@
|
||||
[[theming]]
|
||||
=== Theming
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Current terminal implementations are rich in features and can usually show
|
||||
something else that just plain text. For example a text can be styled to be
|
||||
_bold_ or have different colors. It's also common for terminals to be able
|
||||
to show various characters from an unicode table like emoji's which are usually
|
||||
used to make shell output more pretty.
|
||||
|
||||
Spring Shell supports these via it's theming framework which contains two parts,
|
||||
firstly _styling_ can be used to change text type and secondly _figures_ how
|
||||
some characters are shown. These two are then combined together as a _theme_.
|
||||
|
||||
More about _theming_ internals, see <<appendix-tech-intro-theming>>.
|
||||
|
||||
NOTE: Default theme is named `default` but can be change using property
|
||||
`spring.shell.theme.name`. Other built-in theme named `dump` uses
|
||||
no styling for colors and tries to not use any special figures.
|
||||
|
||||
Modify existing style by overriding settings.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ThemingSnippets.java[tag=custom-style-class]
|
||||
----
|
||||
====
|
||||
|
||||
Modify existing figures by overriding settings.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ThemingSnippets.java[tag=custom-figure-class]
|
||||
----
|
||||
====
|
||||
|
||||
To create a new theme, create a `ThemeSettings` and provide your own _style_
|
||||
and _figure_ implementations.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ThemingSnippets.java[tag=custom-theme-class]
|
||||
----
|
||||
====
|
||||
|
||||
Register a new bean `Theme` where you can return your custom `ThemeSettings`
|
||||
and a _theme_ name.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ThemingSnippets.java[tag=custom-theme-config]
|
||||
----
|
||||
====
|
||||
|
||||
You can use `ThemeResolver` to resolve _styles_ if you want to create
|
||||
JLine-styled strings programmatically and _figures_ if you want to
|
||||
theme characters for being more pretty.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/ThemingSnippets.java[tag=using-theme-resolver]
|
||||
----
|
||||
====
|
||||
@@ -1,14 +0,0 @@
|
||||
[[using-shell-customization]]
|
||||
== Customization
|
||||
|
||||
This section describes how you can customize the shell.
|
||||
|
||||
include::using-shell-customization-styling.adoc[]
|
||||
|
||||
include::using-shell-customization-logging.adoc[]
|
||||
|
||||
include::using-shell-customization-commandnotfound.adoc[]
|
||||
|
||||
include::using-shell-customization-singlecommand.adoc[]
|
||||
|
||||
include::using-shell-customization-contextclose.adoc[]
|
||||
@@ -1,35 +0,0 @@
|
||||
[[using-shell-execution]]
|
||||
== Execution
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
This section describes how to set up a Spring Shell to work in interactive mode.
|
||||
|
||||
[[using-shell-execution-interactionmode]]
|
||||
=== Interaction Mode
|
||||
|
||||
Version 2.1.x introduced built-in support to distinguish between interactive
|
||||
and non-interactive modes. This makes it easier to use the shell as a
|
||||
simple command-line tool without requiring customization.
|
||||
|
||||
Currently, interactive mode is entered if any command line options are passed when starting
|
||||
or running a shell from a command line. This works especially well when a shell application
|
||||
is compiled with <<native>>.
|
||||
|
||||
Some commands may not have any useful meanings when they run in interactive mode
|
||||
or (conversely) in non-interactive mode. For example, a built-in `exit` command would
|
||||
have no meaning in non-interactive mode, because it is used to exit interactive mode.
|
||||
|
||||
The `@ShellMethod` annotation has a field called `interactionMode` that you can use to inform
|
||||
shell about when a particular command is available.
|
||||
|
||||
[[using-shell-execution-shellrunner]]
|
||||
=== Shell Runners
|
||||
|
||||
`ShellApplicationRunner` is a main interface where Boot's `ApplicationArguments` are passed
|
||||
and its default implementation makes a choice which `ShellRunner` is used. There can be
|
||||
only one `ShellApplicationRunner` but it can be redefined if needed for some reason.
|
||||
|
||||
Three `ShellRunner` implementation exists, named `InteractiveShellRunner`,
|
||||
`NonInteractiveShellRunner` and `ScriptShellRunner`. These are enabled on default but
|
||||
can be disable if needed using properties `spring.shell.interactive.enabled`,
|
||||
`spring.shell.noninteractive.enabled` and `spring.shell.script.enabled` respecively.
|
||||
@@ -1,91 +0,0 @@
|
||||
[[using-shell-options-arity]]
|
||||
=== Arity
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Arity defines how many parameters option parsing takes.
|
||||
|
||||
NOTE: There are limitations in a `legacy annotation` compared to `annotation`
|
||||
and `programmatic` use of arity settings. These are mentioned in notes in
|
||||
below samples.
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-zeroorone-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-zeroorone-annotation]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Legacy Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-zeroorone-legacyannotation]
|
||||
----
|
||||
|
||||
[[using-shell-options-arity-optionarity-table]]
|
||||
.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
|
||||
|===
|
||||
|
||||
|
||||
NOTE: `legacy annotation` doesn't support defining minimum arity.
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-zerooronewithminmax-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-zerooronewithminmax-annotation]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Legacy Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-zerooronewithminmax-legacyannotation]
|
||||
----
|
||||
|
||||
In below example we have option _arg1_ and it's defined as type _String[]_. Arity
|
||||
defines that it needs at least 1 parameter and not more that 2. As seen in below
|
||||
spesific exceptions _TooManyArgumentsOptionException_ and
|
||||
_NotEnoughArgumentsOptionException_ are thrown to indicate arity mismatch.
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
shell:>e2e reg arity-errors --arg1
|
||||
Not enough arguments --arg1 requires at least 1.
|
||||
|
||||
shell:>e2e reg arity-errors --arg1 one
|
||||
Hello [one]
|
||||
|
||||
shell:>e2e reg arity-errors --arg1 one two
|
||||
Hello [one, two]
|
||||
|
||||
shell:>e2e reg arity-errors --arg1 one two three
|
||||
Too many arguments --arg1 requires at most 2.
|
||||
----
|
||||
====
|
||||
@@ -1,13 +0,0 @@
|
||||
[[using-shell-options-basics-annotation]]
|
||||
==== Annotation
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
`Option` 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-option-annotation]
|
||||
----
|
||||
====
|
||||
@@ -1,33 +0,0 @@
|
||||
[[using-shell-options-basics-legacyannotation]]
|
||||
==== Legacy Annotation
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
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]
|
||||
----
|
||||
====
|
||||
|
||||
If option name is defined without prefix, either `-` or `--`, it is discovered
|
||||
from _ShellMethod#prefix_.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-with-annotation-without-prefix]
|
||||
----
|
||||
====
|
||||
@@ -1,19 +0,0 @@
|
||||
[[using-shell-options-basics-registration]]
|
||||
[[using-shell-options-basics-programmatic]]
|
||||
==== Programmatic
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Programmatic way with `CommandRegistration` is to use `withOption` to define
|
||||
an option.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-longarg]
|
||||
----
|
||||
====
|
||||
|
||||
`CommandRegistration` can be defined as a bean or manually registered
|
||||
with a `CommandCatalog`.
|
||||
|
||||
NOTE: Check below sections for other option types, i.e. short format.
|
||||
@@ -1,13 +0,0 @@
|
||||
[[using-shell-options-basics]]
|
||||
=== Basics
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
This section gives a generic idea how an option can be defined. Following
|
||||
sections, beyond basics, discuss more about how various option behaviour
|
||||
can be accomplished for a particular use case.
|
||||
|
||||
include::using-shell-options-basics-programmatic.adoc[]
|
||||
|
||||
include::using-shell-options-basics-annotation.adoc[]
|
||||
|
||||
include::using-shell-options-basics-legacyannotation.adoc[]
|
||||
@@ -1,26 +0,0 @@
|
||||
[[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 the user defined an option and change behavior
|
||||
based on a default value:
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-default-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-default-annotation]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Legacy Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-default-legacyannotation]
|
||||
----
|
||||
@@ -1,359 +0,0 @@
|
||||
==== Invoking your Commands
|
||||
|
||||
This section addresses how you can control the way in which your commands are invoked.
|
||||
|
||||
===== By Name Versus Positional Parameters
|
||||
|
||||
As seen <<documenting-the-command,earlier>>, decorating a method with `@ShellMethod` is the sole requirement for creating a command.
|
||||
|
||||
The user can set the value of all the method parameters in either of two ways:
|
||||
|
||||
* By using a parameter key (for example, `--arg value`). This approach is called "`by name parameters.`"
|
||||
* Without a key, by setting parameter values in the order in which they appear in the method signature (called "`positional parameters`").
|
||||
|
||||
These two approaches can be mixed and matched, with named parameters always taking precedence (as they are less
|
||||
prone to ambiguity). Consider the following command definition:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Display stuff.")
|
||||
public String echo(int a, int b, int c) {
|
||||
return String.format("You said a=%d, b=%d, c=%d", a, b, c);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Given the preceding command definiton, the following invocations are all equivalent, as shown in the output:
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
shell:>echo 1 2 3 <1>
|
||||
You said a=1, b=2, c=3
|
||||
|
||||
shell:>echo --a 1 --b 2 --c 3 <2>
|
||||
You said a=1, b=2, c=3
|
||||
|
||||
shell:>echo --b 2 --c 3 --a 1 <3>
|
||||
You said a=1, b=2, c=3
|
||||
|
||||
shell:>echo --a 1 2 3 <4>
|
||||
You said a=1, b=2, c=3
|
||||
|
||||
shell:>echo 1 --c 3 2 <5>
|
||||
You said a=1, b=2, c=3
|
||||
----
|
||||
<1> This uses positional parameters.
|
||||
<2> This is an example of full by-name parameters.
|
||||
<3> By-name parameters can be reordered as desired.
|
||||
<4> You can use a mix of the two approaches.
|
||||
<5> The non by-name parameters are resolved in the order in which they appear.
|
||||
====
|
||||
|
||||
====== Customizing the Named Parameter Keys
|
||||
|
||||
As seen <<your-first-command,earlier>>, the default strategy for deriving the key for a named parameter is to use the Java
|
||||
name of the method signature and prefix it with two dashes (`--`). You can customize this in two ways:
|
||||
|
||||
* Use the `prefix()` attribute of the `@ShellMethod` annotation to change the default prefix for the whole method.
|
||||
* Annotate the parameter with the `@ShellOption` annotation to override the entire key in a per-parameter fashion.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod(value = "Display stuff.", prefix="-")
|
||||
public String echo(int a, int b, @ShellOption("--third") int c) {
|
||||
return String.format("You said a=%d, b=%d, c=%d", a, b, c);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
For such a setup, the possible parameter keys are `-a`, `-b` and `--third`.
|
||||
|
||||
[TIP]
|
||||
=====
|
||||
You can specify several keys for a single parameter. If you do so, these keys are mutually exclusive (only one of them can be used) ways
|
||||
to specify the same parameter. The following example shows the signature of the
|
||||
built-in <<built-in-commands-help,`help`>> command:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Describe a command.")
|
||||
public String help(@ShellOption({"-C", "--command"}) String command) {
|
||||
...
|
||||
}
|
||||
----
|
||||
====
|
||||
=====
|
||||
|
||||
[[optional-parameters-default-values]]
|
||||
===== Optional Parameters and Default Values
|
||||
|
||||
Spring Shell provides the ability to give parameters default values, which lets users omit
|
||||
those parameters. Consider the following command definition:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Say hello.")
|
||||
public String greet(@ShellOption(defaultValue="World") String who) {
|
||||
return "Hello " + who;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
With the preceding definition, the `greet` command can still be invoked as `greet Mother` (or `greet --who Mother`), but the following
|
||||
is also possible:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>greet
|
||||
Hello World
|
||||
----
|
||||
====
|
||||
|
||||
===== Parameter Arity
|
||||
Up to now, it has always been assumed that each parameter maps to a single word entered by the user.
|
||||
Situations may arise, though, when a parameter value should be multi-valued. This is driven by the `arity()`
|
||||
attribute of the `@ShellOption` annotation. You can use a collection or array for the parameter type and specify how
|
||||
many values are expected:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Add Numbers.")
|
||||
public float add(@ShellOption(arity=3) float[] numbers) {
|
||||
return numbers[0] + numbers[1] + numbers[2];
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The users can then invoke the command by using any of the following syntax:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>add 1 2 3.3
|
||||
6.3
|
||||
shell:>add --numbers 1 2 3.3
|
||||
6.3
|
||||
----
|
||||
====
|
||||
|
||||
[WARNING]
|
||||
=====
|
||||
When using the _by-name_ parameter approach, the key should *not* be repeated. The following does *not* work:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>add --numbers 1 --numbers 2 --numbers 3.3
|
||||
----
|
||||
====
|
||||
=====
|
||||
|
||||
====== Varying Amount Arity
|
||||
|
||||
The above example demonstrates requiring a known, constant arity for a parameter, three in this case. Allowing any number of multiple values of a parameter can be achieved by leaving `arity` unspecified and using Spring's built-in comma separated value parsing for collections and/or arrays:
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Add a Varying Amount of Numbers.")
|
||||
public double add(@ShellOption double[] numbers) {
|
||||
return Arrays.stream(numbers).sum();
|
||||
}
|
||||
----
|
||||
|
||||
The command may then be invoked with any amount of `numbers`:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>add 1,2,3.3
|
||||
6.3
|
||||
shell:>add --numbers 42
|
||||
42.0
|
||||
shell:>add --numbers 1,2,3.3,4,5
|
||||
15.3
|
||||
----
|
||||
====
|
||||
|
||||
====== Special Handling of Boolean Parameters
|
||||
|
||||
When it comes to parameter arity, one kind of parameter receives a special treatment by default, as
|
||||
is often the case in command-line utilities.
|
||||
Boolean (that is, `boolean` as well as `java.lang.Boolean`) parameters behave like they have an `arity()` of `0` by default, allowing users to set their values by using a "`flag`" approach.
|
||||
Consider the following command definition:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Terminate the system.")
|
||||
public String shutdown(boolean force) {
|
||||
return "You said " + force;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
This preceding command definition allows the following invocations:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>shutdown
|
||||
You said false
|
||||
shell:>shutdown --force
|
||||
You said true
|
||||
----
|
||||
====
|
||||
|
||||
TIP: This special treatment plays well with the <<optional-parameters-default-values,default value>> specification. Although the default
|
||||
for boolean parameters is to have their default value be `false`, you can specify otherwise (that is,
|
||||
`@ShellOption(defaultValue="true")`), and the behavior is inverted (that is, not specifying the parameter
|
||||
results in the value being `true`, and specifying the flag results in the value being `false`)
|
||||
|
||||
[WARNING]
|
||||
=====
|
||||
Having this behavior of implicit `arity()=0` prevents the user from specifying a value (for example, `shutdown --force true`).
|
||||
If you would like to allow this behavior (and forego the flag approach), then force an arity of `1` by using the annotation as follows:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Terminate the system.")
|
||||
public String shutdown(@ShellOption(arity=1, defaultValue="false") boolean force) {
|
||||
return "You said " + force;
|
||||
}
|
||||
----
|
||||
====
|
||||
=====
|
||||
|
||||
[[quotes-handling]]
|
||||
===== Quotes Handling
|
||||
|
||||
Spring Shell takes user input and tokenizes it into words, splitting on space characters.
|
||||
If the user wants to provide a parameter value that contains spaces, that value needs to be quoted.
|
||||
Both single (`'`) and double (`"`) quotes are supported, and those quotes are not part of the value:
|
||||
Consider the following command definition:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Prints what has been entered.")
|
||||
public String echo(String what) {
|
||||
return "You said " + what;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The following commands all invoke the preceding command definition:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>echo Hello
|
||||
You said Hello
|
||||
shell:>echo 'Hello'
|
||||
You said Hello
|
||||
shell:>echo 'Hello World'
|
||||
You said Hello World
|
||||
shell:>echo "Hello World"
|
||||
You said Hello World
|
||||
----
|
||||
====
|
||||
|
||||
Supporting both single and double quotes lets the user embed one type of quotes into
|
||||
a value:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>echo "I'm here!"
|
||||
You said I'm here!
|
||||
shell:>echo 'He said "Hi!"'
|
||||
You said He said "Hi!"
|
||||
----
|
||||
====
|
||||
|
||||
That way, the user can use a single quote as an apostrophe in a message.
|
||||
|
||||
Should the user need to embed the same kind of quote that was used to quote the whole parameter,
|
||||
the escape sequence uses the backslash (`\`) character:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>echo 'I\'m here!'
|
||||
You said I'm here!
|
||||
shell:>echo "He said \"Hi!\""
|
||||
You said He said "Hi!"
|
||||
shell:>echo I\'m here!
|
||||
You said I'm here!
|
||||
----
|
||||
====
|
||||
|
||||
It is also possible to escape space characters when not using enclosing quotes:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>echo This\ is\ a\ single\ value
|
||||
You said This is a single value
|
||||
----
|
||||
====
|
||||
|
||||
[[interacting-with-the-shell]]
|
||||
===== Interacting with the Shell
|
||||
|
||||
The Spring Shell project builds on top of the https://github.com/jline/jline3[JLine] library and, as a result, brings
|
||||
a lot of nice interactive features, some of which are detailed in this section.
|
||||
|
||||
First and foremost, Spring Shell supports tab completion almost everywhere possible. So, if there
|
||||
is an `echo` command and the user types `ec` and presses `TAB`, `echo` appears.
|
||||
Should there be several commands that start with `ec`, then the user is prompted to choose (using `TAB` or
|
||||
`Shift + TAB` to navigate and `ENTER` to select.)
|
||||
|
||||
But completion does not stop at command keys. It also works for parameter keys (`--arg`) and even
|
||||
parameter values, if the application developer registered the appropriate beans (see <<providing-tab-completion>>).
|
||||
|
||||
Another nice feature of Spring Shell applications is support for line continuation. If a command and its parameters
|
||||
is too long and does not fit nicely on the screen, a user can chunk it by ending a line with a backslash
|
||||
(`\`) character, pressing `ENTER`, and continuing on the next line. Upon submission of the whole command, this is
|
||||
parsed as if the user entered a single space on line breaks. The following listing shows an example of this behavior:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>register module --type source --name foo \ <1>
|
||||
> --uri file:///tmp/bar
|
||||
Successfully registered module 'source:foo'
|
||||
----
|
||||
<1> command continues on next line
|
||||
====
|
||||
|
||||
Line continuation also automatically triggers if the user has opened a quote (see <<quotes-handling>>)
|
||||
and presses `ENTER` while still in the quotes:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>echo "Hello <1>
|
||||
dquote> World"
|
||||
You said Hello World
|
||||
----
|
||||
<1> The user pressed `ENTER` here.
|
||||
====
|
||||
|
||||
Finally, Spring Shell applications benefit from a lot of keyboard shortcuts (borrowed from Emacs) with which you may
|
||||
already be familiar from working with your regular OS Shell. Notable shortcuts include `Ctrl+r` to perform
|
||||
a reverse search, `Ctrl+a`] and `Ctrl+e` to move to the beginning and the end of the current line (respectively),
|
||||
and `Esc f` and `Esc b` to move forward or backward (respectively) one word at a time.
|
||||
|
||||
[[providing-tab-completion]]
|
||||
// ===== Providing TAB Completion Proposals
|
||||
|
||||
// TBD
|
||||
@@ -1,40 +0,0 @@
|
||||
[[using-shell-options-label]]
|
||||
=== Label
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_Option Label_ has no functional behaviour within a shell itself other than
|
||||
what a default `help` command outputs. Within a command documentation
|
||||
a type of an option is documented but this is not always super useful. Thus
|
||||
you may want to give better descriptive word for an option.
|
||||
|
||||
NOTE: Label is not supported with `legacy annotation`.
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-label-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-label-annotation]
|
||||
----
|
||||
|
||||
Defining label is then shown in `help`.
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
my-shell:>help labelOption
|
||||
NAME
|
||||
labelOption -
|
||||
|
||||
SYNOPSIS
|
||||
labelOption --arg MYLABEL
|
||||
|
||||
OPTIONS
|
||||
--arg MYLABEL
|
||||
[Optional]
|
||||
|
||||
----
|
||||
====
|
||||
@@ -1,113 +0,0 @@
|
||||
[[using-shell-options-naming]]
|
||||
=== Naming
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
If there is a need to modify option long names that can be done
|
||||
using `OptionNameModifier` interface which is a simple
|
||||
`Function<String, String>`. In this interface original option
|
||||
name goes in and modified name comes out.
|
||||
|
||||
Modifier can be defined per `OptionSpec` in `CommandRegistration`,
|
||||
defaulting globally as bean or via configuration properties.
|
||||
Modifier defined manually in `OptionSpec` takes takes precedence
|
||||
over one defined globally. There is no global modifier defined
|
||||
on default.
|
||||
|
||||
You can define one with an option in `CommandRegistration`.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-naming-case-req]
|
||||
----
|
||||
====
|
||||
|
||||
Add one _singleton bean_ as type `OptionNameModifier` and that becomes
|
||||
a global default.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-naming-case-bean]
|
||||
----
|
||||
====
|
||||
|
||||
It's also possible to just add configuration property with
|
||||
`spring.shell.option.naming.case-type` which auto-configures
|
||||
one based on a type defined.
|
||||
|
||||
`noop` is to do nothing, `camel`, `snake`, `kebab`, `pascal`
|
||||
activates build-in modifiers for `camelCase`, `snake_case`,
|
||||
`kebab-case` or `PascalCase` respectively.
|
||||
|
||||
NOTE: If creating `CommandRegistration` beans directly, global
|
||||
default via configuration properies only work if using
|
||||
pre-configured `Builder` instance. See more
|
||||
<<using-shell-commands-programmaticmodel>>.
|
||||
|
||||
====
|
||||
[source, yaml]
|
||||
----
|
||||
spring:
|
||||
shell:
|
||||
option:
|
||||
naming:
|
||||
case-type: noop
|
||||
# case-type: camel
|
||||
# case-type: snake
|
||||
# case-type: kebab
|
||||
# case-type: pascal
|
||||
----
|
||||
====
|
||||
|
||||
For example options defined in an annotated method like this.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-naming-case-sample1]
|
||||
----
|
||||
====
|
||||
|
||||
On default `help` for that command shows names coming
|
||||
directly from `@ShellOption`.
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
OPTIONS
|
||||
--from_snake String
|
||||
[Mandatory]
|
||||
|
||||
--fromCamel String
|
||||
[Mandatory]
|
||||
|
||||
--from-kebab String
|
||||
[Mandatory]
|
||||
|
||||
--FromPascal String
|
||||
[Mandatory]
|
||||
----
|
||||
====
|
||||
|
||||
Define `spring.shell.option.naming.case-type=kebab` and default
|
||||
modifier is added and option names then look like.
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
OPTIONS
|
||||
--from-snake String
|
||||
[Mandatory]
|
||||
|
||||
--from-camel String
|
||||
[Mandatory]
|
||||
|
||||
--from-kebab String
|
||||
[Mandatory]
|
||||
|
||||
--from-pascal String
|
||||
[Mandatory]
|
||||
|
||||
----
|
||||
====
|
||||
@@ -1,46 +0,0 @@
|
||||
[[using-shell-options-optional]]
|
||||
=== Optional Value
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
An option is either required or not and, generally speaking, how it behaves depends on
|
||||
a command target.
|
||||
|
||||
Making option optional.
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-optional-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-optional-annotation]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Legacy Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-optional-legacyannotation]
|
||||
----
|
||||
|
||||
Making option mandatory.
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-mandatory-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-mandatory-annotation]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Legacy Annotation
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-mandatory-legacyannotation]
|
||||
----
|
||||
@@ -1,70 +0,0 @@
|
||||
[[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]
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Be careful with positional parameters as it may soon
|
||||
become confusing which options those are mapped to.
|
||||
|
||||
Usually arguments are mapped to an option when those are defined in a
|
||||
command line whether it's a long or short option. Generally speaking
|
||||
there are _options_, _option arguments_ and _arguments_ where latter
|
||||
are the ones which are not mapped to any spesific option.
|
||||
|
||||
Unrecognised arguments can then have a secondary mapping logic where
|
||||
positional information is important. With option position you're
|
||||
essentially telling command parsing how to interpret plain raw
|
||||
ambiguous arguments.
|
||||
|
||||
Let's look what happens when we don't define a position.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-aritystrings-noposition]
|
||||
----
|
||||
====
|
||||
|
||||
Option _arg1_ is required and there is no info what to do with argument
|
||||
`one` resulting error for missing option.
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
shell:>arity-strings-1 one
|
||||
Missing mandatory option --arg1.
|
||||
----
|
||||
====
|
||||
|
||||
Now let's define a position `0`.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionSnippets.java[tag=option-registration-aritystrings-position]
|
||||
----
|
||||
====
|
||||
|
||||
Arguments are processed until we get up to 2 arguments.
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
shell:>arity-strings-2 one
|
||||
Hello [one]
|
||||
|
||||
shell:>arity-strings-2 one two
|
||||
Hello [one, two]
|
||||
|
||||
shell:>arity-strings-2 one two three
|
||||
Hello [one, two]
|
||||
----
|
||||
====
|
||||
@@ -1,46 +0,0 @@
|
||||
[[using-shell-options-short]]
|
||||
=== Short Format
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Short style _POSIX_ option is usually just a synonym to long format. As
|
||||
shown below option `--arg` is equal to `-a`.
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-annotation]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Legacy Annotation
|
||||
----
|
||||
include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-legacyannotation]
|
||||
----
|
||||
|
||||
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 presence of a flags
|
||||
as `-abc`, `-abc true` or `-abc false`.
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.Programmatic
|
||||
----
|
||||
include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-programmatic]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Annotation
|
||||
----
|
||||
include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-annotation]
|
||||
----
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.Legacy Annotation
|
||||
----
|
||||
include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-legacyannotation]
|
||||
----
|
||||
@@ -1,137 +0,0 @@
|
||||
[[using-shell-options-types]]
|
||||
=== Types
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
This section talks about how particular data type is used as an option value.
|
||||
|
||||
==== String
|
||||
|
||||
`String` is a most simplest type as there's no conversion involved as what's
|
||||
coming in from a user is always a string.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-anno]
|
||||
----
|
||||
====
|
||||
|
||||
While it's not strictly required to define type as a `String` it's always
|
||||
adviced to do so.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-reg]
|
||||
----
|
||||
====
|
||||
|
||||
==== Boolean
|
||||
|
||||
Using boolean types is a bit more involved as there are `boolean` and
|
||||
`Boolean` where latter can be _null_. Boolean types are usually used as
|
||||
flags meaning argument value may not be needed.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-boolean-anno]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
shell:>example
|
||||
arg1=false arg2=true arg3=false arg4=false arg5=true arg6=false
|
||||
|
||||
shell:>example --arg4
|
||||
arg1=false arg2=true arg3=false arg4=true arg5=true arg6=false
|
||||
|
||||
shell:>example --arg4 false
|
||||
arg1=false arg2=true arg3=false arg4=false arg5=true arg6=false
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-boolean-reg]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
shell:>example
|
||||
arg1=false arg2=true arg3=false arg4=null arg5=true arg6=false
|
||||
|
||||
shell:>example --arg4
|
||||
arg1=false arg2=true arg3=false arg4=true arg5=true arg6=false
|
||||
|
||||
shell:>example --arg4 false
|
||||
arg1=false arg2=true arg3=false arg4=false arg5=true arg6=false
|
||||
----
|
||||
====
|
||||
|
||||
==== Number
|
||||
|
||||
Numbers are converted as is.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-integer-anno]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-integer-reg]
|
||||
----
|
||||
====
|
||||
|
||||
==== Enum
|
||||
|
||||
Conversion to enums is possible if given value is exactly matching enum itself.
|
||||
Currently you can convert assuming case insensitivity.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-enum-class]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-enum-anno]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-enum-reg]
|
||||
----
|
||||
====
|
||||
|
||||
==== Array
|
||||
|
||||
Arrays can be used as is with strings and primitive types.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-array-anno]
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-array-reg]
|
||||
----
|
||||
====
|
||||
@@ -1,28 +0,0 @@
|
||||
[[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.
|
||||
|
||||
Annotations found on command parameters and annotations at the method level are
|
||||
honored and trigger validation prior to the command executing. Consider the following command:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@ShellMethod("Change password.")
|
||||
public String changePassword(@Size(min = 8, max = 40) String password) {
|
||||
return "Password successfully set to " + password;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
From the preceding example, you get the following behavior for free:
|
||||
|
||||
====
|
||||
----
|
||||
shell:>change-password hello
|
||||
The following constraints were not met:
|
||||
--password string : size must be between 8 and 40 (You passed 'hello')
|
||||
----
|
||||
====
|
||||
@@ -1,38 +0,0 @@
|
||||
[[using-shell-options]]
|
||||
== Options
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Command line arguments can be separated into options and positional parameters.
|
||||
Following sections describes features how options are defined and used. We first
|
||||
go through some basics about using options and then go into details about
|
||||
various ways how options and arguments works.
|
||||
|
||||
Generally speaking an _option_ is something after a commands prefixed with
|
||||
either `-` or `--`. An _option_ can either have a value or not depending
|
||||
on its context.
|
||||
|
||||
Options can be defined with a target method using annotations with a method
|
||||
arguments or with programmatically using `CommandRegistration`.
|
||||
|
||||
NOTE: In below sections `@ShellOption` refer to a _legacy annotation model_
|
||||
and `@Option` refer to an _annotation model_.
|
||||
|
||||
include::using-shell-options-basics.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[]
|
||||
|
||||
include::using-shell-options-label.adoc[]
|
||||
|
||||
include::using-shell-options-types.adoc[]
|
||||
|
||||
include::using-shell-options-naming.adoc[]
|
||||
@@ -1,25 +0,0 @@
|
||||
[[using-shell-testing-basics]]
|
||||
=== Basics
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Spring Shell provides a number of utilities and annotations to help when testing your application.
|
||||
Test support is provided by two modules: `spring-shell-test` contains core items, and
|
||||
`spring-shell-test-autoconfigure` supports auto-configuration for tests.
|
||||
|
||||
To test _interactive_ commands.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-interactive]
|
||||
----
|
||||
====
|
||||
|
||||
To test _non-interactive_ commands.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-noninteractive]
|
||||
----
|
||||
====
|
||||
@@ -1,27 +0,0 @@
|
||||
[[using-shell-testing-settings]]
|
||||
=== Settings
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Built in emulation uses terminal width 80 and height 24 on default.
|
||||
Changing dimensions is useful if output would span into multiple
|
||||
lines and you don't want to handle those cases in a tests.
|
||||
|
||||
These can be changed using properties `spring.shell.test.terminal-width`
|
||||
or `spring.shell.test.terminal-height`.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-dimensions-props]
|
||||
----
|
||||
====
|
||||
|
||||
`ShellTest` annotation have fields `terminalWidth` and `terminalHeight`
|
||||
which can also be used to change dimensions.
|
||||
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-dimensions-field]
|
||||
----
|
||||
====
|
||||
@@ -1,20 +0,0 @@
|
||||
[[using-shell-testing]]
|
||||
== Testing
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Testing cli application is difficult due to various reasons:
|
||||
|
||||
- There are differences between OS's.
|
||||
- Within OS there may be different shell implementations in use.
|
||||
- What goes into a shell and comes out from a shell my be totally
|
||||
different what you see in shell itself due to control characters.
|
||||
- Shell may feel syncronous but most likely it is not meaning when
|
||||
someting is written into it, you can't assume next update in
|
||||
in it is not final.
|
||||
|
||||
NOTE: Testing support is currently under development and will be
|
||||
unstable for various parts.
|
||||
|
||||
include::using-shell-testing-basics.adoc[]
|
||||
|
||||
include::using-shell-testing-settings.adoc[]
|
||||
@@ -1,17 +0,0 @@
|
||||
include::using-shell-basics.adoc[]
|
||||
|
||||
include::using-shell-commands.adoc[]
|
||||
|
||||
include::using-shell-options.adoc[]
|
||||
|
||||
include::using-shell-completion.adoc[]
|
||||
|
||||
include::using-shell-building.adoc[]
|
||||
|
||||
include::using-shell-components.adoc[]
|
||||
|
||||
include::using-shell-customization.adoc[]
|
||||
|
||||
include::using-shell-execution.adoc[]
|
||||
|
||||
include::using-shell-testing.adoc[]
|
||||