From de772eb858e0a5c6470d4b8373059ba3bce0f855 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 00:38:27 +0530 Subject: [PATCH 01/17] moved changes to new branch of new jira --- .../unreleased/SOLR-17697-packagetool.yml | 9 + .../src/java/org/apache/solr/cli/AddKey.java | 56 ++++ .../src/java/org/apache/solr/cli/AddRepo.java | 62 ++++ .../apache/solr/cli/ConnectionOptions.java | 77 +++++ .../src/java/org/apache/solr/cli/Deploy.java | 100 ++++++ .../src/java/org/apache/solr/cli/Install.java | 60 ++++ .../org/apache/solr/cli/ListAvailable.java | 47 +++ .../org/apache/solr/cli/ListDeployed.java | 77 +++++ .../org/apache/solr/cli/ListInstalled.java | 47 +++ .../apache/solr/cli/PackageSubCommand.java | 63 ++++ .../java/org/apache/solr/cli/PackageTool.java | 285 +++++++++++++----- .../src/java/org/apache/solr/cli/SolrCLI.java | 3 +- .../java/org/apache/solr/cli/Undeploy.java | 74 +++++ .../java/org/apache/solr/cli/Uninstall.java | 55 ++++ .../solr/cli/PackageToolPicocliTest.java | 32 ++ .../org/apache/solr/cli/PackageToolTest.java | 79 ++--- 16 files changed, 998 insertions(+), 128 deletions(-) create mode 100644 changelog/unreleased/SOLR-17697-packagetool.yml create mode 100644 solr/core/src/java/org/apache/solr/cli/AddKey.java create mode 100644 solr/core/src/java/org/apache/solr/cli/AddRepo.java create mode 100644 solr/core/src/java/org/apache/solr/cli/Deploy.java create mode 100644 solr/core/src/java/org/apache/solr/cli/Install.java create mode 100644 solr/core/src/java/org/apache/solr/cli/ListAvailable.java create mode 100644 solr/core/src/java/org/apache/solr/cli/ListDeployed.java create mode 100644 solr/core/src/java/org/apache/solr/cli/ListInstalled.java create mode 100644 solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java create mode 100644 solr/core/src/java/org/apache/solr/cli/Undeploy.java create mode 100644 solr/core/src/java/org/apache/solr/cli/Uninstall.java create mode 100644 solr/core/src/test/org/apache/solr/cli/PackageToolPicocliTest.java diff --git a/changelog/unreleased/SOLR-17697-packagetool.yml b/changelog/unreleased/SOLR-17697-packagetool.yml new file mode 100644 index 000000000000..ac5d963a050e --- /dev/null +++ b/changelog/unreleased/SOLR-17697-packagetool.yml @@ -0,0 +1,9 @@ +title: + Implement picocli for package command / PackageTool +type: changed +authors: + - name: Jalaz Kumar + nick: jaykay12 +links: + - name: SOLR-17697 + url: https://issues.apache.org/jira/browse/SOLR-17697 diff --git a/solr/core/src/java/org/apache/solr/cli/AddKey.java b/solr/core/src/java/org/apache/solr/cli/AddKey.java new file mode 100644 index 000000000000..9cdd6414b10d --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/AddKey.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +import java.nio.file.Path; + +/** Supports package add-key command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "add-key", + description = "Add a trusted key to Solr.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # Add a trusted public key", + " bin/solr package add-key /path/to/public.key.der", + }) +public class AddKey extends PackageSubCommand { + + @picocli.CommandLine.Parameters( + index = "0", + arity = "1", + paramLabel = "KEY-FILE", + description = "Path to a file containing the trusted key.") + private Path keyFile; + + @Override + public int callTool() throws Exception { + return runWithManagers( + ((packageManager, repositoryManager) -> packageTool.addKey(repositoryManager, keyFile))); + } + + @Override + public String getName() { + return "add-key"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/AddRepo.java b/solr/core/src/java/org/apache/solr/cli/AddRepo.java new file mode 100644 index 000000000000..e9c24d724293 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/AddRepo.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +/** Supports package add-repo command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "add-repo", + description = "Add a package repository to Solr.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # Add a package repository", + " bin/solr package add-repo myrepo https://my.repo.example/repo", + }) +public class AddRepo extends PackageSubCommand { + + @picocli.CommandLine.Parameters( + index = "0", + arity = "1", + paramLabel = "REPOSITORY-NAME", + description = "Name of the package repository.") + private String repoName; + + @picocli.CommandLine.Parameters( + index = "1", + arity = "1", + paramLabel = "REPOSITORY-URL", + description = "URL of the package repository.") + private String repoUrl; + + @Override + public int callTool() throws Exception { + return runWithManagers( + ((packageManager, repositoryManager) -> + packageTool.addRepo(repositoryManager, repoName, repoUrl))); + } + + @Override + public String getName() { + return "add-repo"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java b/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java index 0a782b5a60fb..b17518a3e647 100644 --- a/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java +++ b/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java @@ -17,7 +17,10 @@ package org.apache.solr.cli; import java.io.IOException; +import java.util.Map; +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; +import org.apache.solr.common.util.EnvUtils; import picocli.CommandLine; /** @@ -73,4 +76,78 @@ String effectiveSolrUrl() throws IOException { } return solrUrl; } + + static String resolveSolrUrl(ConnectionOptions connectionOptions, String credentials) + throws Exception { + if (connectionOptions != null) { + String solrUrl = connectionOptions.effectiveSolrUrl(); + if (solrUrl != null) { + return CLIUtils.normalizeSolrUrl(solrUrl); + } + String zkHost = connectionOptions.effectiveZkHost(); + if (zkHost != null) { + return CLIUtils.solrUrlFromConnection( + CloudSolrClient.CloudSolrClientConnection.parse(zkHost), credentials); + } + } + + String solrConnectionProp = EnvUtils.getProperty("solr-connection"); + if (solrConnectionProp != null && !solrConnectionProp.isBlank()) { + var connection = CloudSolrClient.CloudSolrClientConnection.parse(solrConnectionProp); + if (connection.isZookeeper()) { + return CLIUtils.solrUrlFromConnection(connection, credentials); + } + return CLIUtils.normalizeSolrUrl(connection.quorumItems().get(0)); + } + + String zkHostProp = EnvUtils.getProperty("zkHost"); + if (zkHostProp != null && !zkHostProp.isBlank()) { + return CLIUtils.solrUrlFromConnection( + CloudSolrClient.CloudSolrClientConnection.parse(zkHostProp), credentials); + } + + String defaultUrl = CLIUtils.getDefaultSolrUrl(); + CLIO.err( + "Neither --solr-connection, --zk-host or --solr-url parameters, nor SOLR_CONNECTION, ZK_HOST env var provided, so assuming solr url is " + + defaultUrl + + "."); + return defaultUrl; + } + + static String resolveZkHost( + ConnectionOptions connectionOptions, String solrUrl, String credentials) throws Exception { + if (connectionOptions != null) { + String zkHost = connectionOptions.effectiveZkHost(); + if (zkHost != null) { + return zkHost; + } + } + + String solrConnectionProp = EnvUtils.getProperty("solr-connection"); + if (solrConnectionProp != null && !solrConnectionProp.isBlank()) { + var connection = CloudSolrClient.CloudSolrClientConnection.parse(solrConnectionProp); + if (connection.isZookeeper()) { + return solrConnectionProp; + } + } + + String zkHostProp = EnvUtils.getProperty("zkHost"); + if (zkHostProp != null && !zkHostProp.isBlank()) { + return zkHostProp; + } + + try (SolrClient solrClient = CLIUtils.getSolrClient(solrUrl, credentials)) { + Map status = StatusTool.reportStatus(solrClient); + @SuppressWarnings("unchecked") + Map cloud = (Map) status.get("cloud"); + if (cloud != null) { + String zookeeper = cloud.get("ZooKeeper").toString(); + if (zookeeper != null && zookeeper.endsWith("(embedded)")) { + zookeeper = zookeeper.substring(0, zookeeper.length() - "(embedded)".length()); + } + return zookeeper; + } + } + return null; + } } diff --git a/solr/core/src/java/org/apache/solr/cli/Deploy.java b/solr/core/src/java/org/apache/solr/cli/Deploy.java new file mode 100644 index 000000000000..4e27c9809e8c --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/Deploy.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +import static org.apache.solr.cli.SolrCLI.printRed; + +/** Supports package deploy command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "deploy", + description = "Deploy an installed package to collections or at cluster level.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # Deploy a package to a collection", + " bin/solr package deploy mypkg:1.0.0 --collections myCollection -y", + "", + " # Update an existing deployment", + " bin/solr package deploy mypkg --update --collections myCollection -y" + }) +public class Deploy extends PackageSubCommand { + + @picocli.CommandLine.Parameters( + index = "0", + arity = "1", + paramLabel = "PACKAGE[:VERSION]", + description = "Package name, optionally with :version.") + private String packageNameAndVersion; + + @picocli.CommandLine.Option( + names = {"--cluster"}, + description = "Specifies that this action should affect cluster-level plugins only.") + private boolean cluster; + + @picocli.CommandLine.Option( + names = {"--collections"}, + paramLabel = "COLLECTIONS", + description = + "Specifies that this action should affect plugins for the given collections only, excluding cluster level plugins.") + private String collections; + + @picocli.CommandLine.Option( + names = {"-p", "--param"}, + paramLabel = "PARAMS", + description = "List of parameters to be used with deploy command.") + private String[] params; + + @picocli.CommandLine.Option( + names = {"--update"}, + description = "If a deployment is an update over a previous deployment.") + private boolean update; + + @picocli.CommandLine.Option( + names = {"-y", "--no-prompt"}, + description = "Don't prompt for input; accept all default choices, defaults to false.") + private boolean noPrompt; + + @Override + public int callTool() throws Exception { + if (!cluster && collections == null) { + printRed( + "Either specify --cluster to deploy cluster level plugins or --collections to deploy collection level plugins"); + return 1; + } + return runWithManagers( + (packageManager, repositoryManager) -> + packageTool.deploy( + packageManager, + packageNameAndVersion, + cluster, + collections, + params, + update, + noPrompt)); + } + + @Override + public String getName() { + return "deploy"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/Install.java b/solr/core/src/java/org/apache/solr/cli/Install.java new file mode 100644 index 000000000000..1e38f7d67cd4 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/Install.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +/** Supports package install command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "install", + description = "Install a package into Solr.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # Install a specific package version", + " bin/solr package install mypkg:1.0.0", + "", + " # Install the latest available version", + " bin/solr package install mypkg" + }) +public class Install extends PackageSubCommand { + + @picocli.CommandLine.Parameters( + index = "0", + arity = "1", + paramLabel = "PACKAGE[:VERSION]", + description = "Package name, optionally with :version.") + private String packageNameAndVersion; + + @Override + public int callTool() throws Exception { + final boolean[] status = {true}; + runWithManagers( + (packageManager, repositoryManager) -> + status[0] = packageTool.install(repositoryManager, packageNameAndVersion)); + return status[0] ? 0 : 1; + } + + @Override + public String getName() { + return "install"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/ListAvailable.java b/solr/core/src/java/org/apache/solr/cli/ListAvailable.java new file mode 100644 index 000000000000..c5f2fe7a124b --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/ListAvailable.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +/** Supports package list-available command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "list-available", + description = "Print a list of packages available in the repositories.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # List packages available from configured repositories", + " bin/solr package list-available", + }) +public class ListAvailable extends PackageSubCommand { + + @Override + public int callTool() throws Exception { + return runWithManagers( + (packageManager, repositoryManager) -> packageTool.listAvailable(repositoryManager)); + } + + @Override + public String getName() { + return "list-available"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/ListDeployed.java b/solr/core/src/java/org/apache/solr/cli/ListDeployed.java new file mode 100644 index 000000000000..1303502e70c0 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/ListDeployed.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +import static org.apache.solr.cli.SolrCLI.printRed; + +/** Supports package list-deployed command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "list-deployed", + description = + "Print packages deployed on a collection, or collections where a package is deployed.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # List packages deployed on a collection", + " bin/solr package list-deployed -c myCollection", + "", + " # List collections where a package is deployed", + " bin/solr package list-deployed mypkg" + }) +public class ListDeployed extends PackageSubCommand { + + @picocli.CommandLine.Option( + names = {"-c", "--collection"}, + paramLabel = "COLLECTION", + description = "The collection to apply the package to, not required.") + private String collection; + + @picocli.CommandLine.Parameters( + index = "0", + arity = "0..1", + paramLabel = "PACKAGE", + description = "Package name; lists collections where this package is deployed.") + private String packageName; + + @Override + public int callTool() throws Exception { + if (collection == null && packageName == null) { + printRed("Either -c/--collection or a package name is required."); + return 1; + } + + return runWithManagers( + (packageManager, repositoryManager) -> { + if (collection != null) { + packageTool.listPackagesDeployedOnCollection(packageManager, collection); + } else { + packageTool.listCollectionsWithPackageDeployed(packageManager, packageName); + } + }); + } + + @Override + public String getName() { + return "list-deployed"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/ListInstalled.java b/solr/core/src/java/org/apache/solr/cli/ListInstalled.java new file mode 100644 index 000000000000..ec936a0331d3 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/ListInstalled.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +/** Supports package list-installed command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "list-installed", + description = "Print a list of packages installed in Solr.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # List all installed packages", + " bin/solr package list-installed", + }) +public class ListInstalled extends PackageSubCommand { + + @Override + public int callTool() throws Exception { + return runWithManagers( + (packageManager, repositoryManager) -> packageTool.listInstalled(packageManager)); + } + + @Override + public String getName() { + return "list-installed"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java new file mode 100644 index 000000000000..2a1ae5de3746 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +import org.apache.commons.cli.CommandLine; +import org.apache.solr.packagemanager.PackageManager; +import org.apache.solr.packagemanager.RepositoryManager; + +/** Shared picocli wiring for {@code bin/solr package leaves} */ +abstract class PackageSubCommand extends ToolBase { + + @FunctionalInterface + interface PackageAction { + void run(PackageManager packageManager, RepositoryManager repositoryManager) throws Exception; + } + + @picocli.CommandLine.ParentCommand PackageTool packageTool; + + @picocli.CommandLine.Mixin CredentialsOptions credentialsOptions; + + @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1") + ConnectionOptions connectionOptions; + + PackageSubCommand() { + super(new DefaultToolRuntime()); + } + + @Override + public void runImpl(CommandLine cli) throws Exception { + throw new UnsupportedOperationException( + getName() + " is implemented via the commons-cli path under PackageTool"); + } + + final int runWithManagers(PackageAction action) throws Exception { + String credentials = + credentialsOptions.credentials != null + ? credentialsOptions.credentials + : packageTool.credentialsOptions != null + ? packageTool.credentialsOptions.credentials + : null; + + packageTool.runWithManagers( + connectionOptions != null ? connectionOptions : packageTool.connectionOptions, + credentials, + action); + return 0; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/PackageTool.java b/solr/core/src/java/org/apache/solr/cli/PackageTool.java index cba26c58a3a9..2040cc591392 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageTool.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageTool.java @@ -24,6 +24,7 @@ import java.lang.invoke.MethodHandles; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Map; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; @@ -46,6 +47,43 @@ import org.slf4j.LoggerFactory; /** Supports package command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "package", + description = { + "Install, deploy and manage Solr packages in SolrCloud.", + "Pass --help or -h after any command to see command-specific usage information.", + " Note: (a) Please add '--solr-url http://host:port' parameter if needed (usually on Windows).", + " (b) Please make sure that all solr nodes are started with '-Dsolr.packages.enabled=true'." + }, + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0:Operation completed successfully.", + "1:Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + subcommands = { + AddRepo.class, + AddKey.class, + ListInstalled.class, + ListAvailable.class, + ListDeployed.class, + Install.class, + Deploy.class, + Undeploy.class, + Uninstall.class + }, + footer = { + " # Add a package repository", + " bin/solr package add-repo myrepo https://my.repo.example/repo", + "", + " # Install a package and deploy it to a collection", + " bin/solr package install mypkg:1.0.0", + " bin/solr package deploy mypkg:1.0.0 --collections myCollection -y", + "", + " # List packages deployed on a collection", + " bin/solr package list-deployed -c myCollection" + }) public class PackageTool extends ToolBase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -93,6 +131,29 @@ public class PackageTool extends ToolBase { .desc("Don't prompt for input; accept all default choices, defaults to false.") .get(); + /** Parameters for package sub-commands, independent of the command line parser */ + record PackageFlags( + String collections, + boolean cluster, + String[] parameters, + boolean update, + String collection, + boolean noPrompt) {} + + @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1") + ConnectionOptions connectionOptions; + + @picocli.CommandLine.Mixin CredentialsOptions credentialsOptions; + + @picocli.CommandLine.Spec private picocli.CommandLine.Model.CommandSpec spec; + + private PackageManager packageManager; + private RepositoryManager repositoryManager; + + public PackageTool() { + this(new DefaultToolRuntime()); + } + public PackageTool(ToolRuntime runtime) { super(runtime); } @@ -102,17 +163,36 @@ public String getName() { return "package"; } - public PackageManager packageManager; - public RepositoryManager repositoryManager; - @Override + public void runImpl(CommandLine cli) throws Exception { + String credentials = cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION); + String command = cli.getArgs()[0]; + String[] cmdArgs = Arrays.copyOfRange(cli.getArgs(), 1, cli.getArgs().length); + PackageFlags packageFlags = + new PackageFlags( + cli.getOptionValue(COLLECTIONS_OPTION), + cli.hasOption(CLUSTER_OPTION), + cli.getOptionValues(PARAM_OPTION), + cli.hasOption(UPDATE_OPTION), + cli.getOptionValue(COLLECTION_OPTION), + cli.hasOption(NO_PROMPT_OPTION)); + + executePackage(cli, credentials, command, cmdArgs, packageFlags); + } + @SuppressForbidden( reason = "We really need to print the stacktrace here, otherwise " + "there shall be little else information to debug problems. Other SolrCLI tools " + "don't print stack traces, hence special treatment is needed here." + "Need to turn off logging, and SLF4J doesn't seem to provide for a way.") - public void runImpl(CommandLine cli) throws Exception { + private void executePackage( + CommandLine cli, + String credentials, + String command, + String[] cmdArgs, + PackageFlags packageFlags) + throws Exception { // Need a logging free, clean output going through to the user. Level oldLevel = LoggerContext.getContext(false).getRootLogger().getLevel(); @@ -121,83 +201,23 @@ public void runImpl(CommandLine cli) throws Exception { try { String solrUrl = CLIUtils.normalizeSolrUrl(cli); String zkHost = CLIUtils.getZkHost(cli); + if (zkHost == null) { throw new SolrException(ErrorCode.INVALID_STATE, "Package manager runs only in SolrCloud"); } log.info("ZK: {}", zkHost); - String cmd = cli.getArgs()[0]; - - try (SolrClient solrClient = - CLIUtils.getSolrClient( - solrUrl, cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION), true)) { + try (SolrClient solrClient = CLIUtils.getSolrClient(solrUrl, credentials, true)) { packageManager = new PackageManager(runtime, solrClient, solrUrl, zkHost); try { repositoryManager = new RepositoryManager(solrClient, packageManager); - - // Dispatches to a parser-independent method per sub-command - switch (cmd) { - case "add-repo": - addRepo(cli.getArgs()[1], cli.getArgs()[2]); - break; - case "add-key": - addKey(Path.of(cli.getArgs()[1])); - break; - case "list-installed": - listInstalled(); - break; - case "list-available": - listAvailable(); - break; - case "list-deployed": - if (cli.hasOption(COLLECTION_OPTION)) { - listPackagesDeployedOnCollection(cli.getOptionValue(COLLECTION_OPTION)); - } else { - // nuance that we use an arg here instead of requiring a --package parameter with a - // value in this code path - listCollectionsWithPackageDeployed(cli.getArgs()[1]); - } - break; - case "install": - install(cli.getArgList().get(1)); - break; - case "deploy": - if (cli.hasOption(CLUSTER_OPTION) || cli.hasOption(COLLECTIONS_OPTION)) { - deploy( - cli.getArgList().get(1), - cli.hasOption(CLUSTER_OPTION), - cli.getOptionValue(COLLECTIONS_OPTION), - cli.getOptionValues(PARAM_OPTION), - cli.hasOption(UPDATE_OPTION), - cli.hasOption(NO_PROMPT_OPTION)); - } else { - printRed( - "Either specify --cluster to deploy cluster level plugins or --collections to deploy collection level plugins"); - } - break; - case "undeploy": - if (cli.hasOption(CLUSTER_OPTION) || cli.hasOption(COLLECTIONS_OPTION)) { - undeploy( - cli.getArgList().get(1), - cli.hasOption(CLUSTER_OPTION), - cli.getOptionValue(COLLECTIONS_OPTION)); - } else { - printRed( - "Either specify --cluster to undeploy cluster level plugins or -collections to undeploy collection level plugins"); - } - break; - case "uninstall": - uninstall(cli.getArgList().get(1)); - break; - default: - throw new RuntimeException("Unrecognized command: " + cmd); - } + handleCommand(command, cmdArgs, packageFlags); } finally { packageManager.close(); } } - log.info("Finished: {}", cmd); + log.info("Finished: {}", command); } catch (Exception ex) { // We need to print this since SolrCLI drops the stack trace in favour @@ -210,23 +230,66 @@ public void runImpl(CommandLine cli) throws Exception { } } - private void addRepo(String repoName, String repoUrl) throws Exception { + /** + * Picocli subcommand path: resolve connection, open managers, run action, close. Commons-cli runs + * through {@link #executePackage(CommandLine, String, String, String[], PackageFlags)} instead. + */ + @SuppressForbidden( + reason = + "Package tool prints stack traces and turns off logging; this is same as executePackage.") + void runWithManagers( + ConnectionOptions opts, String credentials, PackageSubCommand.PackageAction action) + throws Exception { + // Need a logging free, clean output going through to the user. + Level oldLevel = LoggerContext.getContext(false).getRootLogger().getLevel(); + Configurator.setRootLevel(Level.OFF); + + try { + String solrUrl = ConnectionOptions.resolveSolrUrl(opts, credentials); + String zkHost = ConnectionOptions.resolveZkHost(opts, solrUrl, credentials); + + if (zkHost == null) { + throw new SolrException(ErrorCode.INVALID_STATE, "Package manager runs only in SolrCloud"); + } + + log.info("ZK: {}", zkHost); + + try (SolrClient solrClient = CLIUtils.getSolrClient(solrUrl, credentials, true)) { + packageManager = new PackageManager(runtime, solrClient, solrUrl, zkHost); + try { + repositoryManager = new RepositoryManager(solrClient, packageManager); + action.run(packageManager, repositoryManager); + } finally { + packageManager.close(); + } + } + + } catch (Exception ex) { + ex.printStackTrace(); + throw ex; + } finally { + Configurator.setRootLevel(oldLevel); + } + } + + void addRepo(RepositoryManager repositoryManager, String repoName, String repoUrl) + throws Exception { repositoryManager.addRepository(repoName, repoUrl); printGreen("Added repository: " + repoName); } - private void addKey(Path keyFile) throws Exception { + void addKey(RepositoryManager repositoryManager, Path keyFile) throws Exception { repositoryManager.addKey(Files.readAllBytes(keyFile), keyFile.getFileName().toString()); } - private void listInstalled() throws Exception { + void listInstalled(PackageManager packageManager) throws Exception { printGreen("Installed packages:\n-----"); for (SolrPackageInstance pkg : packageManager.fetchInstalledPackageInstances()) { printGreen(pkg); } } - private void listAvailable() throws Exception { + void listAvailable(RepositoryManager repositoryManager) throws Exception { printGreen("Available packages:\n-----"); for (SolrPackage pkg : repositoryManager.getPackages()) { printGreen(pkg.name + " \t\t" + pkg.description); @@ -236,7 +299,7 @@ private void listAvailable() throws Exception { } } - private void listPackagesDeployedOnCollection(String collection) { + void listPackagesDeployedOnCollection(PackageManager packageManager, String collection) { Map packages = packageManager.getPackagesDeployed(collection); printGreen("Packages deployed on " + collection + ":"); for (String packageName : packages.keySet()) { @@ -244,7 +307,7 @@ private void listPackagesDeployedOnCollection(String collection) { } } - private void listCollectionsWithPackageDeployed(String packageName) { + void listCollectionsWithPackageDeployed(PackageManager packageManager, String packageName) { Map deployedCollections = packageManager.getDeployedCollections(packageName); if (!deployedCollections.isEmpty()) { printGreen("Collections on which package " + packageName + " was deployed:"); @@ -263,7 +326,8 @@ private void listCollectionsWithPackageDeployed(String packageName) { } } - private void install(String packageNameAndVersion) throws Exception { + boolean install(RepositoryManager repositoryManager, String packageNameAndVersion) + throws Exception { Pair parsedVersion = parsePackageVersion(packageNameAndVersion); String packageName = parsedVersion.first(); String version = parsedVersion.second(); @@ -273,12 +337,14 @@ private void install(String packageNameAndVersion) throws Exception { } else { printRed(packageName + " installation failed."); } + return success; } /** * @param collections raw comma-separated value of the --collections option, or null */ - private void deploy( + void deploy( + PackageManager packageManager, String packageNameAndVersion, boolean cluster, String collections, @@ -300,7 +366,11 @@ private void deploy( /** * @param collections raw comma-separated value of the --collections option, or null */ - private void undeploy(String packageNameAndVersion, boolean cluster, String collections) + void undeploy( + PackageManager packageManager, + String packageNameAndVersion, + boolean cluster, + String collections) throws Exception { Pair parsedVersion = parsePackageVersion(packageNameAndVersion); if (parsedVersion.second() != null) { @@ -316,7 +386,7 @@ private void undeploy(String packageNameAndVersion, boolean cluster, String coll packageManager.undeploy(packageName, collectionArray, cluster); } - private void uninstall(String packageNameAndVersion) throws Exception { + void uninstall(PackageManager packageManager, String packageNameAndVersion) throws Exception { Pair parsedVersion = parsePackageVersion(packageNameAndVersion); if (parsedVersion.second() == null) { throw new SolrException( @@ -326,6 +396,62 @@ private void uninstall(String packageNameAndVersion) throws Exception { packageManager.uninstall(parsedVersion.first(), parsedVersion.second()); } + private void handleCommand(String command, String[] cmdArgs, PackageFlags packageFlags) + throws Exception { + switch (command) { + case "add-repo": + addRepo(repositoryManager, cmdArgs[0], cmdArgs[1]); + break; + case "add-key": + addKey(repositoryManager, Path.of(cmdArgs[0])); + break; + case "list-installed": + listInstalled(packageManager); + break; + case "list-available": + listAvailable(repositoryManager); + break; + case "list-deployed": + if (packageFlags.collection() != null) { + listPackagesDeployedOnCollection(packageManager, packageFlags.collection()); + } else { + listCollectionsWithPackageDeployed(packageManager, cmdArgs[0]); + } + break; + case "install": + install(repositoryManager, cmdArgs[0]); + break; + case "deploy": + if (packageFlags.cluster() || packageFlags.collections() != null) { + deploy( + packageManager, + cmdArgs[0], + packageFlags.cluster(), + packageFlags.collections(), + packageFlags.parameters(), + packageFlags.update(), + packageFlags.noPrompt()); + } else { + printRed( + "Either specify --cluster to deploy cluster level plugins or --collections to deploy collection level plugins"); + } + break; + case "undeploy": + if (packageFlags.cluster() || packageFlags.collections() != null) { + undeploy(packageManager, cmdArgs[0], packageFlags.cluster(), packageFlags.collections()); + } else { + printRed( + "Either specify --cluster to undeploy cluster level plugins or --collections to undeploy collection level plugins"); + } + break; + case "uninstall": + uninstall(packageManager, cmdArgs[0]); + break; + default: + throw new RuntimeException("Unrecognized command: " + command); + } + } + @Override public String getHeader() { StringBuilder sb = new StringBuilder(); @@ -415,6 +541,7 @@ public Options getOptions() { @Override public int callTool() throws Exception { - throw new UnsupportedOperationException("This tool does not yet support PicoCli"); + spec.commandLine().usage(CLIO.getOutStream()); + return 0; } } diff --git a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java index a80d7f7883e8..3f6de7b0fd42 100755 --- a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java +++ b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java @@ -80,7 +80,8 @@ ZkTool.class, AuthTool.class, CreateTool.class, - DeleteTool.class + DeleteTool.class, + PackageTool.class }) public class SolrCLI implements CLIO, java.util.concurrent.Callable { diff --git a/solr/core/src/java/org/apache/solr/cli/Undeploy.java b/solr/core/src/java/org/apache/solr/cli/Undeploy.java new file mode 100644 index 000000000000..7c1939aa6f7e --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/Undeploy.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +import static org.apache.solr.cli.SolrCLI.printRed; + +/** Supports package undeploy command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "undeploy", + description = "Undeploy a package from specified collection(s) or at cluster level.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # Undeploy a package from a collection", + " bin/solr package undeploy mypkg --collections myCollection" + }) +public class Undeploy extends PackageSubCommand { + + @picocli.CommandLine.Parameters( + index = "0", + arity = "1", + paramLabel = "PACKAGE", + description = "Package name") + private String packageName; + + @picocli.CommandLine.Option( + names = {"--cluster"}, + description = "Specifies that this action should affect cluster-level plugins only.") + private boolean cluster; + + @picocli.CommandLine.Option( + names = {"--collections"}, + paramLabel = "COLLECTIONS", + description = + "Specifies that this action should affect plugins for the given collections only, excluding cluster level plugins.") + private String collections; + + @Override + public int callTool() throws Exception { + if (!cluster && collections == null) { + printRed( + "Either specify --cluster to undeploy cluster level plugins or --collections to undeploy collection level plugins"); + return 1; + } + return runWithManagers( + (packageManager, repositoryManager) -> + packageTool.undeploy(packageManager, packageName, cluster, collections)); + } + + @Override + public String getName() { + return "undeploy"; + } +} diff --git a/solr/core/src/java/org/apache/solr/cli/Uninstall.java b/solr/core/src/java/org/apache/solr/cli/Uninstall.java new file mode 100644 index 000000000000..0a45b0ba76cd --- /dev/null +++ b/solr/core/src/java/org/apache/solr/cli/Uninstall.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +/** Supports package uninstall command in the bin/solr script. */ +@SuppressWarnings("UnnecessarilyFullyQualified") +@picocli.CommandLine.Command( + name = "uninstall", + description = "Uninstall any package with a specified version from Solr.", + exitCodeListHeading = "%nExit Codes:%n", + exitCodeList = { + "0: Operation completed successfully.", + "1: Operation failed; check output for details." + }, + footerHeading = "%nExamples:%n", + footer = { + " # Uninstall a specific package version", + " bin/solr package uninstall mypkg:1.0.0", + }) +public class Uninstall extends PackageSubCommand { + + @picocli.CommandLine.Parameters( + index = "0", + arity = "1", + paramLabel = "PACKAGE:VERSION", + description = "Package name and version, separated by a colon.") + private String packageNameAndVersion; + + @Override + public int callTool() throws Exception { + return runWithManagers( + (packageManager, repositoryManager) -> + packageTool.uninstall(packageManager, packageNameAndVersion)); + } + + @Override + public String getName() { + return "uninstall"; + } +} diff --git a/solr/core/src/test/org/apache/solr/cli/PackageToolPicocliTest.java b/solr/core/src/test/org/apache/solr/cli/PackageToolPicocliTest.java new file mode 100644 index 000000000000..b850ee70cf19 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/cli/PackageToolPicocliTest.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.cli; + +import picocli.CommandLine; + +/** Runs all {@link PackageToolTest} tests through the picocli invocation path. */ +public class PackageToolPicocliTest extends PackageToolTest { + + @Override + protected int runTool(String[] args, ToolRuntime runtime) throws Exception { + PackageTool tool = new PackageTool(runtime); + return new CommandLine(tool) + .setDefaultValueProvider(new CliDefaultValueProvider()) + .execute(args); + } +} diff --git a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java index 9282af37e520..557ea5d1d345 100644 --- a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java +++ b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java @@ -89,21 +89,21 @@ private > T withBasicAuth(T req) { return req; } - @Test - public void testPackageTool() throws Exception { - ToolRuntime runtime = new CLITestHelper.TestingRuntime(false); + protected int runTool(String[] args, ToolRuntime runtime) throws Exception { PackageTool tool = new PackageTool(runtime); + return tool.runTool(SolrCLI.processCommandLineArgs(tool, args)); + } + @Test + public void testPackageTool() throws Exception { String solrUrl = cluster.getJettySolrRunner(0).getBaseUrl().toString(); run( - tool, new String[] { "--solr-url", solrUrl, "list-installed", "--credentials", SecurityJson.USER_PASS }); run( - tool, new String[] { "--solr-url", solrUrl, @@ -115,13 +115,11 @@ public void testPackageTool() throws Exception { }); run( - tool, new String[] { "--solr-url", solrUrl, "list-available", "--credentials", SecurityJson.USER_PASS }); run( - tool, new String[] { "--solr-url", solrUrl, @@ -132,7 +130,6 @@ public void testPackageTool() throws Exception { }); run( - tool, new String[] { "--solr-url", solrUrl, "list-installed", "--credentials", SecurityJson.USER_PASS }); @@ -145,7 +142,6 @@ public void testPackageTool() throws Exception { String rhPath = "/mypath2"; run( - tool, new String[] { "--solr-url", solrUrl, @@ -157,7 +153,6 @@ public void testPackageTool() throws Exception { // Leaving -p in for --param to test the deprecated value continues to work. run( - tool, new String[] { "--solr-url", solrUrl, @@ -175,7 +170,6 @@ public void testPackageTool() throws Exception { "abc", "question-answer", "1.0.0", rhPath, "1.0.0", SecurityJson.USER_PASS); run( - tool, new String[] { "--solr-url", solrUrl, @@ -186,7 +180,6 @@ public void testPackageTool() throws Exception { }); run( - tool, new String[] { "--solr-url", solrUrl, @@ -206,7 +199,6 @@ public void testPackageTool() throws Exception { // This command pegs the version to the latest available run( - tool, new String[] { "--solr-url", solrUrl, @@ -222,7 +214,6 @@ public void testPackageTool() throws Exception { "abc", "question-answer", "$LATEST", rhPath, "1.0.0", SecurityJson.USER_PASS); run( - tool, new String[] { "--solr-url", solrUrl, @@ -237,7 +228,6 @@ public void testPackageTool() throws Exception { log.info("Testing explicit deployment to a different/newer version"); run( - tool, new String[] { "--solr-url", solrUrl, @@ -252,7 +242,6 @@ public void testPackageTool() throws Exception { // even if parameters are not passed in, they should be picked up from previous deployment if (random().nextBoolean()) { run( - tool, new String[] { "--solr-url", solrUrl, @@ -269,7 +258,6 @@ public void testPackageTool() throws Exception { }); } else { run( - tool, new String[] { "--solr-url", solrUrl, @@ -289,7 +277,6 @@ public void testPackageTool() throws Exception { log.info("Running undeploy..."); run( - tool, new String[] { "--solr-url", solrUrl, @@ -302,7 +289,6 @@ public void testPackageTool() throws Exception { }); run( - tool, new String[] { "--solr-url", solrUrl, @@ -382,23 +368,21 @@ public void testDeployValidationMessages() throws Exception { .processAndWait(cluster.getSolrClient(), 10); CLITestHelper.TestingRuntime captureRuntime = new CLITestHelper.TestingRuntime(true); - PackageTool tool = new PackageTool(captureRuntime); // Collection exists but package does not — collection validation should pass, // package lookup should fail. - tool.runTool( - SolrCLI.processCommandLineArgs( - tool, - new String[] { - "--solr-url", - solrUrl, - "deploy", - "NONEXISTENT_PKG", - "--collections", - "validation-test", - "--credentials", - SecurityJson.USER_PASS - })); + runTool( + new String[] { + "--solr-url", + solrUrl, + "deploy", + "NONEXISTENT_PKG", + "--collections", + "validation-test", + "--credentials", + SecurityJson.USER_PASS + }, + captureRuntime); String deployOut = captureRuntime.getOutput(); assertFalse( "Should not complain about invalid collection", deployOut.contains("Invalid collection")); @@ -409,19 +393,18 @@ public void testDeployValidationMessages() throws Exception { captureRuntime.clearOutput(); // Undeploy of a package that was never deployed should give a clear message. - tool.runTool( - SolrCLI.processCommandLineArgs( - tool, - new String[] { - "--solr-url", - solrUrl, - "undeploy", - "NONEXISTENT_PKG", - "--collections", - "validation-test", - "--credentials", - SecurityJson.USER_PASS - })); + runTool( + new String[] { + "--solr-url", + solrUrl, + "undeploy", + "NONEXISTENT_PKG", + "--collections", + "validation-test", + "--credentials", + SecurityJson.USER_PASS + }, + captureRuntime); String undeployOut = captureRuntime.getOutput(); assertFalse( "Should not complain about invalid collection", undeployOut.contains("Invalid collection")); @@ -430,8 +413,8 @@ public void testDeployValidationMessages() throws Exception { undeployOut.contains("Package NONEXISTENT_PKG not deployed on collection validation-test")); } - private void run(PackageTool tool, String[] args) throws Exception { - int res = tool.runTool(SolrCLI.processCommandLineArgs(tool, args)); + private void run(String[] args) throws Exception { + int res = runTool(args, new CLITestHelper.TestingRuntime(false)); assertEquals("Non-zero status returned for: " + Arrays.toString(args), 0, res); } From 815dea0cd96ae290799852b3fc3c1663ca945da0 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 00:47:26 +0530 Subject: [PATCH 02/17] docs generated --- .../deployment-guide/deployment-nav.adoc | 10 ++ .../deployment-guide/pages/cli/index.adoc | 10 ++ .../pages/cli/solr-package-add-key.adoc | 96 +++++++++++++ .../pages/cli/solr-package-add-repo.adoc | 100 +++++++++++++ .../pages/cli/solr-package-deploy.adoc | 116 +++++++++++++++ .../pages/cli/solr-package-install.adoc | 100 +++++++++++++ .../cli/solr-package-list-available.adoc | 88 ++++++++++++ .../pages/cli/solr-package-list-deployed.adoc | 104 ++++++++++++++ .../cli/solr-package-list-installed.adoc | 88 ++++++++++++ .../pages/cli/solr-package-undeploy.adoc | 103 ++++++++++++++ .../pages/cli/solr-package-uninstall.adoc | 96 +++++++++++++ .../pages/cli/solr-package.adoc | 132 ++++++++++++++++++ 12 files changed, 1043 insertions(+) create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-key.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-repo.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-deploy.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-install.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-available.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-deployed.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-installed.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-undeploy.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-uninstall.adoc create mode 100644 solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package.adoc diff --git a/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc b/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc index 309b2bd959f6..74816f96e951 100644 --- a/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc +++ b/solr/solr-ref-guide/modules/deployment-guide/deployment-nav.adoc @@ -23,6 +23,16 @@ *** xref:cli/solr-auth.adoc[auth] *** xref:cli/solr-create.adoc[create] *** xref:cli/solr-delete.adoc[delete] +*** xref:cli/solr-package.adoc[package] +**** xref:cli/solr-package-add-key.adoc[key] +**** xref:cli/solr-package-add-repo.adoc[repo] +**** xref:cli/solr-package-deploy.adoc[deploy] +**** xref:cli/solr-package-install.adoc[install] +**** xref:cli/solr-package-list-available.adoc[available] +**** xref:cli/solr-package-list-deployed.adoc[deployed] +**** xref:cli/solr-package-list-installed.adoc[installed] +**** xref:cli/solr-package-undeploy.adoc[undeploy] +**** xref:cli/solr-package-uninstall.adoc[uninstall] *** xref:cli/solr-start.adoc[start] *** xref:cli/solr-status.adoc[status] *** xref:cli/solr-stop.adoc[stop] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc index f00109598068..4442410513d1 100644 --- a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/index.adoc @@ -62,6 +62,16 @@ Any command not listed here is unavailable when the picocli implementation is en |xref:cli/solr-auth.adoc[bin/solr auth] |xref:cli/solr-create.adoc[bin/solr create] |xref:cli/solr-delete.adoc[bin/solr delete] +|xref:cli/solr-package-add-key.adoc[bin/solr package add key] +|xref:cli/solr-package-add-repo.adoc[bin/solr package add repo] +|xref:cli/solr-package-deploy.adoc[bin/solr package deploy] +|xref:cli/solr-package-install.adoc[bin/solr package install] +|xref:cli/solr-package-list-available.adoc[bin/solr package list available] +|xref:cli/solr-package-list-deployed.adoc[bin/solr package list deployed] +|xref:cli/solr-package-list-installed.adoc[bin/solr package list installed] +|xref:cli/solr-package-undeploy.adoc[bin/solr package undeploy] +|xref:cli/solr-package-uninstall.adoc[bin/solr package uninstall] +|xref:cli/solr-package.adoc[bin/solr package] |xref:cli/solr-start.adoc[bin/solr start] |xref:cli/solr-status.adoc[bin/solr status] |xref:cli/solr-stop.adoc[bin/solr stop] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-key.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-key.adoc new file mode 100644 index 000000000000..801afac30917 --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-key.adoc @@ -0,0 +1,96 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package add key +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package add-key [-hv] [-u=] [-s= | + --solr-url= | -z=] KEY-FILE +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Add a trusted key to Solr. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-arguments[] +== Arguments + +_KEY-FILE_:: + Path to a file containing the trusted key. + +// end::picocli-generated-man-section-arguments[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # Add a trusted public key + bin/solr package add-key /path/to/public.key.der + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-repo.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-repo.adoc new file mode 100644 index 000000000000..04f1eccd2fc5 --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-add-repo.adoc @@ -0,0 +1,100 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package add repo +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package add-repo [-hv] [-u=] [-s= | + --solr-url= | -z=] REPOSITORY-NAME + REPOSITORY-URL +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Add a package repository to Solr. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-arguments[] +== Arguments + +_REPOSITORY-NAME_:: + Name of the package repository. + +_REPOSITORY-URL_:: + URL of the package repository. + +// end::picocli-generated-man-section-arguments[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # Add a package repository + bin/solr package add-repo myrepo https://my.repo.example/repo + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-deploy.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-deploy.adoc new file mode 100644 index 000000000000..cd1b181a2a41 --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-deploy.adoc @@ -0,0 +1,116 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package deploy +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package deploy [-hvy] [--cluster] [--update] [--collections=COLLECTIONS] + [-u=] [-p=PARAMS]... [-s= | + --solr-url= | -z=] PACKAGE[:VERSION] +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Deploy an installed package to collections or at cluster level. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*--cluster*:: + Specifies that this action should affect cluster-level plugins only. + +*--collections*=_COLLECTIONS_:: + Specifies that this action should affect plugins for the given collections only, excluding cluster level plugins. + +*-h*, *--help*:: + Print this help message and exit. + +*-p*, *--param*=_PARAMS_:: + List of parameters to be used with deploy command. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*--update*:: + If a deployment is an update over a previous deployment. + +*-v*, *--verbose*:: + Enable verbose mode. + +*-y*, *--no-prompt*:: + Don't prompt for input; accept all default choices, defaults to false. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-arguments[] +== Arguments + +_PACKAGE[:VERSION]_:: + Package name, optionally with :version. + +// end::picocli-generated-man-section-arguments[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # Deploy a package to a collection + bin/solr package deploy mypkg:1.0.0 --collections myCollection -y + +[%hardbreaks] + # Update an existing deployment + bin/solr package deploy mypkg --update --collections myCollection -y + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-install.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-install.adoc new file mode 100644 index 000000000000..7734cedff149 --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-install.adoc @@ -0,0 +1,100 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package install +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package install [-hv] [-u=] [-s= | + --solr-url= | -z=] PACKAGE[:VERSION] +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Install a package into Solr. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-arguments[] +== Arguments + +_PACKAGE[:VERSION]_:: + Package name, optionally with :version. + +// end::picocli-generated-man-section-arguments[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # Install a specific package version + bin/solr package install mypkg:1.0.0 + +[%hardbreaks] + # Install the latest available version + bin/solr package install mypkg + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-available.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-available.adoc new file mode 100644 index 000000000000..83110eb433db --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-available.adoc @@ -0,0 +1,88 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package list available +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package list-available [-hv] [-u=] [-s= | + --solr-url= | -z=] +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Print a list of packages available in the repositories. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # List packages available from configured repositories + bin/solr package list-available + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-deployed.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-deployed.adoc new file mode 100644 index 000000000000..ecd8cdfb609d --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-deployed.adoc @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package list deployed +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package list-deployed [-hv] [-c=COLLECTION] [-u=] + [-s= | --solr-url= | + -z=] [PACKAGE] +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Print packages deployed on a collection, or collections where a package is deployed. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-c*, *--collection*=_COLLECTION_:: + The collection to apply the package to, not required. + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-arguments[] +== Arguments + +[_PACKAGE_]:: + Package name; lists collections where this package is deployed. + +// end::picocli-generated-man-section-arguments[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # List packages deployed on a collection + bin/solr package list-deployed -c myCollection + +[%hardbreaks] + # List collections where a package is deployed + bin/solr package list-deployed mypkg + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-installed.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-installed.adoc new file mode 100644 index 000000000000..216b3e58bfb4 --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-list-installed.adoc @@ -0,0 +1,88 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package list installed +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package list-installed [-hv] [-u=] [-s= | + --solr-url= | -z=] +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Print a list of packages installed in Solr. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # List all installed packages + bin/solr package list-installed + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-undeploy.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-undeploy.adoc new file mode 100644 index 000000000000..dd61fbb36a0d --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-undeploy.adoc @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package undeploy +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package undeploy [-hv] [--cluster] [--collections=COLLECTIONS] + [-u=] [-s= | + --solr-url= | -z=] PACKAGE +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Undeploy a package from specified collection(s) or at cluster level. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*--cluster*:: + Specifies that this action should affect cluster-level plugins only. + +*--collections*=_COLLECTIONS_:: + Specifies that this action should affect plugins for the given collections only, excluding cluster level plugins. + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-arguments[] +== Arguments + +_PACKAGE_:: + Package name + +// end::picocli-generated-man-section-arguments[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # Undeploy a package from a collection + bin/solr package undeploy mypkg --collections myCollection + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-uninstall.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-uninstall.adoc new file mode 100644 index 000000000000..689984fa85ac --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package-uninstall.adoc @@ -0,0 +1,96 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package uninstall +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package uninstall [-hv] [-u=] [-s= | + --solr-url= | -z=] PACKAGE:VERSION +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Uninstall any package with a specified version from Solr. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-arguments[] +== Arguments + +_PACKAGE:VERSION_:: + Package name and version, separated by a colon. + +// end::picocli-generated-man-section-arguments[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # Uninstall a specific package version + bin/solr package uninstall mypkg:1.0.0 + +// end::picocli-generated-man-section-footer[] diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package.adoc new file mode 100644 index 000000000000..ba00cf3e03b3 --- /dev/null +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/cli/solr-package.adoc @@ -0,0 +1,132 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// DO NOT EDIT -- this page is auto-generated from picocli annotations. +// To update: modify the @Command/@Option annotations in the Java source, then run: +// ./gradlew :solr:solr-ref-guide:generateCliDocs + += bin/solr package +:page-toclevels: 2 + +[WARNING] +==== +This page documents the *experimental* picocli implementation of `bin/solr`, which is not enabled by default. +For what `bin/solr` does by default, see xref:solr-control-script-reference.adoc[]. +See xref:cli/index.adoc[] to enable this implementation and for its known limitations. +==== + +// tag::picocli-generated-man-section-synopsis[] +== Synopsis + +.... +bin/solr package [-hv] [-u=] [-s= | + --solr-url= | -z=] [COMMAND] +.... + +// end::picocli-generated-man-section-synopsis[] + +// tag::picocli-generated-man-section-description[] +== Description + +Install, deploy and manage Solr packages in SolrCloud. +Pass --help or -h after any command to see command-specific usage information. + Note: (a) Please add '--solr-url http://host:port' parameter if needed (usually on Windows). + (b) Please make sure that all solr nodes are started with '-Dsolr.packages.enabled=true'. + +// end::picocli-generated-man-section-description[] + +// tag::picocli-generated-man-section-options[] +== Options + +*-h*, *--help*:: + Print this help message and exit. + +*-s*, *--solr-connection*=__:: + Zookeeper or HTTP(s) connection string; unnecessary if SOLR_CONNECTION is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +*--solr-url*=__:: + Base Solr URL, which can be used to determine the zk-host if that's not known. + +*-u*, *--credentials*=__:: + Credentials in the format username:password. Example: --credentials solr:SolrRocks + +*-v*, *--verbose*:: + Enable verbose mode. + +*-z*, *--zk-host*=__:: + Zookeeper connection string; unnecessary if ZK_HOST is defined in solr.in.sh; otherwise, defaults to localhost:9983. + +// end::picocli-generated-man-section-options[] + +// tag::picocli-generated-man-section-commands[] +== Commands + +xref:cli/solr-package-add-repo.adoc[*add-repo*]:: + Add a package repository to Solr. + +xref:cli/solr-package-add-key.adoc[*add-key*]:: + Add a trusted key to Solr. + +xref:cli/solr-package-list-installed.adoc[*list-installed*]:: + Print a list of packages installed in Solr. + +xref:cli/solr-package-list-available.adoc[*list-available*]:: + Print a list of packages available in the repositories. + +xref:cli/solr-package-list-deployed.adoc[*list-deployed*]:: + Print packages deployed on a collection, or collections where a package is deployed. + +xref:cli/solr-package-install.adoc[*install*]:: + Install a package into Solr. + +xref:cli/solr-package-deploy.adoc[*deploy*]:: + Deploy an installed package to collections or at cluster level. + +xref:cli/solr-package-undeploy.adoc[*undeploy*]:: + Undeploy a package from specified collection(s) or at cluster level. + +xref:cli/solr-package-uninstall.adoc[*uninstall*]:: + Uninstall any package with a specified version from Solr. + +// end::picocli-generated-man-section-commands[] + +// tag::picocli-generated-man-section-exit-status[] +== Exit Codes +*0*:: + Operation completed successfully. + +*1*:: + Operation failed; check output for details. + +// end::picocli-generated-man-section-exit-status[] + +// tag::picocli-generated-man-section-footer[] +== Examples +[%hardbreaks] + # Add a package repository + bin/solr package add-repo myrepo https://my.repo.example/repo + +[%hardbreaks] + # Install a package and deploy it to a collection + bin/solr package install mypkg:1.0.0 + bin/solr package deploy mypkg:1.0.0 --collections myCollection -y + +[%hardbreaks] + # List packages deployed on a collection + bin/solr package list-deployed -c myCollection + +// end::picocli-generated-man-section-footer[] From 9949c90a1987c956fe8944d5584cd54b68ca6cef Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 00:57:56 +0530 Subject: [PATCH 03/17] minor --- solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java index 2a1ae5de3746..62103e8ddd7b 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java @@ -29,7 +29,8 @@ interface PackageAction { void run(PackageManager packageManager, RepositoryManager repositoryManager) throws Exception; } - @picocli.CommandLine.ParentCommand PackageTool packageTool; + @picocli.CommandLine.ParentCommand + PackageTool packageTool; @picocli.CommandLine.Mixin CredentialsOptions credentialsOptions; From eb871221209ea4d92a1e79f670099a643e46e8c0 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 01:08:27 +0530 Subject: [PATCH 04/17] tidy --- solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java index 62103e8ddd7b..2a1ae5de3746 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java @@ -29,8 +29,7 @@ interface PackageAction { void run(PackageManager packageManager, RepositoryManager repositoryManager) throws Exception; } - @picocli.CommandLine.ParentCommand - PackageTool packageTool; + @picocli.CommandLine.ParentCommand PackageTool packageTool; @picocli.CommandLine.Mixin CredentialsOptions credentialsOptions; From 157ef8866f26d90015c7590a330547d18e698d8e Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 01:21:01 +0530 Subject: [PATCH 05/17] precommit fixed --- .../src/java/org/apache/solr/cli/PackageSubCommand.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java index 2a1ae5de3746..2324892fe93c 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java @@ -20,6 +20,9 @@ import org.apache.commons.cli.CommandLine; import org.apache.solr.packagemanager.PackageManager; import org.apache.solr.packagemanager.RepositoryManager; +import picocli.CommandLine.ArgGroup; +import picocli.CommandLine.Mixin; +import picocli.CommandLine.ParentCommand; /** Shared picocli wiring for {@code bin/solr package leaves} */ abstract class PackageSubCommand extends ToolBase { @@ -29,11 +32,11 @@ interface PackageAction { void run(PackageManager packageManager, RepositoryManager repositoryManager) throws Exception; } - @picocli.CommandLine.ParentCommand PackageTool packageTool; + @ParentCommand PackageTool packageTool; - @picocli.CommandLine.Mixin CredentialsOptions credentialsOptions; + @Mixin CredentialsOptions credentialsOptions; - @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1") + @ArgGroup(exclusive = true, multiplicity = "0..1") ConnectionOptions connectionOptions; PackageSubCommand() { From dec41f5df7392afe2436049300eac7ceec2e59fb Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 01:28:51 +0530 Subject: [PATCH 06/17] cl refresh --- changelog/unreleased/SOLR-17697-packagetool.yml | 9 --------- changelog/unreleased/SOLR-18515-package-tool-picocli.yml | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 changelog/unreleased/SOLR-17697-packagetool.yml create mode 100644 changelog/unreleased/SOLR-18515-package-tool-picocli.yml diff --git a/changelog/unreleased/SOLR-17697-packagetool.yml b/changelog/unreleased/SOLR-17697-packagetool.yml deleted file mode 100644 index ac5d963a050e..000000000000 --- a/changelog/unreleased/SOLR-17697-packagetool.yml +++ /dev/null @@ -1,9 +0,0 @@ -title: - Implement picocli for package command / PackageTool -type: changed -authors: - - name: Jalaz Kumar - nick: jaykay12 -links: - - name: SOLR-17697 - url: https://issues.apache.org/jira/browse/SOLR-17697 diff --git a/changelog/unreleased/SOLR-18515-package-tool-picocli.yml b/changelog/unreleased/SOLR-18515-package-tool-picocli.yml new file mode 100644 index 000000000000..d8b4b7d7e940 --- /dev/null +++ b/changelog/unreleased/SOLR-18515-package-tool-picocli.yml @@ -0,0 +1,9 @@ +title: + Implement PicoCLI for package command / PackageTool +type: changed +authors: + - name: Jalaz Kumar + nick: jaykay12 +links: + - name: SOLR-18515 + url: https://issues.apache.org/jira/browse/SOLR-18515 From 1750e6c989c49d838a5f7edc0c8f5345adc2c5a7 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 01:43:39 +0530 Subject: [PATCH 07/17] pr comments --- .../cli/{AddKey.java => PackageAddKey.java} | 2 +- .../cli/{AddRepo.java => PackageAddRepo.java} | 2 +- .../cli/{Deploy.java => PackageDeploy.java} | 6 +++--- ...ailable.java => PackageListAvailable.java} | 2 +- ...Deployed.java => PackageListDeployed.java} | 2 +- ...stalled.java => PackageListInstalled.java} | 2 +- .../java/org/apache/solr/cli/PackageTool.java | 20 +++++++++---------- .../{Undeploy.java => PackageUndeploy.java} | 6 +++--- .../{Uninstall.java => PackageUninstall.java} | 6 +++--- .../solr/packagemanager/PackageManager.java | 8 ++++---- .../org/apache/solr/cli/PackageToolTest.java | 2 +- 11 files changed, 29 insertions(+), 29 deletions(-) rename solr/core/src/java/org/apache/solr/cli/{AddKey.java => PackageAddKey.java} (97%) rename solr/core/src/java/org/apache/solr/cli/{AddRepo.java => PackageAddRepo.java} (97%) rename solr/core/src/java/org/apache/solr/cli/{Deploy.java => PackageDeploy.java} (94%) rename solr/core/src/java/org/apache/solr/cli/{ListAvailable.java => PackageListAvailable.java} (96%) rename solr/core/src/java/org/apache/solr/cli/{ListDeployed.java => PackageListDeployed.java} (97%) rename solr/core/src/java/org/apache/solr/cli/{ListInstalled.java => PackageListInstalled.java} (96%) rename solr/core/src/java/org/apache/solr/cli/{Undeploy.java => PackageUndeploy.java} (92%) rename solr/core/src/java/org/apache/solr/cli/{Uninstall.java => PackageUninstall.java} (89%) diff --git a/solr/core/src/java/org/apache/solr/cli/AddKey.java b/solr/core/src/java/org/apache/solr/cli/PackageAddKey.java similarity index 97% rename from solr/core/src/java/org/apache/solr/cli/AddKey.java rename to solr/core/src/java/org/apache/solr/cli/PackageAddKey.java index 9cdd6414b10d..97f6bc286beb 100644 --- a/solr/core/src/java/org/apache/solr/cli/AddKey.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageAddKey.java @@ -34,7 +34,7 @@ " # Add a trusted public key", " bin/solr package add-key /path/to/public.key.der", }) -public class AddKey extends PackageSubCommand { +public class PackageAddKey extends PackageSubCommand { @picocli.CommandLine.Parameters( index = "0", diff --git a/solr/core/src/java/org/apache/solr/cli/AddRepo.java b/solr/core/src/java/org/apache/solr/cli/PackageAddRepo.java similarity index 97% rename from solr/core/src/java/org/apache/solr/cli/AddRepo.java rename to solr/core/src/java/org/apache/solr/cli/PackageAddRepo.java index e9c24d724293..cb3bc7067a32 100644 --- a/solr/core/src/java/org/apache/solr/cli/AddRepo.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageAddRepo.java @@ -32,7 +32,7 @@ " # Add a package repository", " bin/solr package add-repo myrepo https://my.repo.example/repo", }) -public class AddRepo extends PackageSubCommand { +public class PackageAddRepo extends PackageSubCommand { @picocli.CommandLine.Parameters( index = "0", diff --git a/solr/core/src/java/org/apache/solr/cli/Deploy.java b/solr/core/src/java/org/apache/solr/cli/PackageDeploy.java similarity index 94% rename from solr/core/src/java/org/apache/solr/cli/Deploy.java rename to solr/core/src/java/org/apache/solr/cli/PackageDeploy.java index 4e27c9809e8c..ea4ee59b1252 100644 --- a/solr/core/src/java/org/apache/solr/cli/Deploy.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageDeploy.java @@ -23,7 +23,7 @@ @SuppressWarnings("UnnecessarilyFullyQualified") @picocli.CommandLine.Command( name = "deploy", - description = "Deploy an installed package to collections or at cluster level.", + description = "PackageDeploy an installed package to collections or at cluster level.", exitCodeListHeading = "%nExit Codes:%n", exitCodeList = { "0: Operation completed successfully.", @@ -31,13 +31,13 @@ }, footerHeading = "%nExamples:%n", footer = { - " # Deploy a package to a collection", + " # PackageDeploy a package to a collection", " bin/solr package deploy mypkg:1.0.0 --collections myCollection -y", "", " # Update an existing deployment", " bin/solr package deploy mypkg --update --collections myCollection -y" }) -public class Deploy extends PackageSubCommand { +public class PackageDeploy extends PackageSubCommand { @picocli.CommandLine.Parameters( index = "0", diff --git a/solr/core/src/java/org/apache/solr/cli/ListAvailable.java b/solr/core/src/java/org/apache/solr/cli/PackageListAvailable.java similarity index 96% rename from solr/core/src/java/org/apache/solr/cli/ListAvailable.java rename to solr/core/src/java/org/apache/solr/cli/PackageListAvailable.java index c5f2fe7a124b..e0420ecb7d46 100644 --- a/solr/core/src/java/org/apache/solr/cli/ListAvailable.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageListAvailable.java @@ -32,7 +32,7 @@ " # List packages available from configured repositories", " bin/solr package list-available", }) -public class ListAvailable extends PackageSubCommand { +public class PackageListAvailable extends PackageSubCommand { @Override public int callTool() throws Exception { diff --git a/solr/core/src/java/org/apache/solr/cli/ListDeployed.java b/solr/core/src/java/org/apache/solr/cli/PackageListDeployed.java similarity index 97% rename from solr/core/src/java/org/apache/solr/cli/ListDeployed.java rename to solr/core/src/java/org/apache/solr/cli/PackageListDeployed.java index 1303502e70c0..944fce6591b0 100644 --- a/solr/core/src/java/org/apache/solr/cli/ListDeployed.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageListDeployed.java @@ -38,7 +38,7 @@ " # List collections where a package is deployed", " bin/solr package list-deployed mypkg" }) -public class ListDeployed extends PackageSubCommand { +public class PackageListDeployed extends PackageSubCommand { @picocli.CommandLine.Option( names = {"-c", "--collection"}, diff --git a/solr/core/src/java/org/apache/solr/cli/ListInstalled.java b/solr/core/src/java/org/apache/solr/cli/PackageListInstalled.java similarity index 96% rename from solr/core/src/java/org/apache/solr/cli/ListInstalled.java rename to solr/core/src/java/org/apache/solr/cli/PackageListInstalled.java index ec936a0331d3..e1d62b26d956 100644 --- a/solr/core/src/java/org/apache/solr/cli/ListInstalled.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageListInstalled.java @@ -32,7 +32,7 @@ " # List all installed packages", " bin/solr package list-installed", }) -public class ListInstalled extends PackageSubCommand { +public class PackageListInstalled extends PackageSubCommand { @Override public int callTool() throws Exception { diff --git a/solr/core/src/java/org/apache/solr/cli/PackageTool.java b/solr/core/src/java/org/apache/solr/cli/PackageTool.java index 2040cc591392..d8e130004071 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageTool.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageTool.java @@ -63,15 +63,15 @@ }, footerHeading = "%nExamples:%n", subcommands = { - AddRepo.class, - AddKey.class, - ListInstalled.class, - ListAvailable.class, - ListDeployed.class, + PackageAddRepo.class, + PackageAddKey.class, + PackageListInstalled.class, + PackageListAvailable.class, + PackageListDeployed.class, Install.class, - Deploy.class, - Undeploy.class, - Uninstall.class + PackageDeploy.class, + PackageUndeploy.class, + PackageUninstall.class }, footer = { " # Add a package repository", @@ -488,12 +488,12 @@ public String getHeader() { format(sb, ""); formatGreen( sb, "bin/solr package undeploy --collections "); - format(sb, "Undeploy a package from specified collection(s)"); + format(sb, "PackageUndeploy a package from specified collection(s)"); format(sb, ""); formatGreen(sb, "bin/solr package uninstall :"); format( sb, - "Uninstall an unused package with specified version from Solr. Both package name and version are required."); + "PackageUninstall an unused package with specified version from Solr. Both package name and version are required."); format(sb, "\n"); format( sb, diff --git a/solr/core/src/java/org/apache/solr/cli/Undeploy.java b/solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java similarity index 92% rename from solr/core/src/java/org/apache/solr/cli/Undeploy.java rename to solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java index 7c1939aa6f7e..2af04a8903b7 100644 --- a/solr/core/src/java/org/apache/solr/cli/Undeploy.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java @@ -23,7 +23,7 @@ @SuppressWarnings("UnnecessarilyFullyQualified") @picocli.CommandLine.Command( name = "undeploy", - description = "Undeploy a package from specified collection(s) or at cluster level.", + description = "PackageUndeploy a package from specified collection(s) or at cluster level.", exitCodeListHeading = "%nExit Codes:%n", exitCodeList = { "0: Operation completed successfully.", @@ -31,10 +31,10 @@ }, footerHeading = "%nExamples:%n", footer = { - " # Undeploy a package from a collection", + " # PackageUndeploy a package from a collection", " bin/solr package undeploy mypkg --collections myCollection" }) -public class Undeploy extends PackageSubCommand { +public class PackageUndeploy extends PackageSubCommand { @picocli.CommandLine.Parameters( index = "0", diff --git a/solr/core/src/java/org/apache/solr/cli/Uninstall.java b/solr/core/src/java/org/apache/solr/cli/PackageUninstall.java similarity index 89% rename from solr/core/src/java/org/apache/solr/cli/Uninstall.java rename to solr/core/src/java/org/apache/solr/cli/PackageUninstall.java index 0a45b0ba76cd..21a1775509c1 100644 --- a/solr/core/src/java/org/apache/solr/cli/Uninstall.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageUninstall.java @@ -21,7 +21,7 @@ @SuppressWarnings("UnnecessarilyFullyQualified") @picocli.CommandLine.Command( name = "uninstall", - description = "Uninstall any package with a specified version from Solr.", + description = "PackageUninstall any package with a specified version from Solr.", exitCodeListHeading = "%nExit Codes:%n", exitCodeList = { "0: Operation completed successfully.", @@ -29,10 +29,10 @@ }, footerHeading = "%nExamples:%n", footer = { - " # Uninstall a specific package version", + " # PackageUninstall a specific package version", " bin/solr package uninstall mypkg:1.0.0", }) -public class Uninstall extends PackageSubCommand { +public class PackageUninstall extends PackageSubCommand { @picocli.CommandLine.Parameters( index = "0", diff --git a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java index b8c38274f8d1..41b1e7fb2bd7 100644 --- a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java +++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java @@ -124,7 +124,7 @@ public void uninstall(String packageName, String version) + packageName + " is currently deployed on collection: " + collection - + ". Undeploy the package with undeploy --collections [,,...] before attempting to uninstall the package."); + + ". PackageUndeploy the package with undeploy --collections [,,...] before attempting to uninstall the package."); runtime.exit(1); } } @@ -141,7 +141,7 @@ public void uninstall(String packageName, String version) + packageName + "is currently deployed as a cluster-level plugin (" + clusterPackageInstance.getCustomData() - + "). Undeploy the package with undeploy --collections [,,...] before uninstalling the package."); + + "). PackageUndeploy the package with undeploy --collections [,,...] before uninstalling the package."); runtime.exit(1); } } @@ -969,7 +969,7 @@ public void undeploy( throws SolrException { ensureCollectionsExist(Arrays.asList(collections)); - // Undeploy cluster level plugins + // PackageUndeploy cluster level plugins if (shouldUndeployClusterPlugins) { SolrPackageInstance deployedPackage = getPackagesDeployedAsClusterLevelPlugins().get(packageName); @@ -1016,7 +1016,7 @@ public void undeploy( } } } - // Undeploy collection level plugins + // PackageUndeploy collection level plugins for (String collection : collections) { SolrPackageInstance deployedPackage = getPackagesDeployed(collection).get(packageName); if (deployedPackage == null) { diff --git a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java index 557ea5d1d345..4c5ccbce497d 100644 --- a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java +++ b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java @@ -392,7 +392,7 @@ public void testDeployValidationMessages() throws Exception { captureRuntime.clearOutput(); - // Undeploy of a package that was never deployed should give a clear message. + // PackageUndeploy of a package that was never deployed should give a clear message. runTool( new String[] { "--solr-url", From ace4dc6773e7e88f91910a94254ef57fbde3d561 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 01:47:11 +0530 Subject: [PATCH 08/17] minor --- solr/core/src/java/org/apache/solr/cli/PackageTool.java | 4 ++-- .../org/apache/solr/packagemanager/PackageManager.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cli/PackageTool.java b/solr/core/src/java/org/apache/solr/cli/PackageTool.java index d8e130004071..d64fc286a872 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageTool.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageTool.java @@ -488,12 +488,12 @@ public String getHeader() { format(sb, ""); formatGreen( sb, "bin/solr package undeploy --collections "); - format(sb, "PackageUndeploy a package from specified collection(s)"); + format(sb, "Undeploy a package from specified collection(s)"); format(sb, ""); formatGreen(sb, "bin/solr package uninstall :"); format( sb, - "PackageUninstall an unused package with specified version from Solr. Both package name and version are required."); + "Uninstall an unused package with specified version from Solr. Both package name and version are required."); format(sb, "\n"); format( sb, diff --git a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java index 41b1e7fb2bd7..b8c38274f8d1 100644 --- a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java +++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java @@ -124,7 +124,7 @@ public void uninstall(String packageName, String version) + packageName + " is currently deployed on collection: " + collection - + ". PackageUndeploy the package with undeploy --collections [,,...] before attempting to uninstall the package."); + + ". Undeploy the package with undeploy --collections [,,...] before attempting to uninstall the package."); runtime.exit(1); } } @@ -141,7 +141,7 @@ public void uninstall(String packageName, String version) + packageName + "is currently deployed as a cluster-level plugin (" + clusterPackageInstance.getCustomData() - + "). PackageUndeploy the package with undeploy --collections [,,...] before uninstalling the package."); + + "). Undeploy the package with undeploy --collections [,,...] before uninstalling the package."); runtime.exit(1); } } @@ -969,7 +969,7 @@ public void undeploy( throws SolrException { ensureCollectionsExist(Arrays.asList(collections)); - // PackageUndeploy cluster level plugins + // Undeploy cluster level plugins if (shouldUndeployClusterPlugins) { SolrPackageInstance deployedPackage = getPackagesDeployedAsClusterLevelPlugins().get(packageName); @@ -1016,7 +1016,7 @@ public void undeploy( } } } - // PackageUndeploy collection level plugins + // Undeploy collection level plugins for (String collection : collections) { SolrPackageInstance deployedPackage = getPackagesDeployed(collection).get(packageName); if (deployedPackage == null) { From 8617db07348f041d822359c3d9f4ccff683480ae Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 01:49:09 +0530 Subject: [PATCH 09/17] pr comments --- .../org/apache/solr/cli/{Install.java => PackageInstall.java} | 2 +- solr/core/src/java/org/apache/solr/cli/PackageTool.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename solr/core/src/java/org/apache/solr/cli/{Install.java => PackageInstall.java} (97%) diff --git a/solr/core/src/java/org/apache/solr/cli/Install.java b/solr/core/src/java/org/apache/solr/cli/PackageInstall.java similarity index 97% rename from solr/core/src/java/org/apache/solr/cli/Install.java rename to solr/core/src/java/org/apache/solr/cli/PackageInstall.java index 1e38f7d67cd4..b48c65f4a120 100644 --- a/solr/core/src/java/org/apache/solr/cli/Install.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageInstall.java @@ -35,7 +35,7 @@ " # Install the latest available version", " bin/solr package install mypkg" }) -public class Install extends PackageSubCommand { +public class PackageInstall extends PackageSubCommand { @picocli.CommandLine.Parameters( index = "0", diff --git a/solr/core/src/java/org/apache/solr/cli/PackageTool.java b/solr/core/src/java/org/apache/solr/cli/PackageTool.java index d64fc286a872..5e7ebe39a9d6 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageTool.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageTool.java @@ -68,7 +68,7 @@ PackageListInstalled.class, PackageListAvailable.class, PackageListDeployed.class, - Install.class, + PackageInstall.class, PackageDeploy.class, PackageUndeploy.class, PackageUninstall.class From 5fdef46f8cb34c05315ecc967b399eaf870a8c84 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 01:56:04 +0530 Subject: [PATCH 10/17] fixed --- solr/core/src/java/org/apache/solr/cli/PackageDeploy.java | 4 ++-- solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java | 4 ++-- solr/core/src/java/org/apache/solr/cli/PackageUninstall.java | 4 ++-- solr/core/src/test/org/apache/solr/cli/PackageToolTest.java | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cli/PackageDeploy.java b/solr/core/src/java/org/apache/solr/cli/PackageDeploy.java index ea4ee59b1252..ff24a7a1692d 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageDeploy.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageDeploy.java @@ -23,7 +23,7 @@ @SuppressWarnings("UnnecessarilyFullyQualified") @picocli.CommandLine.Command( name = "deploy", - description = "PackageDeploy an installed package to collections or at cluster level.", + description = "Deploy an installed package to collections or at cluster level.", exitCodeListHeading = "%nExit Codes:%n", exitCodeList = { "0: Operation completed successfully.", @@ -31,7 +31,7 @@ }, footerHeading = "%nExamples:%n", footer = { - " # PackageDeploy a package to a collection", + " # Deploy a package to a collection", " bin/solr package deploy mypkg:1.0.0 --collections myCollection -y", "", " # Update an existing deployment", diff --git a/solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java b/solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java index 2af04a8903b7..d38da3404070 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageUndeploy.java @@ -23,7 +23,7 @@ @SuppressWarnings("UnnecessarilyFullyQualified") @picocli.CommandLine.Command( name = "undeploy", - description = "PackageUndeploy a package from specified collection(s) or at cluster level.", + description = "Undeploy a package from specified collection(s) or at cluster level.", exitCodeListHeading = "%nExit Codes:%n", exitCodeList = { "0: Operation completed successfully.", @@ -31,7 +31,7 @@ }, footerHeading = "%nExamples:%n", footer = { - " # PackageUndeploy a package from a collection", + " # Undeploy a package from a collection", " bin/solr package undeploy mypkg --collections myCollection" }) public class PackageUndeploy extends PackageSubCommand { diff --git a/solr/core/src/java/org/apache/solr/cli/PackageUninstall.java b/solr/core/src/java/org/apache/solr/cli/PackageUninstall.java index 21a1775509c1..0171ec552b38 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageUninstall.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageUninstall.java @@ -21,7 +21,7 @@ @SuppressWarnings("UnnecessarilyFullyQualified") @picocli.CommandLine.Command( name = "uninstall", - description = "PackageUninstall any package with a specified version from Solr.", + description = "Uninstall any package with a specified version from Solr.", exitCodeListHeading = "%nExit Codes:%n", exitCodeList = { "0: Operation completed successfully.", @@ -29,7 +29,7 @@ }, footerHeading = "%nExamples:%n", footer = { - " # PackageUninstall a specific package version", + " # Uninstall a specific package version", " bin/solr package uninstall mypkg:1.0.0", }) public class PackageUninstall extends PackageSubCommand { diff --git a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java index 4c5ccbce497d..557ea5d1d345 100644 --- a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java +++ b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java @@ -392,7 +392,7 @@ public void testDeployValidationMessages() throws Exception { captureRuntime.clearOutput(); - // PackageUndeploy of a package that was never deployed should give a clear message. + // Undeploy of a package that was never deployed should give a clear message. runTool( new String[] { "--solr-url", From cc5f61da1ed83aa0e8653489002cc8677e34cd9d Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Wed, 7 Oct 2026 02:02:03 +0530 Subject: [PATCH 11/17] nit --- .../java/org/apache/solr/cli/PackageSubCommand.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java index 2324892fe93c..9b8130227af1 100644 --- a/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java +++ b/solr/core/src/java/org/apache/solr/cli/PackageSubCommand.java @@ -20,11 +20,9 @@ import org.apache.commons.cli.CommandLine; import org.apache.solr.packagemanager.PackageManager; import org.apache.solr.packagemanager.RepositoryManager; -import picocli.CommandLine.ArgGroup; -import picocli.CommandLine.Mixin; -import picocli.CommandLine.ParentCommand; /** Shared picocli wiring for {@code bin/solr package leaves} */ +@SuppressWarnings("UnnecessarilyFullyQualified") abstract class PackageSubCommand extends ToolBase { @FunctionalInterface @@ -32,11 +30,11 @@ interface PackageAction { void run(PackageManager packageManager, RepositoryManager repositoryManager) throws Exception; } - @ParentCommand PackageTool packageTool; + @picocli.CommandLine.ParentCommand PackageTool packageTool; - @Mixin CredentialsOptions credentialsOptions; + @picocli.CommandLine.Mixin CredentialsOptions credentialsOptions; - @ArgGroup(exclusive = true, multiplicity = "0..1") + @picocli.CommandLine.ArgGroup(exclusive = true, multiplicity = "0..1") ConnectionOptions connectionOptions; PackageSubCommand() { From 7fcf9fb83d0f43ffd4e3ed27eb69a4c08f7dced2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 7 Oct 2026 20:04:59 +0200 Subject: [PATCH 12/17] CLI: Use the solr.connection sysprop key for SOLR_CONNECTION fallback Main renamed the key from 'solr-connection' to 'solr.connection' in #5054; EnvUtils maps SOLR_FOO -> solr.foo, so the hyphenated key was never set. --- solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java b/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java index b17518a3e647..d7c06c2c6cf6 100644 --- a/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java +++ b/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java @@ -91,7 +91,7 @@ static String resolveSolrUrl(ConnectionOptions connectionOptions, String credent } } - String solrConnectionProp = EnvUtils.getProperty("solr-connection"); + String solrConnectionProp = EnvUtils.getProperty("solr.connection"); if (solrConnectionProp != null && !solrConnectionProp.isBlank()) { var connection = CloudSolrClient.CloudSolrClientConnection.parse(solrConnectionProp); if (connection.isZookeeper()) { @@ -123,7 +123,7 @@ static String resolveZkHost( } } - String solrConnectionProp = EnvUtils.getProperty("solr-connection"); + String solrConnectionProp = EnvUtils.getProperty("solr.connection"); if (solrConnectionProp != null && !solrConnectionProp.isBlank()) { var connection = CloudSolrClient.CloudSolrClientConnection.parse(solrConnectionProp); if (connection.isZookeeper()) { From c38aae984f83cd7dd1e8806b1b97619d80b86205 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Thu, 8 Oct 2026 17:36:03 +0530 Subject: [PATCH 13/17] copilo cuggestion --- .../apache/solr/cli/ConnectionOptions.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java b/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java index d7c06c2c6cf6..57ee0532faaa 100644 --- a/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java +++ b/solr/core/src/java/org/apache/solr/cli/ConnectionOptions.java @@ -116,24 +116,28 @@ static String resolveSolrUrl(ConnectionOptions connectionOptions, String credent static String resolveZkHost( ConnectionOptions connectionOptions, String solrUrl, String credentials) throws Exception { + boolean resolveFromSolrUrl = false; if (connectionOptions != null) { String zkHost = connectionOptions.effectiveZkHost(); if (zkHost != null) { return zkHost; } + resolveFromSolrUrl = connectionOptions.effectiveSolrUrl() != null; } - String solrConnectionProp = EnvUtils.getProperty("solr.connection"); - if (solrConnectionProp != null && !solrConnectionProp.isBlank()) { - var connection = CloudSolrClient.CloudSolrClientConnection.parse(solrConnectionProp); - if (connection.isZookeeper()) { - return solrConnectionProp; + if (!resolveFromSolrUrl) { + String solrConnectionProp = EnvUtils.getProperty("solr.connection"); + if (solrConnectionProp != null && !solrConnectionProp.isBlank()) { + var connection = CloudSolrClient.CloudSolrClientConnection.parse(solrConnectionProp); + if (connection.isZookeeper()) { + return solrConnectionProp; + } } - } - String zkHostProp = EnvUtils.getProperty("zkHost"); - if (zkHostProp != null && !zkHostProp.isBlank()) { - return zkHostProp; + String zkHostProp = EnvUtils.getProperty("zkHost"); + if (zkHostProp != null && !zkHostProp.isBlank()) { + return zkHostProp; + } } try (SolrClient solrClient = CLIUtils.getSolrClient(solrUrl, credentials)) { From e31cd75f6f572e8be615563cb8388ce404c6834e Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Thu, 8 Oct 2026 17:42:22 +0530 Subject: [PATCH 14/17] tests --- .../solr/cli/ConnectionOptionsTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 solr/core/src/test/org/apache/solr/cli/ConnectionOptionsTest.java diff --git a/solr/core/src/test/org/apache/solr/cli/ConnectionOptionsTest.java b/solr/core/src/test/org/apache/solr/cli/ConnectionOptionsTest.java new file mode 100644 index 000000000000..c5b794c1f24d --- /dev/null +++ b/solr/core/src/test/org/apache/solr/cli/ConnectionOptionsTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.solr.cli; + +import org.apache.solr.cloud.SolrCloudTestCase; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ConnectionOptionsTest extends SolrCloudTestCase { + + @BeforeClass + public static void setupCluster() throws Exception { + configureCluster(1).configure(); + } + + @Test + public void testResolveZkHostIgnoresEnvWhenSolrUrlProvided() throws Exception { + String solrUrl = cluster.getJettySolrRunner(0).getBaseUrl().toString(); + + System.setProperty("zkHost", "other-cluster:2181/solr"); + System.setProperty("solr.connection", "other-cluster:2181/solr"); + + ConnectionOptions opts = new ConnectionOptions(); + opts.solrUrl = solrUrl; + + String resolved = ConnectionOptions.resolveZkHost(opts, solrUrl, null); + assertNotNull(resolved); + assertFalse( + "HTTP CLI target must not pick up a conflicting zkHost/sys property", + resolved.contains("other-cluster")); + } +} From 014d6e05bc7f941f30acbbf25d98408b96475f99 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Thu, 8 Oct 2026 17:51:03 +0530 Subject: [PATCH 15/17] common cl across the board --- .../unreleased/SOLR-17697-picocli-experimental-cli.yml | 4 ++++ changelog/unreleased/SOLR-18515-package-tool-picocli.yml | 9 --------- 2 files changed, 4 insertions(+), 9 deletions(-) delete mode 100644 changelog/unreleased/SOLR-18515-package-tool-picocli.yml diff --git a/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml b/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml index 85cdf1fd90d4..3725df990248 100644 --- a/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml +++ b/changelog/unreleased/SOLR-17697-picocli-experimental-cli.yml @@ -7,6 +7,10 @@ type: added authors: - name: Jan Høydahl url: https://home.apache.org/phonebook.html?uid=janhoy + - name: Jalaz Kumar + nick: jaykay12 links: - name: SOLR-17697 url: https://issues.apache.org/jira/browse/SOLR-17697 + - name: SOLR-18515 + url: https://issues.apache.org/jira/browse/SOLR-18515 diff --git a/changelog/unreleased/SOLR-18515-package-tool-picocli.yml b/changelog/unreleased/SOLR-18515-package-tool-picocli.yml deleted file mode 100644 index d8b4b7d7e940..000000000000 --- a/changelog/unreleased/SOLR-18515-package-tool-picocli.yml +++ /dev/null @@ -1,9 +0,0 @@ -title: - Implement PicoCLI for package command / PackageTool -type: changed -authors: - - name: Jalaz Kumar - nick: jaykay12 -links: - - name: SOLR-18515 - url: https://issues.apache.org/jira/browse/SOLR-18515 From 3ca62e67c71db9b7014812fc3ff90f8ee187b752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 8 Oct 2026 20:35:23 +0200 Subject: [PATCH 16/17] Make package version sync wait for an in-flight refresh A node answering a /cluster/package?expectedVersion=N request could report itself in sync as soon as its ZK watcher had bumped the packages.json version, while that watcher thread was still building the classloader for the new version and reloading plugins. A client that installed a new version and then verified collections pegged to $LATEST could therefore observe the old version. Only the exit code of the commons-cli package tool hid this, since it ignored the install result; the picocli port propagates it. Make SolrPackageLoader.refreshPackageConf() and notifyListeners() synchronized and have syncToVersion always go through refreshPackageConf(), so both the version sync and the explicit refresh command block until any in-flight application of the new packages.json has completed. --- solr/core/src/java/org/apache/solr/pkg/PackageAPI.java | 6 ++---- .../src/java/org/apache/solr/pkg/SolrPackageLoader.java | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java index 0fd1e29dc4a9..4574f7b3318f 100644 --- a/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java +++ b/solr/core/src/java/org/apache/solr/pkg/PackageAPI.java @@ -407,13 +407,11 @@ public void get(SolrQueryRequest req, SolrQueryResponse rsp) { } private void syncToVersion(int expectedVersion) { - int origVersion = pkgs.znodeVersion; for (int i = 0; i < 10; i++) { log.debug("my version is {} , and expected version {}", pkgs.znodeVersion, expectedVersion); if (pkgs.znodeVersion >= expectedVersion) { - if (origVersion < pkgs.znodeVersion) { - packageLoader.refreshPackageConf(); - } + // Blocks until any in-flight refresh started by the ZK watcher has been applied + packageLoader.refreshPackageConf(); return; } try { diff --git a/solr/core/src/java/org/apache/solr/pkg/SolrPackageLoader.java b/solr/core/src/java/org/apache/solr/pkg/SolrPackageLoader.java index 34f6b136eb6c..a512fe77914e 100644 --- a/solr/core/src/java/org/apache/solr/pkg/SolrPackageLoader.java +++ b/solr/core/src/java/org/apache/solr/pkg/SolrPackageLoader.java @@ -80,7 +80,7 @@ public Map getPackages() { return Map.of(); } - public void refreshPackageConf() { + public synchronized void refreshPackageConf() { log.debug( "{} updated to version {}", ZkStateReader.SOLR_PKGS_PATH, packageAPI.pkgs.znodeVersion); @@ -139,7 +139,7 @@ public Map> getModified( return changed; } - public void notifyListeners(String pkg) { + public synchronized void notifyListeners(String pkg) { SolrPackage p = packageClassLoaders.get(pkg); if (p != null) { List l = List.of(p); From 7ee9561c11c2cfc068296f42f904bd3a14135e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 8 Oct 2026 20:44:55 +0200 Subject: [PATCH 17/17] PackageToolTest: give validation-test its own configset testDeployValidationMessages created validation-test on conf1, shared with abc, so a deploy to abc also showed up as a deployment on validation-test through the shared PKG_VERSIONS params. Use a dedicated configset so the two test methods do not influence each other. --- solr/core/src/test/org/apache/solr/cli/PackageToolTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java index 557ea5d1d345..a919b30555b7 100644 --- a/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java +++ b/solr/core/src/test/org/apache/solr/cli/PackageToolTest.java @@ -68,6 +68,9 @@ public static void setupClusterWithSecurityEnabled() throws Exception { "conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf")) .addConfig( "conf3", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf")) + .addConfig( + "conf-validation", + TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf")) .withSecurityJson(SecurityJson.SIMPLE) .configure(); @@ -364,7 +367,8 @@ public static void testForResponseElement( public void testDeployValidationMessages() throws Exception { String solrUrl = cluster.getJettySolrRunner(0).getBaseUrl().toString(); - withBasicAuth(CollectionAdminRequest.createCollection("validation-test", "conf1", 1, 1)) + withBasicAuth( + CollectionAdminRequest.createCollection("validation-test", "conf-validation", 1, 1)) .processAndWait(cluster.getSolrClient(), 10); CLITestHelper.TestingRuntime captureRuntime = new CLITestHelper.TestingRuntime(true);