From 3b9d8dc65f49e3e64356a09832529f87adbdf5b4 Mon Sep 17 00:00:00 2001 From: Alix Lourme Date: Wed, 23 May 2018 10:26:32 +0200 Subject: [PATCH] For Windows OS, revert the usage of cmd.exe by default --- .../codehaus/plexus/util/cli/Commandline.java | 36 +++++++-- .../plexus/util/cli/CommandlineTest.java | 77 ++++++++++++++++--- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/codehaus/plexus/util/cli/Commandline.java b/src/main/java/org/codehaus/plexus/util/cli/Commandline.java index 58ddfe35..812e873d 100644 --- a/src/main/java/org/codehaus/plexus/util/cli/Commandline.java +++ b/src/main/java/org/codehaus/plexus/util/cli/Commandline.java @@ -123,6 +123,15 @@ public class Commandline private Shell shell; + /** + * For {@link Os#FAMILY_WINDOWS} (only), force the usage of {@link CmdShell} (=> 'cmd.exe /X /C' prefix).
+ * Allow built-in commands (like echo) or .cmd/.bat files on PATH without extension + * suffix.
+ * Warning: This usage breaks the capacity to terminate the launched sub process when SIGINT signal (CTRL+C) is + * catched ; So use at your own risk. + */ + private boolean forceShellOsSpefic; + /** * @deprecated Use {@link Commandline#setExecutable(String)} instead. */ @@ -496,24 +505,26 @@ public String[] getEnvironmentVariables() /** * Returns the executable and all defined arguments.
- * For Windows Family, {@link Commandline#getShellCommandline()} is returned + * For Windows Family when {@link Commandline#setForceShellOsSpefic(boolean)} is used, + * {@link Commandline#getShellCommandline()} is returned */ public String[] getCommandline() { - if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) + + if ( this.forceShellOsSpefic && Os.isFamily( Os.FAMILY_WINDOWS ) ) { return getShellCommandline(); } final String[] args = getArguments(); - String executable = getLiteralExecutable(); + String executableTmp = getLiteralExecutable(); - if ( executable == null ) + if ( executableTmp == null ) { return args; } final String[] result = new String[args.length + 1]; - result[0] = executable; + result[0] = executableTmp; System.arraycopy( args, 0, result, 1, args.length ); return result; } @@ -728,6 +739,21 @@ public Shell getShell() return shell; } + /** + * For {@link Os#FAMILY_WINDOWS} (only), force the usage of {@link CmdShell} (=> 'cmd.exe /X /C' prefix).
+ * Allow built-in commands (like echo) or .cmd/.bat files on PATH without extension + * suffix.
+ * Warning: This usage breaks the capacity to terminate the launched sub process when SIGINT signal (CTRL+C) is + * catched ; So use at your own risk. + * + * @param forceShellOsSpefic boolean + * @since 3.1.1 + */ + public void setForceShellOsSpefic( boolean forceShellOsSpefic ) + { + this.forceShellOsSpefic = forceShellOsSpefic; + } + /** * @deprecated Use {@link CommandLineUtils#translateCommandline(String)} instead. */ diff --git a/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java b/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java index 8cd96f6c..3b2df1c9 100644 --- a/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java +++ b/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java @@ -60,8 +60,8 @@ public void testCommandlineWithoutCommandInConstructor() { Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); - cmd.createArgument().setValue( "cd" ); - cmd.createArgument().setValue( "." ); + cmd.createArg().setValue( "cd" ); + cmd.createArg().setValue( "." ); // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "cd .", cmd.toString() ); @@ -93,8 +93,37 @@ public void testExecuteBinaryOnPath() try { // Maven startup script on PATH is required for this test + String binary = "mvn"; + if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) + { + binary += ".cmd"; + } Commandline cmd = new Commandline(); cmd.setWorkingDirectory( baseDir ); + cmd.setExecutable( binary ); + assertEquals( binary, cmd.getShell().getOriginalExecutable() ); + cmd.createArg().setValue( "-version" ); + Process process = cmd.execute(); + String out = IOUtil.toString( process.getInputStream() ); + assertTrue( out.contains( "Apache Maven" ) ); + assertTrue( out.contains( "Maven home:" ) ); + assertTrue( out.contains( "Java version:" ) ); + assertTrue( out.contains( "Java home:" ) ); + } + catch ( Exception e ) + { + fail( "Maven startup script seems not on the PATH: " + e.getMessage() ); + } + } + + public void testExecuteBinaryOnPathWithOsShell() + { + try + { + // Maven startup script on PATH is required for this test + Commandline cmd = new Commandline(); + cmd.setForceShellOsSpefic( true ); + cmd.setWorkingDirectory( baseDir ); cmd.setExecutable( "mvn" ); assertEquals( "mvn", cmd.getShell().getOriginalExecutable() ); cmd.createArg().setValue( "-version" ); @@ -112,15 +141,43 @@ public void testExecuteBinaryOnPath() } public void testExecute() + { + try + { + String binary = "echo"; + Commandline cmd = new Commandline(); + cmd.setWorkingDirectory( baseDir ); + if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) + { + binary = "cmd"; + cmd.createArg().setValue( "/X" ); + cmd.createArg().setValue( "/C" ); + cmd.createArg().setValue( "echo" ); + } + cmd.setExecutable( binary ); + assertEquals( binary, cmd.getShell().getOriginalExecutable() ); + cmd.createArg().setValue( "Hello" ); + + Process process = cmd.execute(); + assertEquals( "Hello", IOUtil.toString( process.getInputStream() ).trim() ); + } + catch ( Exception e ) + { + fail( e.getMessage() ); + } + } + + public void testExecuteWithOsShell() { try { // allow it to detect the proper shell here. Commandline cmd = new Commandline(); + cmd.setForceShellOsSpefic( true ); cmd.setWorkingDirectory( baseDir ); cmd.setExecutable( "echo" ); assertEquals( "echo", cmd.getShell().getOriginalExecutable() ); - cmd.createArgument().setValue( "Hello" ); + cmd.createArg().setValue( "Hello" ); Process process = cmd.execute(); assertEquals( "Hello", IOUtil.toString( process.getInputStream() ).trim() ); @@ -138,8 +195,8 @@ public void testSetLine() Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); cmd.setExecutable( "echo" ); - cmd.createArgument().setLine( null ); - cmd.createArgument().setLine( "Hello" ); + cmd.createArg().setValue( null ); + cmd.createArg().setLine( "Hello" ); // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "echo Hello", cmd.toString() ); @@ -156,8 +213,8 @@ public void testCreateCommandInReverseOrder() { Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); - cmd.createArgument().setValue( "." ); - cmd.createArgument( true ).setValue( "cd" ); + cmd.createArg().setValue( "." ); + cmd.createArg( true ).setValue( "cd" ); // NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result. assertEquals( "cd .", cmd.toString() ); @@ -174,9 +231,9 @@ public void testSetFile() { Commandline cmd = new Commandline( new Shell() ); cmd.setWorkingDirectory( baseDir ); - cmd.createArgument().setValue( "more" ); + cmd.createArg().setValue( "more" ); File f = new File( "test.txt" ); - cmd.createArgument().setFile( f ); + cmd.createArg().setFile( f ); String fileName = f.getAbsolutePath(); if ( fileName.contains( " " ) ) { @@ -486,7 +543,7 @@ public void testDollarSignInArgumentPath() } Commandline cmd = new Commandline(); - // cmd.getShell().setShellCommand( "/bin/sh" ); + cmd.setForceShellOsSpefic( true ); cmd.getShell().setQuotedArgumentsEnabled( true ); cmd.setExecutable( "cat" ); if ( Os.isFamily( Os.FAMILY_WINDOWS ) )