Shell.java
package org.codehaus.plexus.util.cli.shell;
/*
* Copyright The Codehaus Foundation.
*
* Licensed 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.codehaus.plexus.util.StringUtils;
/**
* Class that abstracts the Shell functionality, with subclasses for shells that behave particularly, like
* <ul>
* <li><code>command.com</code></li>
* <li><code>cmd.exe</code></li>
* </ul>
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @since 1.2
*
*/
public class Shell implements Cloneable {
private static final char[] DEFAULT_QUOTING_TRIGGER_CHARS = {' '};
private String shellCommand;
private List<String> shellArgs = new ArrayList<String>();
private boolean quotedArgumentsEnabled = true;
private boolean unconditionallyQuote = false;
private String executable;
private String workingDir;
private boolean quotedExecutableEnabled = true;
private boolean doubleQuotedArgumentEscaped = false;
private boolean singleQuotedArgumentEscaped = false;
private boolean doubleQuotedExecutableEscaped = false;
private boolean singleQuotedExecutableEscaped = false;
private char argQuoteDelimiter = '\"';
private char exeQuoteDelimiter = '\"';
private String argumentEscapePattern = "\\%s";
/**
* Toggle unconditional quoting
*
* @param unconditionallyQuote see name
*/
public void setUnconditionalQuoting(boolean unconditionallyQuote) {
this.unconditionallyQuote = unconditionallyQuote;
}
/**
* Set the command to execute the shell (eg. COMMAND.COM, /bin/bash,...)
*
* @param shellCommand see name
*/
public void setShellCommand(String shellCommand) {
this.shellCommand = shellCommand;
}
/**
* Get the command to execute the shell
*
* @return the command
*/
public String getShellCommand() {
return shellCommand;
}
/**
* Set the shell arguments when calling a command line (not the executable arguments) (eg. /X /C for CMD.EXE)
*
* @param shellArgs see name
*/
public void setShellArgs(String[] shellArgs) {
this.shellArgs.clear();
this.shellArgs.addAll(Arrays.asList(shellArgs));
}
/**
* @return the shell arguments
*/
public String[] getShellArgs() {
if ((shellArgs == null) || shellArgs.isEmpty()) {
return null;
} else {
return shellArgs.toArray(new String[0]);
}
}
/**
* Get the command line for the provided executable and arguments in this shell
*
* @param executable executable that the shell has to call
* @param arguments arguments for the executable, not the shell
* @return List with one String object with executable and arguments quoted as needed
*/
public List<String> getCommandLine(String executable, String[] arguments) {
return getRawCommandLine(executable, arguments);
}
protected String quoteOneItem(String inputString, boolean isExecutable) {
char[] escapeChars = getEscapeChars(isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped());
return StringUtils.quoteAndEscape(
inputString,
isExecutable ? getExecutableQuoteDelimiter() : getArgumentQuoteDelimiter(),
escapeChars,
getQuotingTriggerChars(),
'\\',
unconditionallyQuote);
}
protected List<String> getRawCommandLine(String executable, String[] arguments) {
List<String> commandLine = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
if (executable != null) {
String preamble = getExecutionPreamble();
if (preamble != null) {
sb.append(preamble);
}
if (isQuotedExecutableEnabled()) {
sb.append(quoteOneItem(getOriginalExecutable(), true));
} else {
sb.append(getExecutable());
}
}
for (String argument : arguments) {
if (sb.length() > 0) {
sb.append(" ");
}
if (isQuotedArgumentsEnabled()) {
sb.append(quoteOneItem(argument, false));
} else {
sb.append(argument);
}
}
commandLine.add(sb.toString());
return commandLine;
}
protected char[] getQuotingTriggerChars() {
return DEFAULT_QUOTING_TRIGGER_CHARS;
}
protected String getExecutionPreamble() {
return null;
}
protected 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;
}
protected boolean isDoubleQuotedArgumentEscaped() {
return doubleQuotedArgumentEscaped;
}
protected boolean isSingleQuotedArgumentEscaped() {
return singleQuotedArgumentEscaped;
}
protected boolean isDoubleQuotedExecutableEscaped() {
return doubleQuotedExecutableEscaped;
}
protected boolean isSingleQuotedExecutableEscaped() {
return singleQuotedExecutableEscaped;
}
protected void setArgumentQuoteDelimiter(char argQuoteDelimiter) {
this.argQuoteDelimiter = argQuoteDelimiter;
}
protected char getArgumentQuoteDelimiter() {
return argQuoteDelimiter;
}
protected void setExecutableQuoteDelimiter(char exeQuoteDelimiter) {
this.exeQuoteDelimiter = exeQuoteDelimiter;
}
protected char getExecutableQuoteDelimiter() {
return exeQuoteDelimiter;
}
protected void setArgumentEscapePattern(String argumentEscapePattern) {
this.argumentEscapePattern = argumentEscapePattern;
}
protected String getArgumentEscapePattern() {
return argumentEscapePattern;
}
/**
* 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<String>();
if (getShellCommand() != null) {
commandLine.add(getShellCommand());
}
if (getShellArgs() != null) {
commandLine.addAll(getShellArgsList());
}
commandLine.addAll(getCommandLine(getOriginalExecutable(), arguments));
return commandLine;
}
public List<String> getShellArgsList() {
return shellArgs;
}
public void addShellArg(String arg) {
shellArgs.add(arg);
}
public void setQuotedArgumentsEnabled(boolean quotedArgumentsEnabled) {
this.quotedArgumentsEnabled = quotedArgumentsEnabled;
}
public boolean isQuotedArgumentsEnabled() {
return quotedArgumentsEnabled;
}
public void setQuotedExecutableEnabled(boolean quotedExecutableEnabled) {
this.quotedExecutableEnabled = quotedExecutableEnabled;
}
public boolean isQuotedExecutableEnabled() {
return quotedExecutableEnabled;
}
/**
*
* @param executable Sets the executable to run.
*/
public void setExecutable(String executable) {
if ((executable == null) || (executable.length() == 0)) {
return;
}
this.executable = executable.replace('/', File.separatorChar).replace('\\', File.separatorChar);
}
public String getExecutable() {
return executable;
}
/**
* @param path Sets execution directory.
*/
public void setWorkingDirectory(String path) {
if (path != null) {
workingDir = path;
}
}
/**
* @param workingDir Sets execution directory.
*/
public void setWorkingDirectory(File workingDir) {
if (workingDir != null) {
this.workingDir = workingDir.getAbsolutePath();
}
}
public File getWorkingDirectory() {
return workingDir == null ? null : new File(workingDir);
}
public String getWorkingDirectoryAsString() {
return workingDir;
}
public void clearArguments() {
shellArgs.clear();
}
@Override
public Object clone() {
Shell shell = new Shell();
shell.setExecutable(getExecutable());
shell.setWorkingDirectory(getWorkingDirectory());
shell.setShellArgs(getShellArgs());
return shell;
}
public String getOriginalExecutable() {
return executable;
}
public List<String> getOriginalCommandLine(String executable, String[] arguments) {
return getRawCommandLine(executable, arguments);
}
protected void setDoubleQuotedArgumentEscaped(boolean doubleQuotedArgumentEscaped) {
this.doubleQuotedArgumentEscaped = doubleQuotedArgumentEscaped;
}
protected void setDoubleQuotedExecutableEscaped(boolean doubleQuotedExecutableEscaped) {
this.doubleQuotedExecutableEscaped = doubleQuotedExecutableEscaped;
}
protected void setSingleQuotedArgumentEscaped(boolean singleQuotedArgumentEscaped) {
this.singleQuotedArgumentEscaped = singleQuotedArgumentEscaped;
}
protected void setSingleQuotedExecutableEscaped(boolean singleQuotedExecutableEscaped) {
this.singleQuotedExecutableEscaped = singleQuotedExecutableEscaped;
}
}