1 package org.codehaus.plexus.util.cli;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.Writer;
22 import java.nio.file.Files;
23
24 import org.codehaus.plexus.util.IOUtil;
25 import org.codehaus.plexus.util.Os;
26 import org.codehaus.plexus.util.StringUtils;
27 import org.codehaus.plexus.util.cli.shell.BourneShell;
28 import org.codehaus.plexus.util.cli.shell.CmdShell;
29 import org.codehaus.plexus.util.cli.shell.Shell;
30 import org.junit.jupiter.api.BeforeEach;
31 import org.junit.jupiter.api.Test;
32 import org.junit.jupiter.api.condition.DisabledOnOs;
33 import org.junit.jupiter.api.condition.OS;
34
35 import static org.junit.jupiter.api.Assertions.assertEquals;
36 import static org.junit.jupiter.api.Assertions.assertTrue;
37 import static org.junit.jupiter.api.Assertions.fail;
38
39
40
41
42
43
44
45 class CommandlineTest {
46 private String baseDir;
47
48 @BeforeEach
49 void setUp() throws Exception {
50 baseDir = System.getProperty("basedir");
51
52 if (baseDir == null) {
53 baseDir = new File(".").getCanonicalPath();
54 }
55 }
56
57 @SuppressWarnings("deprecation")
58 @Test
59 void commandlineWithoutCommandInConstructor() {
60 Commandline cmd = new Commandline(new Shell());
61 cmd.setWorkingDirectory(baseDir);
62 cmd.createArgument().setValue("cd");
63 cmd.createArgument().setValue(".");
64
65
66 assertEquals("cd .", cmd.toString());
67 }
68
69 @Test
70 void commandlineWithCommandInConstructor() {
71 Commandline cmd = new Commandline("cd .", new Shell());
72 cmd.setWorkingDirectory(baseDir);
73
74
75 assertEquals("cd .", cmd.toString());
76 }
77
78 @Test
79 void executeBinaryOnPath() throws Exception {
80
81 Commandline cmd = new Commandline();
82 cmd.setWorkingDirectory(baseDir);
83 cmd.setExecutable("mvn");
84 assertEquals("mvn", cmd.getShell().getOriginalExecutable());
85 cmd.createArg().setValue("-version");
86 Process process = cmd.execute();
87 String out = IOUtil.toString(process.getInputStream());
88 assertTrue(out.contains("Apache Maven"));
89 assertTrue(out.contains("Maven home:"));
90 assertTrue(out.contains("Java version:"));
91 }
92
93 @SuppressWarnings("deprecation")
94 @Test
95 void execute() throws Exception {
96
97 Commandline cmd = new Commandline();
98 cmd.setWorkingDirectory(baseDir);
99 cmd.setExecutable("echo");
100 assertEquals("echo", cmd.getShell().getOriginalExecutable());
101 cmd.createArgument().setValue("Hello");
102
103 Process process = cmd.execute();
104 assertEquals("Hello", IOUtil.toString(process.getInputStream()).trim());
105 }
106
107 @SuppressWarnings("deprecation")
108 @Test
109 void setLine() {
110 Commandline cmd = new Commandline(new Shell());
111 cmd.setWorkingDirectory(baseDir);
112 cmd.setExecutable("echo");
113 cmd.createArgument().setLine(null);
114 cmd.createArgument().setLine("Hello");
115
116
117 assertEquals("echo Hello", cmd.toString());
118 }
119
120 @SuppressWarnings("deprecation")
121 @Test
122 void createCommandInReverseOrder() {
123 Commandline cmd = new Commandline(new Shell());
124 cmd.setWorkingDirectory(baseDir);
125 cmd.createArgument().setValue(".");
126 cmd.createArgument(true).setValue("cd");
127
128
129 assertEquals("cd .", cmd.toString());
130 }
131
132 @SuppressWarnings("deprecation")
133 @Test
134 void setFile() {
135 Commandline cmd = new Commandline(new Shell());
136 cmd.setWorkingDirectory(baseDir);
137 cmd.createArgument().setValue("more");
138 File f = new File("test.txt");
139 cmd.createArgument().setFile(f);
140 String fileName = f.getAbsolutePath();
141 if (fileName.contains(" ")) {
142 fileName = "\"" + fileName + "\"";
143 }
144
145
146 assertEquals("more " + fileName, cmd.toString());
147 }
148
149 @Test
150 void getShellCommandLineWindows() {
151 Commandline cmd = new Commandline(new CmdShell());
152 cmd.setExecutable("c:\\Program Files\\xxx");
153 cmd.addArguments(new String[] {"a", "b"});
154 String[] shellCommandline = cmd.getShellCommandline();
155
156 assertEquals(5, shellCommandline.length, "Command line size");
157
158 assertEquals("cmd.exe", shellCommandline[0]);
159 assertEquals("/X", shellCommandline[1]);
160 assertEquals("/D", shellCommandline[2]);
161 assertEquals("/C", shellCommandline[3]);
162 String expectedShellCmd = "\"c:" + File.separator + "Program Files" + File.separator + "xxx\" a b";
163 expectedShellCmd = "\"" + expectedShellCmd + "\"";
164 assertEquals(expectedShellCmd, shellCommandline[4]);
165 }
166
167 @Test
168 void getShellCommandLineWindowsWithSeveralQuotes() {
169 Commandline cmd = new Commandline(new CmdShell());
170 cmd.setExecutable("c:\\Program Files\\xxx");
171 cmd.addArguments(new String[] {"c:\\Documents and Settings\\whatever", "b"});
172 String[] shellCommandline = cmd.getShellCommandline();
173
174 assertEquals(5, shellCommandline.length, "Command line size");
175
176 assertEquals("cmd.exe", shellCommandline[0]);
177 assertEquals("/X", shellCommandline[1]);
178 assertEquals("/D", shellCommandline[2]);
179 assertEquals("/C", shellCommandline[3]);
180 String expectedShellCmd = "\"c:" + File.separator + "Program Files" + File.separator
181 + "xxx\" \"c:\\Documents and Settings\\whatever\" b";
182 expectedShellCmd = "\"" + expectedShellCmd + "\"";
183 assertEquals(expectedShellCmd, shellCommandline[4]);
184 }
185
186
187
188
189 @Test
190 void getShellCommandLineBash() {
191 Commandline cmd = new Commandline(new BourneShell());
192 cmd.setExecutable("/bin/echo");
193 cmd.addArguments(new String[] {"hello world"});
194
195 String[] shellCommandline = cmd.getShellCommandline();
196
197 assertEquals(3, shellCommandline.length, "Command line size");
198
199 assertEquals("/bin/sh", shellCommandline[0]);
200 assertEquals("-c", shellCommandline[1]);
201 String expectedShellCmd = "'/bin/echo' 'hello world'";
202 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
203 expectedShellCmd = "'\\bin\\echo' 'hello world'";
204 }
205 assertEquals(expectedShellCmd, shellCommandline[2]);
206 }
207
208
209
210
211 @Test
212 void getShellCommandLineBashWithWorkingDirectory() {
213 Commandline cmd = new Commandline(new BourneShell());
214 cmd.setExecutable("/bin/echo");
215 cmd.addArguments(new String[] {"hello world"});
216 File root = File.listRoots()[0];
217 File workingDirectory = new File(root, "path with spaces");
218 cmd.setWorkingDirectory(workingDirectory);
219
220 String[] shellCommandline = cmd.getShellCommandline();
221
222 assertEquals(3, shellCommandline.length, "Command line size");
223
224 assertEquals("/bin/sh", shellCommandline[0]);
225 assertEquals("-c", shellCommandline[1]);
226 String expectedShellCmd = "cd '" + root.getAbsolutePath() + "path with spaces' && '/bin/echo' 'hello world'";
227 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
228 expectedShellCmd = "cd '" + root.getAbsolutePath() + "path with spaces' && '\\bin\\echo' 'hello world'";
229 }
230 assertEquals(expectedShellCmd, shellCommandline[2]);
231 }
232
233
234
235
236 @Test
237 void getShellCommandLineBashWithSingleQuotedArg() {
238 Commandline cmd = new Commandline(new BourneShell());
239 cmd.setExecutable("/bin/echo");
240 cmd.addArguments(new String[] {"'hello world'"});
241
242 String[] shellCommandline = cmd.getShellCommandline();
243
244 assertEquals(3, shellCommandline.length, "Command line size");
245
246 assertEquals("/bin/sh", shellCommandline[0]);
247 assertEquals("-c", shellCommandline[1]);
248 String expectedShellCmd = "'/bin/echo' ''\"'\"'hello world'\"'\"''";
249 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
250 expectedShellCmd = expectedShellCmd.replace("/bin/echo", "\\bin\\echo");
251 }
252 assertEquals(expectedShellCmd, shellCommandline[2]);
253 }
254
255 @Test
256 void getShellCommandLineNonWindows() {
257 Commandline cmd = new Commandline(new BourneShell());
258 cmd.setExecutable("/usr/bin");
259 cmd.addArguments(new String[] {"a", "b"});
260 String[] shellCommandline = cmd.getShellCommandline();
261
262 assertEquals(3, shellCommandline.length, "Command line size");
263
264 assertEquals("/bin/sh", shellCommandline[0]);
265 assertEquals("-c", shellCommandline[1]);
266
267 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
268 assertEquals("'\\usr\\bin' 'a' 'b'", shellCommandline[2]);
269 } else {
270 assertEquals("'/usr/bin' 'a' 'b'", shellCommandline[2]);
271 }
272 }
273
274 @Test
275 void environment() throws Exception {
276 Commandline cmd = new Commandline();
277 cmd.addEnvironment("name", "value");
278 assertEquals("name=value", cmd.getEnvironmentVariables()[0]);
279 }
280
281 @Test
282 void environmentWitOverrideSystemEnvironment() throws Exception {
283 Commandline cmd = new Commandline();
284 cmd.addSystemEnvironment();
285 cmd.addEnvironment("JAVA_HOME", "/usr/jdk1.5");
286 String[] environmentVariables = cmd.getEnvironmentVariables();
287
288 for (String environmentVariable : environmentVariables) {
289 if ("JAVA_HOME=/usr/jdk1.5".equals(environmentVariable)) {
290 return;
291 }
292 }
293
294 fail("can't find JAVA_HOME=/usr/jdk1.5");
295 }
296
297
298
299
300 @Test
301 void quotedPathWithSingleApostrophe() throws Exception {
302 File dir = new File(System.getProperty("basedir"), "target/test/quotedpath'test");
303 createAndCallScript(dir, "echo Quoted");
304
305 dir = new File(System.getProperty("basedir"), "target/test/quoted path'test");
306 createAndCallScript(dir, "echo Quoted");
307 }
308
309
310
311
312 @Test
313 void pathWithShellExpansionStrings() throws Exception {
314 File dir = new File(System.getProperty("basedir"), "target/test/dollar$test");
315 createAndCallScript(dir, "echo Quoted");
316 }
317
318
319
320
321 @Test
322 @DisabledOnOs(OS.WINDOWS)
323 void quotedPathWithQuotationMark() throws Exception {
324 File dir = new File(System.getProperty("basedir"), "target/test/quotedpath\"test");
325 createAndCallScript(dir, "echo Quoted");
326
327 dir = new File(System.getProperty("basedir"), "target/test/quoted path\"test");
328 createAndCallScript(dir, "echo Quoted");
329 }
330
331
332
333
334
335 @Test
336 @DisabledOnOs(OS.WINDOWS)
337 void quotedPathWithQuotationMarkAndApostrophe() throws Exception {
338 File dir = new File(System.getProperty("basedir"), "target/test/quotedpath\"'test");
339 createAndCallScript(dir, "echo Quoted");
340
341 dir = new File(System.getProperty("basedir"), "target/test/quoted path\"'test");
342 createAndCallScript(dir, "echo Quoted");
343 }
344
345
346
347
348 @Test
349 void onlyQuotedPath() throws Exception {
350 File dir = new File(System.getProperty("basedir"), "target/test/quotedpath'test");
351
352 File javaHome = new File(System.getProperty("java.home"));
353 File java;
354 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
355 java = new File(javaHome, "/bin/java.exe");
356 } else {
357 java = new File(javaHome, "/bin/java");
358 }
359
360 if (!java.exists()) {
361 throw new IOException(java.getAbsolutePath() + " doesn't exist");
362 }
363
364 String javaBinStr = java.getAbsolutePath();
365 if (Os.isFamily(Os.FAMILY_WINDOWS) && javaBinStr.contains(" ")) {
366 javaBinStr = "\"" + javaBinStr + "\"";
367 }
368
369 createAndCallScript(dir, javaBinStr + " -version");
370 }
371
372 @Test
373 void dollarSignInArgumentPath() throws Exception {
374 File dir = new File(System.getProperty("basedir"), "target/test");
375 if (!dir.exists()) {
376 assertTrue(dir.mkdirs(), "Can't create dir:" + dir.getAbsolutePath());
377 }
378
379 try (Writer writer = Files.newBufferedWriter(dir.toPath().resolve("test$1.txt"))) {
380 IOUtil.copy("Success", writer);
381 }
382
383 Commandline cmd = new Commandline();
384
385 cmd.getShell().setQuotedArgumentsEnabled(true);
386 cmd.setExecutable("cat");
387 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
388 cmd.setExecutable("dir");
389 }
390 cmd.setWorkingDirectory(dir);
391 cmd.createArg().setLine("test$1.txt");
392
393 executeCommandLine(cmd);
394 }
395
396 @Test
397 void timeOutException() throws Exception {
398 File javaHome = new File(System.getProperty("java.home"));
399 File java;
400 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
401 java = new File(javaHome, "/bin/java.exe");
402 } else {
403 java = new File(javaHome, "/bin/java");
404 }
405
406 if (!java.exists()) {
407 throw new IOException(java.getAbsolutePath() + " doesn't exist");
408 }
409
410 Commandline cli = new Commandline();
411 cli.setExecutable(java.getAbsolutePath());
412 cli.createArg().setLine("-version");
413 CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
414 try {
415
416 CommandLineUtils.executeCommandLine(cli, new DefaultConsumer(), err, 1);
417 } catch (CommandLineTimeOutException e) {
418
419 }
420 }
421
422
423
424
425
426
427
428 private static void makeExecutable(File path) throws IOException {
429 if (path == null) {
430 throw new IllegalArgumentException("The file is null");
431 }
432
433 if (!path.isFile()) {
434 throw new IllegalArgumentException("The file '" + path.getAbsolutePath() + "' should be a file");
435 }
436
437 if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
438 Process proc = Runtime.getRuntime().exec(new String[] {"chmod", "a+x", path.getAbsolutePath()});
439 while (true) {
440 try {
441 proc.waitFor();
442 break;
443 } catch (InterruptedException e) {
444
445 }
446 }
447 }
448 }
449
450
451
452
453
454
455
456
457
458 private static void createAndCallScript(File dir, String content) throws Exception {
459 if (!dir.exists()) {
460 assertTrue(dir.mkdirs(), "Can't create dir:" + dir.getAbsolutePath());
461 }
462
463
464 File bat;
465 if (Os.isFamily(Os.FAMILY_WINDOWS)) {
466 bat = new File(dir, "echo.bat");
467 } else {
468 bat = new File(dir, "echo");
469 }
470
471 try (Writer w = Files.newBufferedWriter(bat.toPath())) {
472 IOUtil.copy(content, w);
473 }
474
475
476 makeExecutable(bat);
477
478 Commandline cmd = new Commandline();
479 cmd.setExecutable(bat.getAbsolutePath());
480 cmd.setWorkingDirectory(dir);
481
482
483 executeCommandLine(cmd);
484 }
485
486
487
488
489
490
491
492 private static void executeCommandLine(Commandline cmd) throws Exception {
493 CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
494
495 try {
496 System.out.println("Command line is: " + StringUtils.join(cmd.getShellCommandline(), " "));
497
498 int exitCode = CommandLineUtils.executeCommandLine(cmd, new DefaultConsumer(), err);
499
500 if (exitCode != 0) {
501 throw new Exception("Exit code: " + exitCode + " - " + err.getOutput());
502 }
503 } catch (CommandLineException e) {
504 throw new Exception("Unable to execute command: " + e.getMessage(), e);
505 }
506 }
507 }