Skip to content

Commit

Permalink
#410 productionize ReflectionConfigGenerator
Browse files Browse the repository at this point in the history
* add documentation to codegen README for generating config during the build
* add --output option to specify a destination file
* add test
* modify exclusions system.property name to `picocli.codegen.excludes` (was `picocli.converters.excludes`)
* update release notes
  • Loading branch information
remkop committed Oct 19, 2018
1 parent 1ae020a commit d7a1601
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 48 deletions.
32 changes: 31 additions & 1 deletion RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@
# <a name="3.7.0"></a> Picocli 3.7.0 (UNRELEASED)
The picocli community is pleased to announce picocli 3.7.0.

This release contains bugfixes and enhancements.
This release contains bugfixes and enhancements in the main picocli module, and adds two new modules:
`picocli-codegen` and `picocli-shell-jline2`.

Picocli Code Generation contains tools for generating source code, documentation and configuration files
for picocli-based applications.

Picocli Shell JLine2 contains components and documentation for building
interactive shell command line applications with JLine 2 and picocli.

Many thanks to the many members of the picocli community who contributed!

Expand All @@ -20,6 +26,30 @@ Picocli follows [semantic versioning](http://semver.org/).

## <a name="3.7.0-new"></a> New and Noteworthy

### <a name="3.7.0-picocli-codegen"></a> New Module `picocli-codegen`
Picocli Code Generation contains tools for generating source code, documentation and configuration files
for picocli-based applications.

This release contains the `ReflectionConfigGenerator` class.
`ReflectionConfigGenerator` generates a JSON String with the program elements that will be accessed reflectively in a picocli-based application, in order to compile this application ahead-of-time into a native executable with GraalVM.

The output of `ReflectionConfigGenerator` is intended to be passed to the `-H:ReflectionConfigurationFiles=/path/to/reflectconfig` option of the `native-image` GraalVM utility. This allows picocli-based applications to be compiled to a native image.

See [Picocli on GraalVM: Blazingly Fast Command Line Apps](https://github.com/remkop/picocli/wiki/Picocli-on-GraalVM:-Blazingly-Fast-Command-Line-Apps) for details.

The module's [README](https://github.com/remkop/picocli/blob/master/picocli-codegen/README.md) explains how to configure your build to generate the configuration file automatically as part of your build.


### <a name="3.7.0-picocli-shell-jline2"></a> New Module `picocli-shell-jline2`
Picocli Shell JLine2 contains components and documentation for building
interactive shell command line applications with JLine 2 and picocli.

This release contains the `PicocliJLineCompleter` class.
`PicocliJLineCompleter` is a small component that generates completion candidates to allow users to
get command line TAB auto-completion for a picocli-based application running in a JLine 2 shell.

See the module's [README](https://github.com/remkop/picocli/blob/master/picocli-shell-jline2/README.md) for more details.

## <a name="3.7.0-fixes"></a> Fixed issues
- [#503] Build: Upgrade to gradle 4.10.2.
- [#497] add module `picocli-shell-jline2` for components and documentation for building interactive shell command line applications with JLine 2 and picocli.
Expand Down
17 changes: 9 additions & 8 deletions docs/picocli-on-graalvm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
:source-highlighter: highlightjs
:highlightjs-theme: darkula

image::https://picocli.info/images/picocli-on-graalvm.png[]

== GraalVM

image::https://www.graalvm.org/resources/img/logo-colored.svg[]

https://www.graalvm.org/[GraalVM] allows you to compile your programs ahead-of-time into a native executable. The resulting program has faster startup time and lower runtime memory overhead compared to a Java VM. This is especially useful for command line utilities, which are often short-lived.

Expand All @@ -18,7 +19,7 @@ https://picocli.info/#option-parameters-methods[methods] or
https://picocli.info/#command-methods[method parameters] annotated with `@Option` and `@Parameters` and other picocli annotations. A future picocli release may include an annotation processor to do this work at compile time, but as it stands, it uses reflection.

== ReflectionConfigGenerator Tool
Picocli 3.7 includes a https://github.com/remkop/picocli/tree/master/picocli-codegen[`picocli-codegen` module], with a tool that generates a GraalVM configuration file.
Picocli 3.7.0 includes a https://github.com/remkop/picocli/tree/master/picocli-codegen[`picocli-codegen` module], with a tool that generates a GraalVM configuration file.

`ReflectionConfigGenerator` generates a JSON String with the program elements that will be accessed reflectively in a picocli-based application, in order to compile this application ahead-of-time into a native executable with GraalVM.

Expand All @@ -33,7 +34,7 @@ Run the `ReflectionConfigGenerator` tool and specify one or more fully qualified
[source,bash]
----
java -cp \
picocli-3.7.0-SNAPSHOT.jar:picocli-codegen-3.7.0-SNAPSHOT-tests.jar:picocli-codegen-3.7.0-SNAPSHOT.jar \
picocli-3.7.0.jar:picocli-codegen-3.7.0-tests.jar:picocli-codegen-3.7.0.jar \
picocli.codegen.aot.graalvm.ReflectionConfigGenerator picocli.codegen.aot.graalvm.Example > reflect.json
----

Expand Down Expand Up @@ -65,7 +66,7 @@ The generated `reflect.json` files looks something like this:
----


TIP: If necessary, it is possible to exclude classes with system property `picocli.converters.excludes`, which accepts a comma-separated list of regular expressions of the fully qualified class names that should not be included in the resulting JSON String.
TIP: If necessary, it is possible to exclude classes with system property `picocli.codegen.excludes`, which accepts a comma-separated list of regular expressions of the fully qualified class names that should not be included in the resulting JSON String.

=== Compiling a Native Image
This assumes you have GraalVM installed, with prerequisites. From https://www.graalvm.org/docs/reference-manual/aot-compilation/[the site]:
Expand All @@ -82,7 +83,7 @@ We compile the example class with the following command:
[source,bash]
----
graalvm-ce-1.0.0-rc6/bin/native-image \
-cp picocli-3.7.0-SNAPSHOT.jar:picocli-codegen-3.7.0-SNAPSHOT-tests.jar \
-cp picocli-3.7.0.jar:picocli-codegen-3.7.0-tests.jar \
-H:ReflectionConfigurationFiles=reflect.json -H:+ReportUnsupportedElementsAtRuntime \
--static --no-server picocli.codegen.aot.graalvm.Example
----
Expand All @@ -106,9 +107,9 @@ Let's first run the application in Java, and time it to see how long it takes to

[source]
----
$ time java -cp picocli-3.7.0-SNAPSHOT.jar:picocli-codegen-3.7.0-SNAPSHOT-tests.jar \
$ time java -cp picocli-3.7.0.jar:picocli-codegen-3.7.0-tests.jar \
picocli.codegen.aot.graalvm.Example --version
3.7.0-SNAPSHOT
3.7.0
real 0m0.492s
user 0m0.847s
Expand All @@ -120,7 +121,7 @@ On Java Hotspot, it takes about half a second to run. Now, we run the native ima
[source]
----
$ time ./picocli.codegen.aot.graalvm.example --version
3.7.0-SNAPSHOT
3.7.0
real 0m0.003s
user 0m0.000s
Expand Down
26 changes: 15 additions & 11 deletions docs/picocli-on-graalvm.html
Original file line number Diff line number Diff line change
Expand Up @@ -422,14 +422,18 @@
<h1>Picocli on GraalVM: Blazingly Fast Command Line Apps</h1>
</div>
<div id="content">
<div class="sect1">
<h2 id="_graalvm">GraalVM</h2>
<div id="preamble">
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="https://www.graalvm.org/resources/img/logo-colored.svg" alt="logo colored">
<img src="https://picocli.info/images/picocli-on-graalvm.png" alt="picocli on graalvm">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_graalvm">GraalVM</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://www.graalvm.org/">GraalVM</a> allows you to compile your programs ahead-of-time into a native executable. The resulting program has faster startup time and lower runtime memory overhead compared to a Java VM. This is especially useful for command line utilities, which are often short-lived.</p>
</div>
Expand All @@ -454,7 +458,7 @@ <h2 id="_reflective_access">Reflective Access</h2>
<h2 id="_reflectionconfiggenerator_tool">ReflectionConfigGenerator Tool</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Picocli 3.7 includes a <a href="https://github.com/remkop/picocli/tree/master/picocli-codegen"><code>picocli-codegen</code> module</a>, with a tool that generates a GraalVM configuration file.</p>
<p>Picocli 3.7.0 includes a <a href="https://github.com/remkop/picocli/tree/master/picocli-codegen"><code>picocli-codegen</code> module</a>, with a tool that generates a GraalVM configuration file.</p>
</div>
<div class="paragraph">
<p><code>ReflectionConfigGenerator</code> generates a JSON String with the program elements that will be accessed reflectively in a picocli-based application, in order to compile this application ahead-of-time into a native executable with GraalVM.</p>
Expand All @@ -476,7 +480,7 @@ <h3 id="_generating_the_configuration_file">Generating the Configuration File</h
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash" data-lang="bash">java -cp \
picocli-3.7.0-SNAPSHOT.jar:picocli-codegen-3.7.0-SNAPSHOT-tests.jar:picocli-codegen-3.7.0-SNAPSHOT.jar \
picocli-3.7.0.jar:picocli-codegen-3.7.0-tests.jar:picocli-codegen-3.7.0.jar \
picocli.codegen.aot.graalvm.ReflectionConfigGenerator picocli.codegen.aot.graalvm.Example &gt; reflect.json</code></pre>
</div>
</div>
Expand Down Expand Up @@ -515,7 +519,7 @@ <h3 id="_generating_the_configuration_file">Generating the Configuration File</h
<div class="title">Tip</div>
</td>
<td class="content">
If necessary, it is possible to exclude classes with system property <code>picocli.converters.excludes</code>, which accepts a comma-separated list of regular expressions of the fully qualified class names that should not be included in the resulting JSON String.
If necessary, it is possible to exclude classes with system property <code>picocli.codegen.excludes</code>, which accepts a comma-separated list of regular expressions of the fully qualified class names that should not be included in the resulting JSON String.
</td>
</tr>
</table>
Expand All @@ -542,7 +546,7 @@ <h3 id="_compiling_a_native_image">Compiling a Native Image</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash" data-lang="bash">graalvm-ce-1.0.0-rc6/bin/native-image \
-cp picocli-3.7.0-SNAPSHOT.jar:picocli-codegen-3.7.0-SNAPSHOT-tests.jar \
-cp picocli-3.7.0.jar:picocli-codegen-3.7.0-tests.jar \
-H:ReflectionConfigurationFiles=reflect.json -H:+ReportUnsupportedElementsAtRuntime \
--static --no-server picocli.codegen.aot.graalvm.Example</code></pre>
</div>
Expand Down Expand Up @@ -582,9 +586,9 @@ <h3 id="_running_the_native_image">Running the Native Image</h3>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code>$ time java -cp picocli-3.7.0-SNAPSHOT.jar:picocli-codegen-3.7.0-SNAPSHOT-tests.jar \
<pre class="highlightjs highlight"><code>$ time java -cp picocli-3.7.0.jar:picocli-codegen-3.7.0-tests.jar \
picocli.codegen.aot.graalvm.Example --version
3.7.0-SNAPSHOT
3.7.0

real 0m0.492s
user 0m0.847s
Expand All @@ -597,7 +601,7 @@ <h3 id="_running_the_native_image">Running the Native Image</h3>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code>$ time ./picocli.codegen.aot.graalvm.example --version
3.7.0-SNAPSHOT
3.7.0

real 0m0.003s
user 0m0.000s
Expand Down Expand Up @@ -630,7 +634,7 @@ <h2 id="_conclusion">Conclusion</h2>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2018-10-05 07:46:13 +09:00
Last updated 2018-10-19 21:57:06 +09:00
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/darkula.min.css">
Expand Down
85 changes: 85 additions & 0 deletions picocli-codegen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,88 @@ for picocli-based applications.
The output of `ReflectionConfigGenerator` is intended to be passed to the `-H:ReflectionConfigurationFiles=/path/to/reflectconfig` option of the `native-image` GraalVM utility. This allows picocli-based applications to be compiled to a native image.

See [Picocli on GraalVM: Blazingly Fast Command Line Apps](https://github.com/remkop/picocli/wiki/Picocli-on-GraalVM:-Blazingly-Fast-Command-Line-Apps) for details.

### Generating GraalVM Reflection Configuration During the Build

Below shows some examples of configuring your build to generate a GraalVM reflection configuration file with the `ReflectionConfigGenerator` tool during the build.

Note that the `--output` option allows you to specify the path to the file to write the configuration to.
When this option is omitted, the output is sent to standard out.

The `ReflectionConfigGenerator` tool accepts any number of fully qualified class names of command classes
(classes with picocli annotations like `@Command`, `@Option` and `@Parameters`).
The resulting configuration file will contain entries for the reflected elements of all specified classes.

#### Maven

For Maven, add an `exec:java` goal to generate a Graal reflection configuration file with the `ReflectionConfigGenerator` tool.
This example uses the `process-classes` phase of the build, there are [alternatives](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html).

Note that the `picocli-codegen` module is only added as a dependency for the `exec` plugin, so it does not need to be added to the project dependencies.

```xml
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>generateGraalReflectionConfig</id>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<includeProjectDependencies>true</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
<mainClass>picocli.codegen.aot.graalvm.ReflectionConfigGenerator</mainClass>
<arguments>
<argument>--output=target/cli-reflect.json</argument>
<argument>com.your.package.YourCommand1</argument>
<argument>com.your.package.YourCommand2</argument>
</arguments>
</configuration>
<dependencies>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli-codegen</artifactId>
<version>3.7.0</version>
<type>jar</type>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
```

#### Gradle

For Gradle, add a custom configuration for the `picocli-codegen` module to your `gradle.build`.
This allows us to add this module to the classpath of our custom task without adding it as a dependency to the "standard" build.

```gradle
configurations {
generateConfig
}
dependencies {
compile 'info.picocli:picocli:3.7.0'
generateConfig 'info.picocli:picocli-codegen:3.7.0'
}
```

Then, add a custom task to run the `ReflectionConfigGenerator` tool.
This example generates the file during the `assemble` lifecycle task, there are [alternatives](https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_tasks).

```gradle
task(generateGraalReflectionConfig, dependsOn: 'classes', type: JavaExec) {
main = 'picocli.codegen.aot.graalvm.ReflectionConfigGenerator'
classpath = configurations.generateConfig + sourceSets.main.runtimeClasspath
def outputFile = new File(project.buildDir, 'cli-reflect.json')
args = ["--output=$outputFile", 'com.your.package.YourCommand1', 'com.your.package.YourCommand2']
}
assemble.dependsOn generateGraalReflectionConfig
```
Loading

0 comments on commit d7a1601

Please sign in to comment.