Skip to content

Commit

Permalink
[JENKINS-33712] Fixed regression issue with empty parameters.
Browse files Browse the repository at this point in the history
  • Loading branch information
escoem authored and armfergom committed May 10, 2016
1 parent f10f69e commit b6956b5
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -6,3 +6,4 @@ work
/.project
/.settings
/.classpath
/.idea
50 changes: 43 additions & 7 deletions src/main/java/hudson/tasks/Ant.java
Expand Up @@ -210,13 +210,7 @@ public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListene
env.put("ANT_OPTS",env.expand(antOpts));

if(!launcher.isUnix()) {
args = args.toWindowsCommand();
// For some reason, ant on windows rejects empty parameters but unix does not.
// Add quotes for any empty parameter values:
List<String> newArgs = new ArrayList<String>(args.toList());
newArgs.set(newArgs.size() - 1, newArgs.get(newArgs.size() - 1).replaceAll(
"(?<= )(-D[^\" ]+)= ", "$1=\"\" "));
args = new ArgumentListBuilder(newArgs.toArray(new String[newArgs.size()]));
args = toWindowsCommand(args.toWindowsCommand());
}

long startTime = System.currentTimeMillis();
Expand Down Expand Up @@ -245,6 +239,48 @@ public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListene
}
}

/**
* Backward compatibility by checking the number of parameters
*
*/
protected static ArgumentListBuilder toWindowsCommand(ArgumentListBuilder args) {
List<String> arguments = args.toList();

if (arguments.size() > 3) { // "cmd.exe", "/C", "ant.bat", ...
boolean[] masks = args.toMaskArray();
// don't know why are missing single quotes.

args = new ArgumentListBuilder();
args.add(arguments.get(0), arguments.get(1)); // "cmd.exe", "/C", ...

int size = arguments.size();
for (int i = 2; i < size; i++) {
String arg = arguments.get(i).replaceAll("^(-D[^\" ]+)=$", "$0\"\"");

if (i == 2) {
arg = "'" + arg;
}
if (i == size - 1) {
arg = arg + "'";
}
if (masks[i]) {
args.addMasked(arg);
} else {
args.add(arg);
}
}
} else {
// For some reason, ant on windows rejects empty parameters but unix does not.
// Add quotes for any empty parameter values:
List<String> newArgs = new ArrayList<String>(args.toList());
newArgs.set(newArgs.size() - 1, newArgs.get(newArgs.size() - 1).replaceAll(
"(?<= )(-D[^\" ]+)= ", "$1=\"\" "));
args = new ArgumentListBuilder(newArgs.toArray(new String[newArgs.size()]));
}

return args;
}

private static FilePath buildFilePath(FilePath base, String buildFile, String targets) {
if(buildFile!=null) return base.child(buildFile);
// some users specify the -f option in the targets field, so take that into account as well.
Expand Down
70 changes: 70 additions & 0 deletions src/test/java/hudson/tasks/AntTest.java
Expand Up @@ -43,6 +43,7 @@
import hudson.tools.InstallSourceProperty;
import hudson.tools.ToolProperty;
import hudson.tools.ToolPropertyDescriptor;
import hudson.util.ArgumentListBuilder;
import hudson.util.DescribableList;
import jenkins.model.Jenkins;

Expand All @@ -62,6 +63,8 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.List;

/**
* @author Kohsuke Kawaguchi
*/
Expand Down Expand Up @@ -324,4 +327,71 @@ private FreeStyleProject createSimpleAntProject(String targets, String ops, Stri
project.getBuildersList().add(new Ant(targets, antName, ops, buildFile, properties));
return project;
}

@Bug(33712)
public void testRegressionNoQuote() throws Exception {
ArgumentListBuilder builder_1_653 = Ant.toWindowsCommand(toWindowsCommand_1_653(new ArgumentListBuilder("ant.bat", "-Dfoo1=", "-Dfoo2=foovalue")));

String[] current = builder_1_653.toCommandArray();
String[] expected = new String[] { "cmd.exe", "/C", "'\"ant.bat", "-Dfoo1=\"\"", "-Dfoo2=foovalue", "&&", "exit", "%%ERRORLEVEL%%\"'" };

assertTrue("[653] Assert that has the same number of arguments. current is " + current.length + " and expected is " + expected.length, current.length == expected.length);
for (int i=0; i<current.length;i++) {
assertEquals("[653] Assert that argument at " + i + ".", expected[i], current[i]);
}

ArgumentListBuilder builder = Ant.toWindowsCommand((new ArgumentListBuilder("ant.bat", "-Dfoo1=", "-Dfoo2=foovalue").toWindowsCommand()));

current = builder.toCommandArray();
expected = new String[] { "cmd.exe", "/C", "\"ant.bat -Dfoo1=\"\" -Dfoo2=foovalue && exit %%ERRORLEVEL%%\"" };

assertTrue("[652] Assert that has the same number of arguments. current is " + current.length + " and expected is " + expected.length, current.length == expected.length);
for (int i=0; i<current.length;i++) {
assertEquals("[652] Assert that argument at " + i + ".", expected[i], current[i]);
}
}

private static ArgumentListBuilder toWindowsCommand_1_653(ArgumentListBuilder arguments) {
List<String> args = arguments.toList();
boolean[] masks = arguments.toMaskArray();

ArgumentListBuilder windowsCommand = new ArgumentListBuilder().add("cmd.exe", "/C");
boolean quoted, percent;
for (int i = 0; i < args.size(); i++) {
StringBuilder quotedArgs = new StringBuilder();
String arg = args.get(i);
quoted = percent = false;
for (int j = 0; j < arg.length(); j++) {
char c = arg.charAt(j);
if (!quoted && (c == ' ' || c == '*' || c == '?' || c == ',' || c == ';')) {
quoted = startQuoting(quotedArgs, arg, j);
}
else if (c == '^' || c == '&' || c == '<' || c == '>' || c == '|') {
if (!quoted) quoted = startQuoting(quotedArgs, arg, j);
// quotedArgs.append('^'); See note in javadoc above
}
else if (c == '"') {
if (!quoted) quoted = startQuoting(quotedArgs, arg, j);
quotedArgs.append('"');
}
percent = (c == '%');
if (quoted) quotedArgs.append(c);
}
if(i == 0 && quoted) quotedArgs.insert(0, '"'); else if (i == 0 && !quoted) quotedArgs.append('"');
if (quoted) quotedArgs.append('"'); else quotedArgs.append(arg);

windowsCommand.add(quotedArgs, masks[i]);
}
// (comment copied from old code in hudson.tasks.Ant)
// on Windows, executing batch file can't return the correct error code,
// so we need to wrap it into cmd.exe.
// double %% is needed because we want ERRORLEVEL to be expanded after
// batch file executed, not before. This alone shows how broken Windows is...
windowsCommand.add("&&").add("exit").add("%%ERRORLEVEL%%\"");
return windowsCommand;
}
private static boolean startQuoting(StringBuilder buf, String arg, int atIndex) {
buf.append('"').append(arg.substring(0, atIndex));
return true;
}
}

0 comments on commit b6956b5

Please sign in to comment.