Skip to content

Commit 04ca619

Browse files
committed
Add in --prompts capablity. Its so lovely!
1 parent f5da9a6 commit 04ca619

File tree

3 files changed

+211
-4
lines changed

3 files changed

+211
-4
lines changed

solr/bin/solr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,14 @@ if [ $# -gt 0 ]; then
817817
PASS_TO_RUN_EXAMPLE+=("--no-prompt")
818818
shift
819819
;;
820+
--prompts)
821+
if [[ -z "$2" || "${2:0:1}" == "-" ]]; then
822+
print_usage "$SCRIPT_CMD" "Prompt values are required when using the $1 option!"
823+
exit 1
824+
fi
825+
PASS_TO_RUN_EXAMPLE+=("--prompts" "$2")
826+
shift 2
827+
;;
820828
--verbose)
821829
verbose=true
822830
SOLR_LOG_LEVEL=DEBUG

solr/core/src/java/org/apache/solr/cli/RunExampleTool.java

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ public class RunExampleTool extends ToolBase {
7373
"Don't prompt for input; accept all defaults when running examples that accept user input.")
7474
.build();
7575

76+
private static final Option PROMPTS_OPTION =
77+
Option.builder()
78+
.longOpt("prompts")
79+
.hasArg()
80+
.argName("VALUES")
81+
.desc(
82+
"Provide comma-separated values for prompts. Same as --no-prompt but uses provided values instead of defaults. "
83+
+ "Example: --prompts 3,8983,8984,8985,\"gettingstarted\",2,2,_default")
84+
.build();
85+
7686
private static final Option EXAMPLE_OPTION =
7787
Option.builder("e")
7888
.longOpt("example")
@@ -176,6 +186,7 @@ public class RunExampleTool extends ToolBase {
176186
protected Path exampleDir;
177187
protected Path solrHomeDir;
178188
protected String urlScheme;
189+
private boolean usingPrompts = false;
179190

180191
/** Default constructor used by the framework when running as a command-line application. */
181192
public RunExampleTool(ToolRuntime runtime) {
@@ -197,6 +208,7 @@ public String getName() {
197208
public Options getOptions() {
198209
return super.getOptions()
199210
.addOption(NO_PROMPT_OPTION)
211+
.addOption(PROMPTS_OPTION)
200212
.addOption(EXAMPLE_OPTION)
201213
.addOption(SCRIPT_OPTION)
202214
.addOption(SERVER_DIR_OPTION)
@@ -214,6 +226,13 @@ public Options getOptions() {
214226

215227
@Override
216228
public void runImpl(CommandLine cli) throws Exception {
229+
// Validate that --no-prompt and --prompts are not used together
230+
if (cli.hasOption(NO_PROMPT_OPTION) && cli.hasOption(PROMPTS_OPTION)) {
231+
throw new IllegalArgumentException(
232+
"Cannot use both --no-prompt and --prompts options together. "
233+
+ "Use --no-prompt to accept defaults, or --prompts to provide specific values.");
234+
}
235+
217236
this.urlScheme = cli.getOptionValue(URL_SCHEME_OPTION, "http");
218237
String exampleType = cli.getOptionValue(EXAMPLE_OPTION);
219238

@@ -515,6 +534,7 @@ protected void runExample(CommandLine cli, String exampleName) throws Exception
515534

516535
protected void runCloudExample(CommandLine cli) throws Exception {
517536

537+
usingPrompts = cli.hasOption(PROMPTS_OPTION);
518538
boolean prompt = !cli.hasOption(NO_PROMPT_OPTION);
519539
int numNodes = 2;
520540
int[] cloudPorts = new int[] {8983, 7574, 8984, 7575};
@@ -530,10 +550,24 @@ protected void runCloudExample(CommandLine cli) throws Exception {
530550

531551
echo("\nWelcome to the SolrCloud example!\n");
532552

533-
Scanner readInput = prompt ? new Scanner(userInput, StandardCharsets.UTF_8) : null;
553+
Scanner readInput = null;
554+
if (usingPrompts) {
555+
// Create a scanner from the provided prompts
556+
String promptsValue = cli.getOptionValue(PROMPTS_OPTION);
557+
InputStream promptsStream =
558+
new java.io.ByteArrayInputStream(promptsValue.getBytes(StandardCharsets.UTF_8));
559+
readInput = new Scanner(promptsStream, StandardCharsets.UTF_8);
560+
readInput.useDelimiter(",");
561+
prompt = true; // Enable prompting code path, but reading from prompts instead of user
562+
} else if (prompt) {
563+
readInput = new Scanner(userInput, StandardCharsets.UTF_8);
564+
}
565+
534566
if (prompt) {
535-
echo(
536-
"This interactive session will help you launch a SolrCloud cluster on your local workstation.");
567+
if (!usingPrompts) {
568+
echo(
569+
"This interactive session will help you launch a SolrCloud cluster on your local workstation.");
570+
}
537571

538572
// get the number of nodes to start
539573
numNodes =
@@ -1121,9 +1155,24 @@ protected String prompt(Scanner s, String prompt) {
11211155

11221156
protected String prompt(Scanner s, String prompt, String defaultValue) {
11231157
echo(prompt);
1124-
String nextInput = s.nextLine();
1158+
String nextInput;
1159+
if (usingPrompts) {
1160+
// Reading from prompts option - use next() instead of nextLine()
1161+
nextInput = s.hasNext() ? s.next() : null;
1162+
// Echo the value being used from prompts
1163+
if (nextInput != null) {
1164+
echo(nextInput);
1165+
}
1166+
} else {
1167+
// Reading from user input - use nextLine()
1168+
nextInput = s.nextLine();
1169+
}
11251170
if (nextInput != null) {
11261171
nextInput = nextInput.trim();
1172+
// Remove quotes if present (for values like "gettingstarted")
1173+
if (nextInput.startsWith("\"") && nextInput.endsWith("\"")) {
1174+
nextInput = nextInput.substring(1, nextInput.length() - 1);
1175+
}
11271176
if (nextInput.isEmpty()) nextInput = null;
11281177
}
11291178
return (nextInput != null) ? nextInput : defaultValue;

solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,156 @@ public void testInteractiveSolrCloudExample() throws Exception {
525525
executor.execute(org.apache.commons.exec.CommandLine.parse("bin/solr stop -p " + bindPort));
526526
}
527527

528+
/**
529+
* Test the --prompts option that allows providing all prompt values as a comma-separated string
530+
* without requiring interactive input.
531+
*/
532+
@Test
533+
public void testSolrCloudExampleWithPrompts() throws Exception {
534+
Path solrHomeDir = ExternalPaths.SERVER_HOME;
535+
if (!Files.isDirectory(solrHomeDir))
536+
fail(solrHomeDir + " not found and is required to run this test!");
537+
538+
Path solrExampleDir = createTempDir();
539+
Path solrServerDir = solrHomeDir.getParent();
540+
541+
int bindPort = -1;
542+
try (ServerSocket socket = new ServerSocket(0)) {
543+
bindPort = socket.getLocalPort();
544+
}
545+
546+
String collectionName = "testCloudExampleWithPrompts";
547+
548+
// Provide all prompt values via --prompts option:
549+
// numNodes, port1, collectionName, numShards, replicationFactor, configName
550+
String promptsValue = "1," + bindPort + ",\"" + collectionName + "\",2,2,_default";
551+
552+
String[] toolArgs =
553+
new String[] {
554+
"--example",
555+
"cloud",
556+
"--server-dir",
557+
solrServerDir.toString(),
558+
"--example-dir",
559+
solrExampleDir.toString(),
560+
"--prompts",
561+
promptsValue
562+
};
563+
564+
// capture tool output to stdout
565+
CLITestHelper.TestingRuntime runtime = new CLITestHelper.TestingRuntime(true);
566+
567+
RunExampleExecutor executor = new RunExampleExecutor();
568+
closeables.add(executor);
569+
570+
RunExampleTool tool = new RunExampleTool(executor, System.in, runtime);
571+
try {
572+
tool.runTool(SolrCLI.processCommandLineArgs(tool, toolArgs));
573+
} catch (Exception e) {
574+
System.err.println(
575+
"RunExampleTool failed due to: "
576+
+ e
577+
+ "; stdout from tool prior to failure: "
578+
+ runtime.getOutput());
579+
throw e;
580+
}
581+
582+
String toolOutput = runtime.getOutput();
583+
584+
// verify Solr is running on the expected port and verify the collection exists
585+
String solrUrl = "http://localhost:" + bindPort + "/solr";
586+
if (!CLIUtils.safeCheckCollectionExists(solrUrl, collectionName, null)) {
587+
fail(
588+
"After running Solr cloud example with --prompts, test collection '"
589+
+ collectionName
590+
+ "' not found in Solr at: "
591+
+ solrUrl
592+
+ "; tool output: "
593+
+ toolOutput);
594+
}
595+
596+
// verify the collection was created with the specified parameters
597+
try (CloudSolrClient cloudClient =
598+
new RandomizingCloudSolrClientBuilder(
599+
Collections.singletonList(executor.solrCloudCluster.getZkServer().getZkAddress()),
600+
Optional.empty())
601+
.withDefaultCollection(collectionName)
602+
.build()) {
603+
604+
// index some test docs to verify the collection works
605+
int numDocs = 5;
606+
for (int d = 0; d < numDocs; d++) {
607+
SolrInputDocument doc = new SolrInputDocument();
608+
doc.setField("id", "doc" + d);
609+
doc.setField("test_s", "prompts");
610+
cloudClient.add(doc);
611+
}
612+
cloudClient.commit();
613+
614+
QueryResponse qr = cloudClient.query(new SolrQuery("test_s:prompts"));
615+
assertEquals(
616+
"Expected "
617+
+ numDocs
618+
+ " docs in the "
619+
+ collectionName
620+
+ " collection created via --prompts",
621+
numDocs,
622+
qr.getResults().getNumFound());
623+
}
624+
625+
// Verify output contains the prompts values
626+
assertTrue(
627+
"Tool output should contain the collection name", toolOutput.contains(collectionName));
628+
629+
// delete the collection
630+
DeleteTool deleteTool = new DeleteTool(runtime);
631+
String[] deleteArgs = new String[] {"--name", collectionName, "--solr-url", solrUrl};
632+
deleteTool.runTool(SolrCLI.processCommandLineArgs(deleteTool, deleteArgs));
633+
634+
// stop the test instance
635+
executor.execute(org.apache.commons.exec.CommandLine.parse("bin/solr stop -p " + bindPort));
636+
}
637+
638+
/** Test that using both --no-prompt and --prompts options together throws an error. */
639+
@Test
640+
public void testPromptsAndNoPromptConflict() throws Exception {
641+
Path solrHomeDir = ExternalPaths.SERVER_HOME;
642+
if (!Files.isDirectory(solrHomeDir))
643+
fail(solrHomeDir + " not found and is required to run this test!");
644+
645+
Path solrExampleDir = createTempDir();
646+
Path solrServerDir = solrHomeDir.getParent();
647+
648+
String[] toolArgs =
649+
new String[] {
650+
"--example",
651+
"cloud",
652+
"--server-dir",
653+
solrServerDir.toString(),
654+
"--example-dir",
655+
solrExampleDir.toString(),
656+
"--no-prompt",
657+
"--prompts",
658+
"1,8983,\"test\",2,2,_default"
659+
};
660+
661+
CLITestHelper.TestingRuntime runtime = new CLITestHelper.TestingRuntime(true);
662+
RunExampleExecutor executor = new RunExampleExecutor();
663+
closeables.add(executor);
664+
665+
RunExampleTool tool = new RunExampleTool(executor, System.in, runtime);
666+
667+
int exitCode = 100; // Initialize to unexpected value
668+
try {
669+
exitCode = tool.runTool(SolrCLI.processCommandLineArgs(tool, toolArgs));
670+
} catch (Exception e) {
671+
fail("Should not throw exception, but return error code. Got: " + e);
672+
}
673+
674+
assertEquals(
675+
"Expected error code 1 when using both --no-prompt and --prompts together", 1, exitCode);
676+
}
677+
528678
@Test
529679
public void testFailExecuteScript() throws Exception {
530680
Path solrHomeDir = ExternalPaths.SERVER_HOME;

0 commit comments

Comments
 (0)