From ff8e0e456802827a2a2b4c28f40d6b8b0798a978 Mon Sep 17 00:00:00 2001 From: Alix Lourme Date: Mon, 21 Dec 2020 12:22:35 +0100 Subject: [PATCH] For Windows OS, revert the usage of cmd.exe by default (new option) --- .../codehaus/plexus/util/cli/Commandline.java | 35 ++++++++-- .../plexus/util/cli/CommandlineTest.java | 66 ++++++++++++++++--- 2 files changed, 86 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 c06147a9..31351ebb 100644 --- a/src/main/java/org/codehaus/plexus/util/cli/Commandline.java +++ b/src/main/java/org/codehaus/plexus/util/cli/Commandline.java @@ -119,6 +119,15 @@ public class Commandline private Shell shell; + /** + * For {@link Os#FAMILY_WINDOWS} (only), force the usage of {@link CmdShell} (sample: '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 forceShellOsSpecific; + /** * @deprecated Use {@link Commandline#setExecutable(String)} instead. */ @@ -492,11 +501,12 @@ public String[] getEnvironmentVariables() /** * @return Returns the executable and all defined arguments. - * For Windows Family, {@link Commandline#getShellCommandline()} is returned + * For Windows Family when {@link Commandline#setForceShellOsSpecific(boolean)} is used, + * {@link Commandline#getShellCommandline()} is returned */ public String[] getCommandline() { - if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) + if ( this.forceShellOsSpecific && Os.isFamily( Os.FAMILY_WINDOWS ) ) { return getShellCommandline(); } @@ -511,14 +521,14 @@ public String[] getCommandline() public String[] getRawCommandline() { 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; } @@ -741,6 +751,21 @@ public Shell getShell() return shell; } + /** + * For {@link Os#FAMILY_WINDOWS} (only), force the usage of {@link CmdShell} (sample: '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 forceShellOsSpecific boolean + * @since 3.4.0 + */ + public void setForceShellOsSpecific( boolean forceShellOsSpecific ) + { + this.forceShellOsSpecific = forceShellOsSpecific; + } + /** * @param toProcess the process * @return the command line arguments 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 28ec8297..99119916 100644 --- a/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java +++ b/src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java @@ -55,8 +55,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() ); @@ -78,6 +78,29 @@ public void testExecuteBinaryOnPath() { // Maven startup script on PATH is required for this test Commandline cmd = new Commandline(); + String executable = "mvn"; + if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) + { + executable += ".cmd"; + } + cmd.setWorkingDirectory( baseDir ); + cmd.setExecutable( executable ); + assertEquals( executable, 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:" ) ); + } + + @Test + public void testExecuteBinaryOnPathWithOsShell() + throws Exception + { + // Maven startup script on PATH is required for this test + Commandline cmd = new Commandline(); + cmd.setForceShellOsSpecific( true ); cmd.setWorkingDirectory( baseDir ); cmd.setExecutable( "mvn" ); assertEquals( "mvn", cmd.getShell().getOriginalExecutable() ); @@ -92,13 +115,36 @@ public void testExecuteBinaryOnPath() @Test public void testExecute() throws Exception + { + String executable = "echo"; + Commandline cmd = new Commandline(); + cmd.setWorkingDirectory( baseDir ); + if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) + { + executable = "cmd"; + cmd.createArg().setValue( "/X" ); + cmd.createArg().setValue( "/C" ); + cmd.createArg().setValue( "echo" ); + } + cmd.setExecutable( executable ); + assertEquals( executable, cmd.getShell().getOriginalExecutable() ); + cmd.createArg().setValue( "Hello" ); + + Process process = cmd.execute(); + assertEquals( "Hello", IOUtil.toString( process.getInputStream() ).trim() ); + } + + @Test + public void testExecuteWithOsShell() + throws Exception { // allow it to detect the proper shell here. Commandline cmd = new Commandline(); + cmd.setForceShellOsSpecific( 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() ); @@ -110,8 +156,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() ); @@ -122,8 +168,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() ); @@ -134,9 +180,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( " " ) ) { @@ -455,7 +501,7 @@ public void testDollarSignInArgumentPath() } Commandline cmd = new Commandline(); - // cmd.getShell().setShellCommand( "/bin/sh" ); + cmd.setForceShellOsSpecific( true ); cmd.getShell().setQuotedArgumentsEnabled( true ); cmd.setExecutable( "cat" ); if ( Os.isFamily( Os.FAMILY_WINDOWS ) )