Skip to content

Commit ff8e0e4

Browse files
committed
For Windows OS, revert the usage of cmd.exe by default (new option)
1 parent 900acba commit ff8e0e4

File tree

2 files changed

+86
-15
lines changed

2 files changed

+86
-15
lines changed

src/main/java/org/codehaus/plexus/util/cli/Commandline.java

+30-5
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@ public class Commandline
119119

120120
private Shell shell;
121121

122+
/**
123+
* For {@link Os#FAMILY_WINDOWS} (only), force the usage of {@link CmdShell} (sample: 'cmd.exe /X /C' prefix).<br>
124+
* Allow built-in commands (like <i>echo</i>) or <i>.cmd</i>/<i>.bat</i> files on PATH without extension
125+
* suffix.<br>
126+
* Warning: This usage breaks the capacity to terminate the launched sub process when SIGINT signal (CTRL+C) is
127+
* catched ; So use at your own risk.
128+
*/
129+
private boolean forceShellOsSpecific;
130+
122131
/**
123132
* @deprecated Use {@link Commandline#setExecutable(String)} instead.
124133
*/
@@ -492,11 +501,12 @@ public String[] getEnvironmentVariables()
492501

493502
/**
494503
* @return Returns the executable and all defined arguments.
495-
* For Windows Family, {@link Commandline#getShellCommandline()} is returned
504+
* For Windows Family when {@link Commandline#setForceShellOsSpecific(boolean)} is used,
505+
* {@link Commandline#getShellCommandline()} is returned
496506
*/
497507
public String[] getCommandline()
498508
{
499-
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
509+
if ( this.forceShellOsSpecific && Os.isFamily( Os.FAMILY_WINDOWS ) )
500510
{
501511
return getShellCommandline();
502512
}
@@ -511,14 +521,14 @@ public String[] getCommandline()
511521
public String[] getRawCommandline()
512522
{
513523
final String[] args = getArguments();
514-
String executable = getLiteralExecutable();
524+
String executableTmp = getLiteralExecutable();
515525

516-
if ( executable == null )
526+
if ( executableTmp == null )
517527
{
518528
return args;
519529
}
520530
final String[] result = new String[args.length + 1];
521-
result[0] = executable;
531+
result[0] = executableTmp;
522532
System.arraycopy( args, 0, result, 1, args.length );
523533
return result;
524534
}
@@ -741,6 +751,21 @@ public Shell getShell()
741751
return shell;
742752
}
743753

