Rework getting started section
- With build add feature to resolve dep versions which can be used in docs. - More polished maven/gradle example. - Relates #527
This commit is contained in:
@@ -33,6 +33,7 @@ import org.asciidoctor.gradle.jvm.AsciidoctorTask;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.plugins.JavaLibraryPlugin;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.PluginManager;
|
||||
@@ -57,20 +58,26 @@ class DocsPlugin implements Plugin<Project> {
|
||||
pluginManager.apply(SpringMavenPlugin.class);
|
||||
pluginManager.apply(AsciidoctorJPlugin.class);
|
||||
|
||||
configureAdocPlugins(project);
|
||||
ExtractVersionConstraints dependencyVersions = project.getTasks().create("dependencyVersions",
|
||||
ExtractVersionConstraints.class, task -> {
|
||||
task.enforcedPlatform(":spring-shell-management");
|
||||
});
|
||||
|
||||
configureAdocPlugins(project, dependencyVersions);
|
||||
|
||||
project.getTasks().withType(GenerateModuleMetadata.class, metadata -> {
|
||||
metadata.setEnabled(false);
|
||||
});
|
||||
}
|
||||
|
||||
private void configureAdocPlugins(Project project) {
|
||||
private void configureAdocPlugins(Project project, ExtractVersionConstraints dependencyVersions) {
|
||||
project.getPlugins().withType(AsciidoctorJPlugin.class, (asciidoctorPlugin) -> {
|
||||
createDefaultAsciidoctorRepository(project);
|
||||
makeAllWarningsFatal(project);
|
||||
Sync unzipResources = createUnzipDocumentationResourcesTask(project);
|
||||
Sync snippetsResources = createSnippetsResourcesTask(project);
|
||||
project.getTasks().withType(AbstractAsciidoctorTask.class, (asciidoctorTask) -> {
|
||||
asciidoctorTask.dependsOn(dependencyVersions);
|
||||
asciidoctorTask.dependsOn(unzipResources);
|
||||
asciidoctorTask.dependsOn(snippetsResources);
|
||||
// configureExtensions(project, asciidoctorTask);
|
||||
@@ -94,12 +101,13 @@ class DocsPlugin implements Plugin<Project> {
|
||||
// For now copy the entire sourceDir over so that include files are
|
||||
// available in the intermediateWorkDir
|
||||
resourcesSrcDirSpec.include("images/*");
|
||||
resourcesSrcDirSpec.include("code/*");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (asciidoctorTask instanceof AsciidoctorTask) {
|
||||
configureHtmlOnlyAttributes(project, asciidoctorTask);
|
||||
configureHtmlOnlyAttributes(project, asciidoctorTask, dependencyVersions);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -179,7 +187,26 @@ class DocsPlugin implements Plugin<Project> {
|
||||
asciidoctorTask.options(Collections.singletonMap("doctype", "book"));
|
||||
}
|
||||
|
||||
private void configureHtmlOnlyAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
|
||||
private void configureHtmlOnlyAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask,
|
||||
ExtractVersionConstraints dependencyVersions) {
|
||||
|
||||
asciidoctorTask.doFirst(new Action<Task>() {
|
||||
|
||||
@Override
|
||||
public void execute(Task arg0) {
|
||||
asciidoctorTask.getAttributeProviders().add(new AsciidoctorAttributeProvider() {
|
||||
@Override
|
||||
public Map<String, Object> getAttributes() {
|
||||
Map<String, String> versionConstraints = dependencyVersions.getVersionConstraints();
|
||||
Map<String, Object> attrs = new HashMap<>();
|
||||
attrs.put("spring-version", versionConstraints.get("org.springframework:spring-core"));
|
||||
attrs.put("spring-boot-version", versionConstraints.get("org.springframework.boot:spring-boot"));
|
||||
return attrs;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("toc", "left");
|
||||
attributes.put("source-highlighter", "highlight.js");
|
||||
@@ -195,8 +222,7 @@ class DocsPlugin implements Plugin<Project> {
|
||||
Object version = project.getVersion();
|
||||
Map<String, Object> attrs = new HashMap<>();
|
||||
if (version != null && version.toString() != Project.DEFAULT_VERSION) {
|
||||
attrs.put("revnumber", version);
|
||||
attrs.put("projectVersion", version);
|
||||
attrs.put("project-version", version);
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
package org.springframework.shell.gradle;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.artifacts.ComponentMetadataDetails;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.DependencyConstraint;
|
||||
import org.gradle.api.artifacts.DependencyConstraintMetadata;
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
/**
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
class ExtractVersionConstraints extends DefaultTask {
|
||||
|
||||
private final Configuration configuration;
|
||||
|
||||
private final Map<String, String> versionConstraints = new TreeMap<>();
|
||||
|
||||
private final Set<ConstrainedVersion> constrainedVersions = new TreeSet<>();
|
||||
|
||||
private final Set<VersionProperty> versionProperties = new TreeSet<>();
|
||||
|
||||
private final List<String> projectPaths = new ArrayList<>();
|
||||
|
||||
public ExtractVersionConstraints() {
|
||||
DependencyHandler dependencies = getProject().getDependencies();
|
||||
this.configuration = getProject().getConfigurations().create(getName());
|
||||
dependencies.getComponents().all(this::processMetadataDetails);
|
||||
}
|
||||
|
||||
public void enforcedPlatform(String projectPath) {
|
||||
this.configuration.getDependencies().add(getProject().getDependencies().enforcedPlatform(
|
||||
getProject().getDependencies().project(Collections.singletonMap("path", projectPath))));
|
||||
this.projectPaths.add(projectPath);
|
||||
}
|
||||
|
||||
@Internal
|
||||
public Map<String, String> getVersionConstraints() {
|
||||
return Collections.unmodifiableMap(this.versionConstraints);
|
||||
}
|
||||
|
||||
@Internal
|
||||
public Set<ConstrainedVersion> getConstrainedVersions() {
|
||||
return this.constrainedVersions;
|
||||
}
|
||||
|
||||
@Internal
|
||||
public Set<VersionProperty> getVersionProperties() {
|
||||
return this.versionProperties;
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void extractVersionConstraints() {
|
||||
this.configuration.resolve();
|
||||
for (String projectPath : this.projectPaths) {
|
||||
for (DependencyConstraint constraint : getProject().project(projectPath).getConfigurations()
|
||||
.getByName("apiElements").getAllDependencyConstraints()) {
|
||||
this.versionConstraints.put(constraint.getGroup() + ":" + constraint.getName(),
|
||||
constraint.getVersionConstraint().toString());
|
||||
this.constrainedVersions.add(new ConstrainedVersion(constraint.getGroup(), constraint.getName(),
|
||||
constraint.getVersionConstraint().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processMetadataDetails(ComponentMetadataDetails details) {
|
||||
details.allVariants((variantMetadata) -> variantMetadata.withDependencyConstraints((dependencyConstraints) -> {
|
||||
for (DependencyConstraintMetadata constraint : dependencyConstraints) {
|
||||
this.versionConstraints.put(constraint.getGroup() + ":" + constraint.getName(),
|
||||
constraint.getVersionConstraint().toString());
|
||||
this.constrainedVersions.add(new ConstrainedVersion(constraint.getGroup(), constraint.getName(),
|
||||
constraint.getVersionConstraint().toString()));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static final class ConstrainedVersion implements Comparable<ConstrainedVersion>, Serializable {
|
||||
|
||||
private final String group;
|
||||
|
||||
private final String artifact;
|
||||
|
||||
private final String version;
|
||||
|
||||
private ConstrainedVersion(String group, String artifact, String version) {
|
||||
this.group = group;
|
||||
this.artifact = artifact;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public String getArtifact() {
|
||||
return this.artifact;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ConstrainedVersion other) {
|
||||
int groupComparison = this.group.compareTo(other.group);
|
||||
if (groupComparison != 0) {
|
||||
return groupComparison;
|
||||
}
|
||||
return this.artifact.compareTo(other.artifact);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class VersionProperty implements Comparable<VersionProperty>, Serializable {
|
||||
|
||||
private final String libraryName;
|
||||
|
||||
private final String versionProperty;
|
||||
|
||||
public VersionProperty(String libraryName, String versionProperty) {
|
||||
this.libraryName = libraryName;
|
||||
this.versionProperty = versionProperty;
|
||||
}
|
||||
|
||||
public String getLibraryName() {
|
||||
return this.libraryName;
|
||||
}
|
||||
|
||||
public String getVersionProperty() {
|
||||
return this.versionProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(VersionProperty other) {
|
||||
int groupComparison = this.libraryName.compareToIgnoreCase(other.libraryName);
|
||||
if (groupComparison != 0) {
|
||||
return groupComparison;
|
||||
}
|
||||
return this.versionProperty.compareTo(other.versionProperty);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
$ $JAVA_HOME/bin/java -jar demo-0.0.1-SNAPSHOT.jar
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
:: Spring Boot :: (v{spring-boot-version})
|
||||
|
||||
2022-09-13T18:42:12.818+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Starting DemoApplication using Java 17.0.4 on ...
|
||||
2022-09-13T18:42:12.821+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: No active profile set, falling back to 1 default profile: "default"
|
||||
2022-09-13T18:42:13.606+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Started DemoApplication in 1.145 seconds (process running for 1.578)
|
||||
shell:>help
|
||||
AVAILABLE COMMANDS
|
||||
|
||||
Built-In Commands
|
||||
help: Display help about available commands
|
||||
stacktrace: Display the full stacktrace of the last error.
|
||||
clear: Clear the shell screen.
|
||||
quit, exit: Exit the shell.
|
||||
history: Display or save the history of previously run commands
|
||||
version: Show version info
|
||||
script: Read and execute commands from a file.
|
||||
@@ -0,0 +1,26 @@
|
||||
$JAVA_HOME/bin/java -jar demo-0.0.1-SNAPSHOT.jar help
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
:: Spring Boot :: (v{spring-boot-version})
|
||||
|
||||
2022-09-13T18:42:12.818+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Starting DemoApplication using Java 17.0.4 on ...
|
||||
2022-09-13T18:42:12.821+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: No active profile set, falling back to 1 default profile: "default"
|
||||
2022-09-13T18:42:13.606+01:00 INFO 12644 --- [ main] com.example.demo.DemoApplication
|
||||
: Started DemoApplication in 1.145 seconds (process running for 1.578)
|
||||
AVAILABLE COMMANDS
|
||||
|
||||
Built-In Commands
|
||||
help: Display help about available commands
|
||||
stacktrace: Display the full stacktrace of the last error.
|
||||
clear: Clear the shell screen.
|
||||
quit, exit: Exit the shell.
|
||||
history: Display or save the history of previously run commands
|
||||
version: Show version info
|
||||
script: Read and execute commands from a file.
|
||||
@@ -2,49 +2,95 @@
|
||||
To see what Spring Shell has to offer, we can write a trivial shell application that
|
||||
has a simple command to add two numbers.
|
||||
|
||||
=== Writing a Simple Boot Application
|
||||
IMPORTANT: _Spring Shell_ is based on _Spring Boot_ {spring-boot-version} and
|
||||
_Spring Framework_ {spring-version} and thus requires _JDK 17_.
|
||||
|
||||
Starting with version 2, Spring Shell has been rewritten from the ground up with various
|
||||
enhancements in mind, one of which is easy integration with Spring Boot.
|
||||
=== Writing a Simple Shell Application
|
||||
|
||||
For the purpose of this tutorial, we create a simple Spring Boot application by
|
||||
using https://start.spring.io. This minimal application depends only on `spring-boot-starter`
|
||||
and configures the `spring-boot-maven-plugin` to generate an executable über-jar:
|
||||
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]
|
||||
[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>
|
||||
----
|
||||
====
|
||||
|
||||
[[using-spring-shell-add-dependency]]
|
||||
=== Adding a Dependency on Spring Shell
|
||||
|
||||
The easiest way to get going with Spring Shell is to depend on the `{starter-artifactId}` artifact.
|
||||
This comes with everything you need to use Spring Shell and plays nicely with Boot,
|
||||
configuring only the necessary beans as needed:
|
||||
With _gradle_ you're expected to have something like:
|
||||
|
||||
====
|
||||
[source, xml, subs=attributes+]
|
||||
[source, groovy, subs=attributes+]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.shell</groupId>
|
||||
<artifactId>{spring-shell-starter}</artifactId>
|
||||
<version>{project-version}</version>
|
||||
</dependency>
|
||||
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.
|
||||
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[]
|
||||
----
|
||||
====
|
||||
|
||||
[[using-spring-shell-your-first-command]]
|
||||
=== Your First Command
|
||||
@@ -76,38 +122,24 @@ public class MyCommands {
|
||||
----
|
||||
====
|
||||
|
||||
[[using-spring-shell-try-application]]
|
||||
=== Trying the Application
|
||||
|
||||
To build the application and run the generated jar, run the following command:
|
||||
New _add_ command becomes visible to _help_:
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
[source, text]
|
||||
----
|
||||
./mvnw clean install -DskipTests
|
||||
[...]
|
||||
|
||||
java -jar target/demo-0.0.1-SNAPSHOT.jar
|
||||
My Commands
|
||||
add: Add two integers together.
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
shell:>
|
||||
----
|
||||
====
|
||||
|
||||
A yellow `shell:>` prompt invites you to type commands. Type `add 1 2`, press `ENTER`, and admire the magic:
|
||||
And you can run it:
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
[source, text]
|
||||
----
|
||||
shell:>add --a 1 --b 2
|
||||
3
|
||||
----
|
||||
====
|
||||
|
||||
You should play with the shell (hint: there is a `help` command). When you are done, type `exit` and press `ENTER`.
|
||||
|
||||
The rest of this document delves deeper into the whole Spring Shell programming model.
|
||||
|
||||
@@ -6,7 +6,7 @@ Eric Bottard; Janne Valkealahti; Jay Bryant; Corneil du Plessis
|
||||
:experimental: // For kbd: macro
|
||||
:spring-shell-starter: spring-shell-starter
|
||||
|
||||
*{projectVersion}*
|
||||
*{project-version}*
|
||||
|
||||
(C) 2017 - 2022 VMware, Inc.
|
||||
|
||||
|
||||
@@ -12,12 +12,3 @@ 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.
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
Spring Shell 2.1.x is a major rework to bring the codebase up to date with
|
||||
existing Spring Boot versions, adding new features and, especially,
|
||||
making it work with GraalVM which makes command-line applications much
|
||||
more relevant in a Java space. Moving to a new major version also lets
|
||||
us clean up the codebase and make some needed breaking changes.
|
||||
====
|
||||
|
||||
Reference in New Issue
Block a user