blob: 4f3bd0418b26b509a0d100c2980df95673a1f88f [file] [log] [blame]
package org.apache.maven.shared.utils.cli.shell;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.maven.shared.utils.StringUtils;
/**
* Class that abstracts the Shell functionality,
* with subclasses for shells that behave particularly, like<p>
*
* <ul>
* <li><code>command.com</code></li>
* <li><code>cmd.exe</code></li>
* </ul>
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
*
*/
public class Shell
implements Cloneable
{
private static final char[] DEFAULT_QUOTING_TRIGGER_CHARS = { ' ' };
private String shellCommand;
private final List<String> shellArgs = new ArrayList<String>();
private boolean quotedArgumentsEnabled = true;
private String executable;
private String workingDir;
private boolean quotedExecutableEnabled = true;
private boolean singleQuotedArgumentEscaped = false;
private boolean singleQuotedExecutableEscaped = false;
private char argQuoteDelimiter = '\"';
private char exeQuoteDelimiter = '\"';
/**
* Set the command to execute the shell (e.g. COMMAND.COM, /bin/bash,...).
*
* @param shellCommand the command
*/
void setShellCommand( String shellCommand )
{
this.shellCommand = shellCommand;
}
/**
* Get the command to execute the shell.
*
* @return the command
*/
String getShellCommand()
{
return shellCommand;
}
/**
* Set the shell arguments when calling a command line (not the executable arguments)
* (e.g. /X /C for CMD.EXE).
*
* @param shellArgs the arguments to the shell
*/
void setShellArgs( String[] shellArgs )
{
this.shellArgs.clear();
this.shellArgs.addAll( Arrays.asList( shellArgs ) );
}
/**
* Get the shell arguments
*
* @return the arguments
*/
String[] getShellArgs()
{
if ( ( shellArgs == null ) || shellArgs.isEmpty() )
{
return null;
}
else
{
return shellArgs.toArray( new String[shellArgs.size()] );
}
}
/**
* Get the command line for the provided executable and arguments in this shell
*
* @param executableParameter executable that the shell has to call
* @param argumentsParameter arguments for the executable, not the shell
* @return list with one String object with executable and arguments quoted as needed
*/
List<String> getCommandLine( String executableParameter, String... argumentsParameter )
{
return getRawCommandLine( executableParameter, argumentsParameter );
}
/**
* @param executableParameter Executable
* @param argumentsParameter the arguments for the executable
* @return the list on command line
*/
List<String> getRawCommandLine( String executableParameter, String... argumentsParameter )
{
List<String> commandLine = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
if ( executableParameter != null )
{
String preamble = getExecutionPreamble();
if ( preamble != null )
{
sb.append( preamble );
}
if ( isQuotedExecutableEnabled() )
{
char[] escapeChars =
getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() );
sb.append( StringUtils.quoteAndEscape( getExecutable(), getExecutableQuoteDelimiter(), escapeChars,
getQuotingTriggerChars(), '\\', false ) );
}
else
{
sb.append( getExecutable() );
}
}
for ( String argument : argumentsParameter )
{
if ( sb.length() > 0 )
{
sb.append( ' ' );
}
if ( isQuotedArgumentsEnabled() )
{
char[] escapeChars = getEscapeChars( isSingleQuotedArgumentEscaped(), isDoubleQuotedArgumentEscaped() );
sb.append( StringUtils.quoteAndEscape( argument, getArgumentQuoteDelimiter(), escapeChars,
getQuotingTriggerChars(), '\\', false ) );
}
else
{
sb.append( argument );
}
}
commandLine.add( sb.toString() );
return commandLine;
}
char[] getQuotingTriggerChars()
{
return DEFAULT_QUOTING_TRIGGER_CHARS;
}
String getExecutionPreamble()
{
return null;
}
char[] getEscapeChars( boolean includeSingleQuote, boolean includeDoubleQuote )
{
StringBuilder buf = new StringBuilder( 2 );
if ( includeSingleQuote )
{
buf.append( '\'' );
}
if ( includeDoubleQuote )
{
buf.append( '\"' );
}
char[] result = new char[buf.length()];
buf.getChars( 0, buf.length(), result, 0 );
return result;
}
/**
* @return false in all cases
*/
protected boolean isDoubleQuotedArgumentEscaped()
{
return false;
}
/**
* @return {@link #singleQuotedArgumentEscaped}
*/
protected boolean isSingleQuotedArgumentEscaped()
{
return singleQuotedArgumentEscaped;
}
boolean isDoubleQuotedExecutableEscaped()
{
return false;
}
boolean isSingleQuotedExecutableEscaped()
{
return singleQuotedExecutableEscaped;
}
/**
* @param argQuoteDelimiterParameter {@link #argQuoteDelimiter}
*/
void setArgumentQuoteDelimiter( char argQuoteDelimiterParameter )
{
this.argQuoteDelimiter = argQuoteDelimiterParameter;
}
char getArgumentQuoteDelimiter()
{
return argQuoteDelimiter;
}
/**
* @param exeQuoteDelimiterParameter {@link #exeQuoteDelimiter}
*/
void setExecutableQuoteDelimiter( char exeQuoteDelimiterParameter )
{
this.exeQuoteDelimiter = exeQuoteDelimiterParameter;
}
char getExecutableQuoteDelimiter()
{
return exeQuoteDelimiter;
}
/**
* Get the full command line to execute, including shell command, shell arguments,
* executable and executable arguments
*
* @param arguments arguments for the executable, not the shell
* @return List of String objects, whose array version is suitable to be used as argument
* of Runtime.getRuntime().exec()
*/
public List<String> getShellCommandLine( String... arguments )
{
List<String> commandLine = new ArrayList<>();
if ( getShellCommand() != null )
{
commandLine.add( getShellCommand() );
}
if ( getShellArgs() != null )
{
commandLine.addAll( getShellArgsList() );
}
commandLine.addAll( getCommandLine( getExecutable(), arguments ) );
return commandLine;
}
List<String> getShellArgsList()
{
return shellArgs;
}
/**
* @param quotedArgumentsEnabled {@link #quotedArgumentsEnabled}
*/
public void setQuotedArgumentsEnabled( boolean quotedArgumentsEnabled )
{
this.quotedArgumentsEnabled = quotedArgumentsEnabled;
}
boolean isQuotedArgumentsEnabled()
{
return quotedArgumentsEnabled;
}
void setQuotedExecutableEnabled( boolean quotedExecutableEnabled )
{
this.quotedExecutableEnabled = quotedExecutableEnabled;
}
boolean isQuotedExecutableEnabled()
{
return quotedExecutableEnabled;
}
/**
* Sets the executable to run.
* @param executable The executable.
*/
public void setExecutable( String executable )
{
if ( ( executable == null ) || ( executable.length() == 0 ) )
{
return;
}
this.executable = executable.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
}
/**
* @return The executable.
*/
public String getExecutable()
{
return executable;
}
/**
* Sets execution directory.
* @param path The path which should be used as working directory.
*/
public void setWorkingDirectory( String path )
{
if ( path != null )
{
this.workingDir = path;
}
}
/**
* Sets execution directory.
*
* @param workingDirectory the working directory
*/
public void setWorkingDirectory( File workingDirectory )
{
if ( workingDirectory != null )
{
this.workingDir = workingDirectory.getAbsolutePath();
}
}
/**
* @return the working directory
*/
public File getWorkingDirectory()
{
return workingDir == null ? null : new File( workingDir );
}
String getWorkingDirectoryAsString()
{
return workingDir;
}
@Override
public Object clone()
{
throw new RuntimeException( "Do we ever clone this?" );
/* Shell shell = new Shell();
shell.setExecutable( getExecutable() );
shell.setWorkingDirectory( getWorkingDirectory() );
shell.setShellArgs( getShellArgs() );
return shell;*/
}
void setSingleQuotedArgumentEscaped( boolean singleQuotedArgumentEscaped )
{
this.singleQuotedArgumentEscaped = singleQuotedArgumentEscaped;
}
void setSingleQuotedExecutableEscaped( boolean singleQuotedExecutableEscaped )
{
this.singleQuotedExecutableEscaped = singleQuotedExecutableEscaped;
}
}