Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
73c243c
Add picocli to project
janhoy Apr 5, 2026
3cbac74
Add sha and license for picocli
janhoy Apr 5, 2026
cb41a69
Add changelog entry for SOLR-17697
janhoy Apr 5, 2026
79feaf5
Enable picocli for start, stop, status, version and zk ls
janhoy Apr 5, 2026
8c23c9f
SOLR-17697 Remove eager ZK connection from CliDefaultValueProvider (#…
janhoy Apr 6, 2026
bae63d4
SOLR-17697 Enable picocli for remaining zk sub commands (#4267)
janhoy Apr 7, 2026
5cd2ab3
SOLR-17697 Remove --version option for all tools except top-level bin…
janhoy Apr 9, 2026
41292ce
SOLR-17697 Implement picocli for create and delete commands (#4269)
janhoy May 14, 2026
f6d6f5f
SOLR-17697 Ref-guide documentation for new picocli commands (#4271)
janhoy May 15, 2026
ecde8f1
Fix precommit
janhoy May 15, 2026
d113b0f
SOLR-17697: visually flag required options (#4433)
epugh May 18, 2026
b064eb6
Spike of supporting longer option description for ref guide and short…
epugh Jun 21, 2026
76cb327
Merge remote-tracking branch 'upstream/main' into jira/SOLR-17697-pic…
janhoy Jul 30, 2026
1b51884
Update lockfiles for jar-checks Copy configurations after merging main
janhoy Jul 30, 2026
b990f9f
Post-merge review fixes: align DeleteTool/CreateTool with main's Conf…
janhoy Jul 30, 2026
6f680d3
SOLR-17697: Bring picocli path to parity with main's --solr-connectio…
janhoy Jul 30, 2026
3784607
Fix Error Prone UnnecessarilyFullyQualified violations failing CI
janhoy Jul 30, 2026
4ec40c9
Fix dropped --credentials in StatusTool.waitToSeeSolrUp
janhoy Jul 30, 2026
4ab0149
Fix CLI docs generation under Gradle 9 and regenerate CLI ref-guide p…
janhoy Jul 30, 2026
91c9460
SOLR-17697: Implement picocli for auth command / AuthTool (#4684)
janhoy Aug 3, 2026
e5cef69
Merge branch 'main' into jira/SOLR-17697-picocli
janhoy Aug 3, 2026
1ae2116
Merge branch 'main' into jira/SOLR-17697-picocli
janhoy Sep 12, 2026
7ad1413
SOLR-17697 Prepare for landing on main branch (#4909)
janhoy Sep 18, 2026
17a5465
SOLR-17697 Fix Error Prone violations in CLI tests
janhoy Sep 19, 2026
50527c6
Merge branch 'main' into jira/SOLR-17697-picocli
janhoy Oct 6, 2026
79e23dc
SOLR-17697 Align delete command docs with the SOLR-18321 behaviour
janhoy Oct 6, 2026
1529ffc
SOLR-17697 Keep create's URL resolution identical to the commons-cli …
janhoy Oct 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/bin-solr-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ jobs:
- name: Test the bin/solr script
run: ./gradlew integrationTests

# Reuses the distribution built above, so this only costs the curated suite run.
- name: Test the bin/solr script with the experimental picocli CLI
run: ./gradlew integrationTestsPicocli

- name: Archive logs
if: ${{ failure() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: logs
path: solr/packaging/build/test-output
path: |
solr/packaging/build/test-output
solr/packaging/build/test-output-picocli
12 changes: 12 additions & 0 deletions changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
title: >
An experimental re-implementation of the `bin/solr` command line interface, built on picocli,
is now included. It is disabled by default and is enabled with `SOLR_PICOCLI=true`. Only some
commands have been migrated so far, and its options may change between releases. See the
"Experimental picocli Command Line Interface" page in the Reference Guide.
type: added
authors:
- name: Jan Høydahl
url: https://home.apache.org/phonebook.html?uid=janhoy
links:
- name: SOLR-17697
url: https://issues.apache.org/jira/browse/SOLR-17697
53 changes: 53 additions & 0 deletions dev-docs/ref-guide/antora.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,59 @@ Instead, update `antora.template.yaml`, and `gradlew buildLocalSite` will build

The only reason you will likely need to change the `antora.template.yml` is if you are introducing new variables for dependency versions.

== Auto-generated CLI Reference Pages

The `bin/solr` command-line tool documentation is partially auto-generated from the picocli `@Command`, `@Option`, and `@Parameters` annotations in the Java source.

=== How it works

For each command registered in `org.apache.solr.cli.SolrCLI` that uses picocli annotations, a dedicated AsciiDoc page is generated by `picocli.codegen.docgen.manpage.ManPageGenerator` and committed to:

----
solr/solr-ref-guide/modules/deployment-guide/pages/cli/
----

The generated pages are post-processed to be Antora-compatible (correct page title, `:page-toclevels:` attribute, ASF license header, DO NOT EDIT notice, and the experimental warning).

Two things about that post-processing are worth knowing before changing it:

* Whether an option is required is worked out by re-parsing the synopsis that picocli generated, because `ManPageGenerator` emits no per-option marker (https://github.com/remkop/picocli/issues/2519[picocli#2519]).
A change to picocli's synopsis layout will therefore change the markers; the build fails loudly rather than silently publishing pages without them.
* `runManPageGenerator` resolves `project.objects` and the `cliClasspath` configuration at execution time, which is not compatible with Gradle's configuration cache should it ever be enabled for this build.
The navigation section in `deployment-nav.adoc` between the `// CLI-DOCS-START` and `// CLI-DOCS-END` markers is also updated automatically.

The main landing page `solr-control-script-reference.adoc` provides an overview of the available tools with links to each man-page.

=== Gradle targets

`./gradlew :solr:solr-ref-guide:generateCliDocs`::
Regenerates all pages under `pages/cli/` from the current picocli annotations and updates the nav.
Run this after modifying any `@Command`, `@Option`, or `@Parameters` annotation in `solr/core/src/java/org/apache/solr/cli/`.

`./gradlew :solr:solr-ref-guide:checkCliDocsUpToDate`::
Verifies that the committed pages in `pages/cli/` are in sync with the current annotations.
It is wired into `gradlew check` alongside the other ref-guide checks, so it is skipped when the ref guide is excluded with `-Prefguide.include=false`.
Note that upgrading picocli can change the generated wording without any annotation having been touched; if the check fails after a version bump, re-run `generateCliDocs` and commit the result.

=== Adding docs for a new tool

The new command will automatically appear in the generated pages, in the navigation and in the command table on `pages/cli/index.adoc` when running `gradlew generateCliDocs`.

`pages/cli/index.adoc` is the only hand-written page in that directory; everything matching `solr-*.adoc` is generated and must not be edited by hand.
`solr-control-script-reference.adoc` documents the default (commons-cli) implementation and should not gain per-command links to the generated pages while the picocli implementation is experimental.

=== What a tool migration should include

When migrating a tool to picocli:

* A `*PicocliTest` subclass of the tool's existing test that overrides only the invocation strategy, so every case runs on both implementations. See `ZkSubcommandsPicocliTest` for the pattern.
* The tool's `.bats` file added to `integrationTestsPicocli` in `solr/packaging/build.gradle`, but only once *every* command that suite invokes has been migrated, not just the one under test.
`test_auth.bats`, for example, uses `solr assert` to wait for startup, so it cannot be added until the assert command is migrated.
Be aware that a failure part-way through that suite is especially awkward: `solr auth enable` appends `SOLR_AUTH_TYPE` and `SOLR_AUTHENTICATION_OPTS` to the `solr.in.sh` of the *built distribution* under `solr/packaging/build/`, so an aborted run leaves every later `bin/solr` invocation trying to authenticate.
If BATS runs start hanging for no apparent reason, check that file, and delete the distribution directory to force `installFullDist` to recreate it.
* A `gradlew :solr:solr-ref-guide:generateCliDocs` run, with the result committed.
* The tool registered in `SolrCLI`'s `subcommands` only once `callTool()` actually works; `SolrCLIPicocliTest` enforces the rules that apply to every registered command.

== Building the HTML Site

A Gradle target `gradlew buildLocalSite` will build the full HTML site (found in `solr/solr-ref-guide/build/site`).
Expand Down
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ ow2-asm = "9.10.1"
owasp-dependencycheck = "13.0.0"
# @keep for version alignment
perfmark = "0.27.0"
picocli = "4.7.6"
prometheus-metrics = "1.8.0"
quicktheories = "0.26"
selenium = "4.47.0"
Expand Down Expand Up @@ -442,6 +443,8 @@ ow2-asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "ow2-asm"
ow2-asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "ow2-asm" }
# @keep transitive dependency for version alignment
perfmark-api = { module = "io.perfmark:perfmark-api", version.ref = "perfmark" }
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
picocli-codegen = { module = "info.picocli:picocli-codegen", version.ref = "picocli" }
prometheus-metrics-expositionformats = { module = "io.prometheus:prometheus-metrics-exposition-formats", version.ref = "prometheus-metrics" }
prometheus-metrics-model = { module = "io.prometheus:prometheus-metrics-model", version.ref = "prometheus-metrics" }
quicktheories-quicktheories = { module = "org.quicktheories:quicktheories", version.ref = "quicktheories" }
Expand Down
1 change: 1 addition & 0 deletions solr/api/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ com.tdunning:t-digest:3.3=jarValidation,testRuntimeClasspath
commons-cli:commons-cli:1.11.0=jarValidation,testRuntimeClasspath
commons-codec:commons-codec:1.22.1=jarValidation,testRuntimeClasspath
commons-io:commons-io:2.22.0=jarValidation,testCompileClasspath,testRuntimeClasspath
info.picocli:picocli:4.7.6=jarValidation,testRuntimeClasspath
io.dropwizard.metrics:metrics-core:4.2.39=jarValidation,testRuntimeClasspath
io.github.classgraph:classgraph:4.8.192=swaggerBuild
io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor
Expand Down
1 change: 1 addition & 0 deletions solr/benchmark/gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ com.tdunning:t-digest:3.3=jarValidation,runtimeClasspath,testRuntimeClasspath
commons-cli:commons-cli:1.11.0=jarValidation,runtimeClasspath,testRuntimeClasspath
commons-codec:commons-codec:1.22.1=jarValidation,runtimeClasspath,testRuntimeClasspath
commons-io:commons-io:2.22.0=compileClasspath,jarValidation,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
info.picocli:picocli:4.7.6=jarValidation,runtimeClasspath,testRuntimeClasspath
io.dropwizard.metrics:metrics-core:4.2.39=jarValidation,runtimeClasspath,testRuntimeClasspath
io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor
Expand Down
6 changes: 5 additions & 1 deletion solr/bin/solr
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,11 @@ if [ $# -gt 0 ]; then
shift 2
;;
-h|--help)
print_usage "$SCRIPT_CMD"
if [[ "${SOLR_PICOCLI:-}" == "true" ]]; then
run_tool "$SCRIPT_CMD" --help
else
print_usage "$SCRIPT_CMD"
fi
exit 0
;;
-y|--no-prompt)
Expand Down
18 changes: 16 additions & 2 deletions solr/bin/solr.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,22 @@ IF "%1"=="--all" goto set_stop_all
:parse_general_args

REM Print usage of command in case help option included
IF "%1"=="--help" goto usage
IF "%1"=="-h" goto usage
IF "%1"=="--help" goto check_picocli_help
IF "%1"=="-h" goto check_picocli_help
goto after_help_check

:check_picocli_help
IF "%SOLR_PICOCLI%"=="true" goto run_picocli_help
goto usage

:run_picocli_help
"%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^
-Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
-classpath "%SOLR_TIP%\lib\*;%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
org.apache.solr.cli.SolrCLI %SCRIPT_CMD% --help
goto done

:after_help_check

REM other args supported by all special commands
IF "%1"=="-p" goto set_port
Expand Down
21 changes: 21 additions & 0 deletions solr/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ dependencies {
implementation libs.commonscodec.commonscodec

implementation libs.commonscli.commonscli
implementation libs.picocli

implementation libs.locationtech.spatial4j

Expand Down Expand Up @@ -200,3 +201,23 @@ dependencies {

testImplementation libs.opentelemetry.sdk.testing
}

// Expose a configuration for CLI doc generation in the solr-ref-guide project.
// This bundles the full runtime classpath plus picocli-codegen (ManPageGenerator)
// and the compiled CLI classes so that generateCliDocs can invoke ManPageGenerator.
configurations {
cliDocsRuntime {
canBeResolved = true
canBeConsumed = true
// Inherit all runtime dependencies (implementation + runtimeOnly transitively)
extendsFrom configurations.runtimeClasspath
}
}

dependencies {
// picocli-codegen provides ManPageGenerator (not in runtime, only needed for doc gen)
cliDocsRuntime libs.picocli.codegen
// Include the compiled CLI classes themselves
cliDocsRuntime files(sourceSets.main.output.classesDirs)
cliDocsRuntime files(sourceSets.main.output.resourcesDir)
}
Loading
Loading