Skip to content

Commit 9136581

Browse files
authored
Merge pull request #447 from dmlloyd/batch-again
Hide Windows batch argument escaping behind an option
2 parents 7b61582 + bfa7eb9 commit 9136581

File tree

6 files changed

+58
-9
lines changed

6 files changed

+58
-9
lines changed

process/src/main/java/io/smallrye/common/process/ArgumentRule.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ void checkArguments(final List<String> arguments) throws IllegalArgumentExceptio
1414
// no operation (accepts any)
1515
}
1616

17-
List<String> formatArguments(final Path command, final List<String> arguments) throws IllegalArgumentException {
17+
List<String> formatArguments(final Path command, final List<String> arguments, final boolean specialQuoting)
18+
throws IllegalArgumentException {
1819
return Stream.concat(Stream.of(command.toString()), arguments.stream()).toList();
1920
}
2021
},
@@ -42,13 +43,19 @@ void checkArguments(final List<String> arguments) throws IllegalArgumentExceptio
4243
}
4344
}
4445

45-
List<String> formatArguments(final Path command, final List<String> arguments) throws IllegalArgumentException {
46+
List<String> formatArguments(final Path command, final List<String> arguments, final boolean specialQuoting)
47+
throws IllegalArgumentException {
4648
// in the future, this will be replaced with a variation which has extra quoting capabilities
4749
ArrayList<String> list = new ArrayList<>(arguments.size() + 5);
48-
StringBuilder sb = new StringBuilder();
49-
list.add(quote(command.toString(), sb));
50-
for (final String argument : arguments) {
51-
list.add(quote(argument, sb));
50+
if (specialQuoting) {
51+
StringBuilder sb = new StringBuilder();
52+
list.add(quote(command.toString(), sb));
53+
for (final String argument : arguments) {
54+
list.add(quote(argument, sb));
55+
}
56+
} else {
57+
list.add(command.toString());
58+
list.addAll(arguments);
5259
}
5360
return list;
5461
}
@@ -89,7 +96,8 @@ void checkArguments(final List<String> arguments) throws IllegalArgumentExceptio
8996
// OK
9097
}
9198

92-
List<String> formatArguments(final Path command, final List<String> arguments) throws IllegalArgumentException {
99+
List<String> formatArguments(final Path command, final List<String> arguments, final boolean specialQuoting)
100+
throws IllegalArgumentException {
93101
return Stream.concat(
94102
Stream.of("powershell.exe", "-ExecutionPolicy", "Bypass", "-File", command.toString()),
95103
arguments.stream()).toList();
@@ -103,5 +111,6 @@ IllegalArgumentException invalidCharacter(final String argument, final int idx)
103111

104112
abstract void checkArguments(List<String> arguments) throws IllegalArgumentException;
105113

106-
abstract List<String> formatArguments(Path command, List<String> arguments) throws IllegalArgumentException;
114+
abstract List<String> formatArguments(Path command, List<String> arguments, boolean specialQuoting)
115+
throws IllegalArgumentException;
107116
}

process/src/main/java/io/smallrye/common/process/PipelineBuilder.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ public sealed interface PipelineBuilder<O> permits PipelineBuilder.Error, Pipeli
4444
*/
4545
PipelineBuilder<O> arguments(String... command);
4646

47+
/**
48+
* Enable special quoting for batch scripts on Windows.
49+
* Note that this requires the batch script to use a specific form
50+
* of argument expansion.
51+
*
52+
* @param specialQuoting {@code true} to enable special quoting, or {@code false} to use default quoting
53+
* @return this builder
54+
*/
55+
PipelineBuilder<O> specialQuoting(boolean specialQuoting);
56+
4757
/**
4858
* Set the working directory for this process execution.
4959
*

process/src/main/java/io/smallrye/common/process/PipelineRunner.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,8 @@ ProcessExecutionException newProcessException(String message) {
597597
int createThreads(final ThreadFactory tf, final ProcessRunner<O> runner, final PipelineRunner<O> nextRunner)
598598
throws IOException {
599599
pb = processBuilder.pb;
600-
pb.command(processBuilder.argumentRule.formatArguments(processBuilder.command, processBuilder.arguments));
600+
pb.command(processBuilder.argumentRule.formatArguments(processBuilder.command, processBuilder.arguments,
601+
processBuilder.specialQuoting));
601602
pb.directory(processBuilder.directory);
602603
int cnt = createInputThread(tf, runner)
603604
+ createErrorThreads(tf, runner)

process/src/main/java/io/smallrye/common/process/ProcessBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,9 @@ default ProcessBuilder<O> arguments(String... command) {
347347
return arguments(List.of(command));
348348
}
349349

350+
@Override
351+
ProcessBuilder<O> specialQuoting(boolean specialQuoting);
352+
350353
@Override
351354
ProcessBuilder<O> directory(Path directory);
352355

process/src/main/java/io/smallrye/common/process/ProcessBuilderImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ final class ProcessBuilderImpl<O> implements ProcessBuilder<O> {
5757
final Path command;
5858
final ArgumentRule argumentRule;
5959
File directory;
60+
boolean specialQuoting;
6061
private volatile boolean locked;
6162
List<String> arguments = List.of();
6263
IntPredicate exitCodeChecker = e -> e == 0;
@@ -120,6 +121,11 @@ public ProcessBuilder<O> arguments(final List<String> arguments) {
120121
return this;
121122
}
122123

124+
public ProcessBuilder<O> specialQuoting(final boolean specialQuoting) {
125+
this.specialQuoting = specialQuoting;
126+
return this;
127+
}
128+
123129
public ProcessBuilder<O> directory(final Path directory) {
124130
check();
125131
this.directory = Assert.checkNotNullParam("directory", directory).toFile();
@@ -234,6 +240,10 @@ public ProcessBuilder<O> arguments(final List<String> command) {
234240
return ProcessBuilderImpl.this.arguments(command);
235241
}
236242

243+
public ProcessBuilder<O> specialQuoting(final boolean specialQuoting) {
244+
return ProcessBuilderImpl.this.specialQuoting(specialQuoting);
245+
}
246+
237247
public ProcessBuilder<O> directory(final Path directory) {
238248
return ProcessBuilderImpl.this.directory(directory);
239249
}

process/src/test/java/io/smallrye/common/process/WindowsSpecificTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,34 @@ public void testBatchArguments() throws Exception {
3333
assertEquals(List.of("hello", "world"), output);
3434

3535
output = ProcessBuilder.newBuilder(findScript("batch/echo_2_args.cmd"))
36+
.specialQuoting(true)
37+
.arguments("--foo=bar", "--foo bar")
38+
.output().toStringList(16, 1024)
39+
.run();
40+
assertEquals(List.of("--foo=bar", "--foo bar"), output);
41+
42+
output = ProcessBuilder.newBuilder(findScript("batch/echo_2_args.cmd"))
43+
.arguments("--foo=bar", "--foo bar")
44+
.output().toStringList(16, 1024)
45+
.run();
46+
assertEquals(List.of("--foo", "bar"), output);
47+
48+
output = ProcessBuilder.newBuilder(findScript("batch/echo_2_args.cmd"))
49+
.specialQuoting(true)
3650
.arguments("with spaces", "with ^ caret")
3751
.output().toStringList(16, 1024)
3852
.run();
3953
assertEquals(List.of("with spaces", "with ^ caret"), output);
4054

4155
output = ProcessBuilder.newBuilder(findScript("batch/echo_2_args.cmd"))
56+
.specialQuoting(true)
4257
.arguments("\"withQuotes\"", "\"quotes and spaces\"")
4358
.output().toStringList(16, 1024)
4459
.run();
4560
assertEquals(List.of("withQuotes", "quotes and spaces"), output);
4661

4762
output = ProcessBuilder.newBuilder(findScript("batch/echo_2_args.cmd"))
63+
.specialQuoting(true)
4864
.arguments("\"with \"interior\" quotes\"", "it works!")
4965
.output().toStringList(16, 1024)
5066
.run();

0 commit comments

Comments
 (0)