754+
/**
755+
* For {@link Os#FAMILY_WINDOWS} (only), force the usage of {@link CmdShell} (sample: 'cmd.exe /X /C' prefix).<br>
756+
* Allow built-in commands (like <i>echo</i>) or <i>.cmd</i>/<i>.bat</i> files on PATH without extension
757+
* suffix.<br>
758+
* Warning: This usage breaks the capacity to terminate the launched sub process when SIGINT signal (CTRL+C) is
759+
* catched ; So use at your own risk.
760+
*
761+
* @param forceShellOsSpecific boolean
762+
* @since 3.4.0
763+
*/
764+
public void setForceShellOsSpecific( boolean forceShellOsSpecific )
765+
{
766+
this.forceShellOsSpecific = forceShellOsSpecific;
767+
}
768+
744769
/**
745770
* @param toProcess the process
746771
* @return the command line arguments

src/test/java/org/codehaus/plexus/util/cli/CommandlineTest.java

+56-10
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ public void testCommandlineWithoutCommandInConstructor()
5555
{
5656
Commandline cmd = new Commandline( new Shell() );
5757
cmd.setWorkingDirectory( baseDir );
58-
cmd.createArgument().setValue( "cd" );
59-
cmd.createArgument().setValue( "." );
58+
cmd.createArg().setValue( "cd" );
59+
cmd.createArg().setValue( "." );
6060

6161
// NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result.
6262
assertEquals( "cd .", cmd.toString() );
@@ -78,6 +78,29 @@ public void testExecuteBinaryOnPath()
7878
{
7979
// Maven startup script on PATH is required for this test
8080
Commandline cmd = new Commandline();
81+
String executable = "mvn";
82+
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
83+
{
84+
executable += ".cmd";
85+
}
86+
cmd.setWorkingDirectory( baseDir );
87+
cmd.setExecutable( executable );
88+
assertEquals( executable, cmd.getShell().getOriginalExecutable() );
89+
cmd.createArg().setValue( "-version" );
90+
Process process = cmd.execute();
91+
String out = IOUtil.toString( process.getInputStream() );
92+
assertTrue( out.contains( "Apache Maven" ) );
93+
assertTrue( out.contains( "Maven home:" ) );
94+
assertTrue( out.contains( "Java version:" ) );
95+
}
96+
97+
@Test
98+
public void testExecuteBinaryOnPathWithOsShell()
99+
throws Exception
100+
{
101+
// Maven startup script on PATH is required for this test
102+
Commandline cmd = new Commandline();
103+
cmd.setForceShellOsSpecific( true );
81104
cmd.setWorkingDirectory( baseDir );
82105
cmd.setExecutable( "mvn" );
83106
assertEquals( "mvn", cmd.getShell().getOriginalExecutable() );
@@ -92,13 +115,36 @@ public void testExecuteBinaryOnPath()
92115
@Test
93116
public void testExecute()
94117
throws Exception
118+
{
119+
String executable = "echo";
120+
Commandline cmd = new Commandline();
121+
cmd.setWorkingDirectory( baseDir );
122+
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
123+
{
124+
executable = "cmd";
125+
cmd.createArg().setValue( "/X" );
126+
cmd.createArg().setValue( "/C" );
127+
cmd.createArg().setValue( "echo" );
128+
}
129+
cmd.setExecutable( executable );
130+
assertEquals( executable, cmd.getShell().getOriginalExecutable() );
131+
cmd.createArg().setValue( "Hello" );
132+
133+
Process process = cmd.execute();
134+
assertEquals( "Hello", IOUtil.toString( process.getInputStream() ).trim() );
135+
}
136+
137+
@Test
138+
public void testExecuteWithOsShell()
139+
throws Exception
95140
{
96141
// allow it to detect the proper shell here.
97142
Commandline cmd = new Commandline();
143+
cmd.setForceShellOsSpecific( true );
98144
cmd.setWorkingDirectory( baseDir );
99145
cmd.setExecutable( "echo" );
100146
assertEquals( "echo", cmd.getShell().getOriginalExecutable() );
101-
cmd.createArgument().setValue( "Hello" );
147+
cmd.createArg().setValue( "Hello" );
102148

103149
Process process = cmd.execute();
104150
assertEquals( "Hello", IOUtil.toString( process.getInputStream() ).trim() );
@@ -110,8 +156,8 @@ public void testSetLine()
110156
Commandline cmd = new Commandline( new Shell() );
111157
cmd.setWorkingDirectory( baseDir );
112158
cmd.setExecutable( "echo" );
113-
cmd.createArgument().setLine( null );
114-
cmd.createArgument().setLine( "Hello" );
159+
cmd.createArg().setValue( null );
160+
cmd.createArg().setLine( "Hello" );
115161

116162
// NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result.
117163
assertEquals( "echo Hello", cmd.toString() );
@@ -122,8 +168,8 @@ public void testCreateCommandInReverseOrder()
122168
{
123169
Commandline cmd = new Commandline( new Shell() );
124170
cmd.setWorkingDirectory( baseDir );
125-
cmd.createArgument().setValue( "." );
126-
cmd.createArgument( true ).setValue( "cd" );
171+
cmd.createArg().setValue( "." );
172+
cmd.createArg( true ).setValue( "cd" );
127173

128174
// NOTE: cmd.toString() uses CommandLineUtils.toString( String[] ), which *quotes* the result.
129175
assertEquals( "cd .", cmd.toString() );
@@ -134,9 +180,9 @@ public void testSetFile()
134180
{
135181
Commandline cmd = new Commandline( new Shell() );
136182
cmd.setWorkingDirectory( baseDir );
137-
cmd.createArgument().setValue( "more" );
183+
cmd.createArg().setValue( "more" );
138184
File f = new File( "test.txt" );
139-
cmd.createArgument().setFile( f );
185+
cmd.createArg().setFile( f );
140186
String fileName = f.getAbsolutePath();
141187
if ( fileName.contains( " " ) )
142188
{
@@ -455,7 +501,7 @@ public void testDollarSignInArgumentPath()
455501
}
456502

457503
Commandline cmd = new Commandline();
458-
// cmd.getShell().setShellCommand( "/bin/sh" );
504+
cmd.setForceShellOsSpecific( true );
459505
cmd.getShell().setQuotedArgumentsEnabled( true );
460506
cmd.setExecutable( "cat" );
461507
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )

0 commit comments

Comments
 (0)