Migrate Structure
This commit is contained in:
@@ -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,12 +0,0 @@
|
||||
[#appendix-tui-catalog]
|
||||
=== Catalog App
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Catalog application is showing various ways how Terminal UI Framework can be used.
|
||||
In this section we discuss how this application works. It can be considered to be
|
||||
a reference application as it's using most of the features available and tries
|
||||
to follow best practices.
|
||||
|
||||
==== Create Scenario
|
||||
Every `Scenario` essentially is a sample code of a `View` as that's what catalog
|
||||
app demonstrates.
|
||||
@@ -1,5 +0,0 @@
|
||||
[#appendix-tui-control]
|
||||
=== Control
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_Control_ draws something into a screen with a given bounds.
|
||||
@@ -1,5 +0,0 @@
|
||||
[#appendix-tui-eventloop]
|
||||
=== EventLoop
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_EventLoop_ is a central system handling eventing in a framework.
|
||||
@@ -1,5 +0,0 @@
|
||||
[#appendix-tui-keyhandling]
|
||||
=== Key Handling
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Handles incoming key events.
|
||||
@@ -1,5 +0,0 @@
|
||||
[#appendix-tui-mousehandling]
|
||||
=== Mouse Handling
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Handles incoming mouse events.
|
||||
@@ -1,6 +0,0 @@
|
||||
[#appendix-tui-screen]
|
||||
=== Screen
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_Screen_ is an abstraction providing higher level concept to draw something
|
||||
into a terminal.
|
||||
@@ -1,5 +0,0 @@
|
||||
[#appendix-tui-view]
|
||||
=== View
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_View_ extends _Control_ providing integration into event loop.
|
||||
@@ -1,22 +0,0 @@
|
||||
[appendix]
|
||||
[#appendix-tech-intro-tui]
|
||||
== Terminal UI
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
This is a technical introduction to _UI Framework_.
|
||||
|
||||
_UI Framework_ is a toolkit to build rich console apps.
|
||||
|
||||
include::appendices-tui-control.adoc[]
|
||||
|
||||
include::appendices-tui-view.adoc[]
|
||||
|
||||
include::appendices-tui-eventloop.adoc[]
|
||||
|
||||
include::appendices-tui-screen.adoc[]
|
||||
|
||||
include::appendices-tui-keyhandling.adoc[]
|
||||
|
||||
include::appendices-tui-mousehandling.adoc[]
|
||||
|
||||
include::appendices-tui-catalog.adoc[]
|
||||
@@ -1,5 +0,0 @@
|
||||
include::appendices-techical-intro.adoc[]
|
||||
|
||||
include::appendices-debugging.adoc[]
|
||||
|
||||
include::appendices-tui.adoc[]
|
||||
@@ -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.boot</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.
|
||||
@@ -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,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,12 +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[]
|
||||
@@ -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,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,14 +0,0 @@
|
||||
[[using-shell-tui-intro]]
|
||||
=== Introduction
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Lets start with a simple app which prints "hello world" in a view.
|
||||
====
|
||||
[source, java, indent=0]
|
||||
----
|
||||
include::{snippets}/TerminalUiSnippets.java[tag=snippet1]
|
||||
----
|
||||
====
|
||||
|
||||
There is not much to see here other than `TerminalUI` is a class handling
|
||||
all logic aroung views and uses `View` as it's root view.
|
||||
@@ -1,6 +0,0 @@
|
||||
[[using-shell-tui-views-box]]
|
||||
==== BoxView
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_BoxView_ is a base implementation providing functionality to draw into a
|
||||
bounded _Rectancle_.
|
||||
@@ -1,5 +0,0 @@
|
||||
[[using-shell-tui-views-list]]
|
||||
==== ListView
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
_ListView_ is a base implementation providing functionality to draw list of items.
|
||||
@@ -1,11 +0,0 @@
|
||||
[[using-shell-tui-views]]
|
||||
=== Views
|
||||
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
|
||||
|
||||
Framework provides a build-in views which are documented below.
|
||||
|
||||
TIP: To learn more about views, see <<appendix-tui-view>>.
|
||||
|
||||
include::using-shell-tui-views-box.adoc[]
|
||||
|
||||
include::using-shell-tui-views-list.adoc[]
|
||||
@@ -1,16 +0,0 @@
|
||||
[[using-shell-tui]]
|
||||
== Terminal UI
|
||||
|
||||
NOTE: Feature is experimental and subject to breaking changes until foundation
|
||||
and related concepts around framework are getting more stable.
|
||||
|
||||
_Terminal UI Framework_ is a toolkit to build rich console apps. This section is
|
||||
for those using existing features as is. If you're planning to go deeper possibly
|
||||
creating your own components <<appendix-tech-intro-tui>> provides more detailed
|
||||
documentation.
|
||||
|
||||
TIP: Catalog sample is a good place to study a real application <<appendix-tui-catalog>>.
|
||||
|
||||
include::using-shell-tui-intro.adoc[]
|
||||
|
||||
include::using-shell-tui-views.adoc[]
|
||||
@@ -1,19 +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-tui.adoc[]
|
||||
|
||||
include::using-shell-customization.adoc[]
|
||||
|
||||
include::using-shell-execution.adoc[]
|
||||
|
||||
include::using-shell-testing.adoc[]
|
||||
Reference in New Issue
Block a user