Skip to content

Commit

Permalink
Quoting for start arguments
Browse files Browse the repository at this point in the history
backport of #10090

Signed-off-by: gregw <[email protected]>
  • Loading branch information
gregw committed Jul 12, 2023
1 parent 9a05c75 commit 68209de
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,81 @@ public static String findJavaBin()
return "java";
}

/**
* Perform an optional quoting of the argument, being intelligent with spaces and quotes as needed. If a subString is set in quotes it won't the subString
* won't be escaped.
*
* @param arg the argument to quote
* @return the quoted and escaped argument
* @deprecated no replacement, quoting is done by {@link #toQuotedString()} now.
*/
@Deprecated
public static String quote(String arg)
private final StringBuilder commandLine = new StringBuilder();
private final List<String> args = new ArrayList<>();
private final String separator;

public CommandLineBuilder()
{
return "'" + arg + "'";
this(false);
}

private List<String> args;

public CommandLineBuilder()
public CommandLineBuilder(boolean multiline)
{
args = new ArrayList<String>();
separator = multiline ? (" \\" + System.lineSeparator() + " ") : " ";
}

public CommandLineBuilder(String bin)
/**
* Quote a string suitable for use with a command line shell using double quotes.
* <p>This method applies doubles quoting as described for the unix {@code sh} commands:
* Enclosing characters within double quotes preserves the literal meaning of all characters except
* dollarsign ($), backquote (`), and backslash (\).
* The backslash inside double quotes is historically weird, and serves
* to quote only the following characters: {@code $ ` " \ newline}.
* Otherwise, it remains literal.
*
* @param input The string to quote if needed
* @return The quoted string or the original string if quotes are not necessary
*/
public static String shellQuoteIfNeeded(String input)
{
this();
args.add(bin);
if (input == null || input.length() == 0)
return input;

int i = 0;
boolean needsQuoting = false;
while (!needsQuoting && i < input.length())
{
char c = input.charAt(i++);

// needs quoting unless a limited set of known good characters
needsQuoting = !(
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '/' ||
c == ':' ||
c == '.' ||
c == '-' ||
c == '_'
);
}

if (!needsQuoting)
return input;

StringBuilder builder = new StringBuilder(input.length() * 2);
builder.append('"');
builder.append(input, 0, --i);

while (i < input.length())
{
char c = input.charAt(i++);
switch (c)
{
case '"':
case '\\':
case'`':
case'$':
builder.append('\\').appendCodePoint(c);
break;
default: builder.appendCodePoint(c);
}
}

builder.append('"');

return builder.toString();
}

/**
Expand All @@ -92,29 +142,25 @@ public void addArg(String arg)
if (arg != null)
{
args.add(arg);
if (commandLine.length() > 0)
commandLine.append(separator);
commandLine.append(shellQuoteIfNeeded(arg));
}
}

/**
* Similar to {@link #addArg(String)} but concats both name + value with an "=" sign, quoting were needed, and excluding the "=" portion if the value is
* undefined or empty.
*
* <pre>
* addEqualsArg("-Dname", "value") = "-Dname=value"
* addEqualsArg("-Djetty.home", "/opt/company inc/jetty (7)/") = "-Djetty.home=/opt/company\ inc/jetty\ (7)/"
* addEqualsArg("-Djenkins.workspace", "/opt/workspaces/jetty jdk7/") = "-Djenkins.workspace=/opt/workspaces/jetty\ jdk7/"
* addEqualsArg("-Dstress", null) = "-Dstress"
* addEqualsArg("-Dstress", "") = "-Dstress"
* </pre>
*
* @param name the name
* @param value the value
*/
public void addEqualsArg(String name, String value)
public void addArg(String name, String value)
{
if (commandLine.length() > 0)
commandLine.append(separator);
commandLine.append(shellQuoteIfNeeded(name));
if ((value != null) && (value.length() > 0))
{
args.add(name + "=" + value);
commandLine.append('=').append(shellQuoteIfNeeded(value));
}
else
{
Expand All @@ -123,17 +169,31 @@ public void addEqualsArg(String name, String value)
}

/**
* Add a simple argument to the command line.
* <p>
* Will <b>NOT</b> quote/escape arguments that have a space in them.
*
* @param arg the simple argument to add
* @param option the option
* @param name the name
* @param value the value
*/
public void addRawArg(String arg)
public void addArg(String option, String name, String value)
{
if (arg != null)
if (commandLine.length() > 0)
commandLine.append(separator);
commandLine.append(option);
if (name == null || name.length() == 0)
{
args.add(arg);
args.add(option);
}
else
{
commandLine.append(shellQuoteIfNeeded(name));
if ((value != null) && (value.length() > 0))
{
args.add(option + name + "=" + value);
commandLine.append('=').append(shellQuoteIfNeeded(value));
}
else
{
args.add(option + name);
}
}
}

Expand All @@ -144,20 +204,12 @@ public List<String> getArgs()

@Override
public String toString()
{
return toString(" ");
}

public String toString(String delim)
{
StringBuilder buf = new StringBuilder();

for (String arg : args)
{
if (buf.length() > 0)
{
buf.append(delim);
}
buf.append(' ');
buf.append(arg); // we assume escaping has occurred during addArg
}

Expand All @@ -169,23 +221,9 @@ public String toString(String delim)
*
* @return the toString but each arg that has spaces is surrounded by {@code '} (single-quote tick)
*/
public String toQuotedString()
public String toCommandLine()
{
StringBuilder buf = new StringBuilder();

for (String arg : args)
{
if (buf.length() > 0)
buf.append(' ');
boolean needsQuotes = (arg.contains(" "));
if (needsQuotes)
buf.append("'");
buf.append(arg);
if (needsQuotes)
buf.append("'");
}

return buf.toString();
return commandLine.toString();
}

public void debug()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ public void start(StartArgs args) throws IOException, InterruptedException
{
CommandLineBuilder cmd = args.getMainArgs(args.getDryRunParts());
cmd.debug();
System.out.println(cmd.toQuotedString());
System.out.println(cmd.toCommandLine());
}

if (args.isStopCommand())
Expand Down
Loading

0 comments on commit 68209de

Please sign in to comment.