Skip to content

Commit 69ee0ff

Browse files
authored
Merge pull request #441 from cherylking/fixDevcSpaceInPath
Build docker commands better
2 parents b48d061 + 2c934e9 commit 69ee0ff

File tree

1 file changed

+87
-38
lines changed
  • src/main/java/io/openliberty/tools/common/plugins/util

1 file changed

+87
-38
lines changed

src/main/java/io/openliberty/tools/common/plugins/util/DevUtil.java

Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,21 +1267,30 @@ private void buildContainerImage(File tempContainerfile, File userContainerfile,
12671267
// Name rules: may contain lowercase letters, digits and a period, one or two underscores, or one or more dashes. Cannot start with dash.
12681268
imageName = imageName.replaceAll("[^a-zA-Z0-9]", "-").replaceAll("^[\\-]+", "").toLowerCase();
12691269

1270-
StringBuilder sb = new StringBuilder();
1271-
sb.append(getContainerCommandPrefix());
1272-
sb.append(" build ");
1270+
// Use List<String> for building the command. This will be converted to a String[] when passed to ProcessBuilder.
1271+
// The ProcessBuilder will handle quoting of paths (for blanks) as needed for various OS.
1272+
List<String> commandElements = new ArrayList<String>();
1273+
commandElements.add(getContainerCommandPrefix().trim());
1274+
commandElements.add("build");
1275+
12731276
if (pullParentImage) {
1274-
sb.append("--pull ");
1277+
commandElements.add("--pull");
12751278
}
1276-
sb.append("-f " + tempContainerfile + " -t " + imageName + " " + buildContext.getAbsolutePath());
1277-
String buildCmd = sb.toString();
1278-
info(buildCmd);
1279+
commandElements.add("-f");
1280+
commandElements.add(tempContainerfile.getAbsolutePath());
1281+
commandElements.add("-t");
1282+
commandElements.add(imageName);
1283+
commandElements.add(buildContext.getAbsolutePath());
1284+
1285+
String[] newCommand = commandElements.toArray(new String[commandElements.size()]);
1286+
info("Container command: "+String.join(" ", newCommand));
1287+
12791288
if (hasFeaturesSh.get()) {
12801289
info("The RUN features.sh command is detected in the Containerfile and extra time may be necessary when installing features.");
12811290
}
12821291
long startTime = System.currentTimeMillis();
12831292

1284-
execContainerCmdAndLog(getRunProcess(buildCmd), containerBuildTimeout, false);
1293+
execContainerCmdAndLog(getRunProcess(newCommand), containerBuildTimeout, false);
12851294

12861295
checkContainerBuildTime(startTime, buildContext);
12871296
info("Completed building container image.");
@@ -1337,8 +1346,8 @@ private void startContainer() throws PluginExecutionException {
13371346
new File(buildDirectory, DEVC_HIDDEN_FOLDER + "/dropins").mkdirs();
13381347

13391348
info("Starting container...");
1340-
String startContainerCommand = getContainerCommand();
1341-
info(startContainerCommand);
1349+
String[] startContainerCommand = getContainerCommand();
1350+
// Use String[] instead for command parameters. It will handle quoting of paths for various OS.
13421351
containerRunProcess = getRunProcess(startContainerCommand);
13431352
execContainerCmdAndLog(containerRunProcess, 0, true);
13441353
} catch (IOException e) {
@@ -1359,9 +1368,11 @@ private void startContainer() throws PluginExecutionException {
13591368
}
13601369
}
13611370

1362-
private Process getRunProcess(String command) throws IOException {
1371+
// Pass String[] containing command and all of its individual arguments.
1372+
// This ensures proper escaping/quoting for arguments that might contain spaces or special characters.
1373+
private Process getRunProcess(String[] command) throws IOException {
13631374
ProcessBuilder processBuilder = new ProcessBuilder();
1364-
processBuilder.command(getCommandTokens(command));
1375+
processBuilder.command(command);
13651376
Map<String, String> env = processBuilder.environment();
13661377
if (!OSUtil.isLinux()){
13671378
if (!env.keySet().contains("DOCKER_BUILDKIT")) { // don't touch if already set
@@ -1569,8 +1580,14 @@ protected static File getLongestCommonDir(File dir1, File dir2) {
15691580
* the CMD attribute of the Open Liberty docker image.
15701581
* @return the command string to use to start the container
15711582
*/
1572-
private String getContainerCommand() throws IOException, PluginExecutionException {
1573-
StringBuilder command = new StringBuilder(getContainerCommandPrefix() + "run --rm");
1583+
private String[] getContainerCommand() throws IOException, PluginExecutionException {
1584+
// Use List<String> for building the command. This will be converted to a String[] when passed to ProcessBuilder.
1585+
// The ProcessBuilder will handle quoting of paths (for blanks) as needed for various OS.
1586+
List<String> commandElements = new ArrayList<String>();
1587+
commandElements.add(getContainerCommandPrefix().trim());
1588+
commandElements.add("run");
1589+
commandElements.add("--rm");
1590+
15741591
if (!skipDefaultPorts) {
15751592
int httpPortToUse, httpsPortToUse;
15761593
try {
@@ -1581,8 +1598,11 @@ private String getContainerCommand() throws IOException, PluginExecutionExceptio
15811598
httpPortToUse = LIBERTY_DEFAULT_HTTP_PORT;
15821599
httpsPortToUse = LIBERTY_DEFAULT_HTTPS_PORT;
15831600
}
1584-
command.append(" -p ").append(httpPortToUse).append(":").append(LIBERTY_DEFAULT_HTTP_PORT);
1585-
command.append(" -p ").append(httpsPortToUse).append(":").append(LIBERTY_DEFAULT_HTTPS_PORT);
1601+
commandElements.add("-p");
1602+
commandElements.add(httpPortToUse+":"+LIBERTY_DEFAULT_HTTP_PORT);
1603+
1604+
commandElements.add("-p");
1605+
commandElements.add(httpsPortToUse+":"+LIBERTY_DEFAULT_HTTPS_PORT);
15861606
}
15871607

15881608
if (libertyDebug) {
@@ -1600,34 +1620,46 @@ private String getContainerCommand() throws IOException, PluginExecutionExceptio
16001620
} catch (IOException x) {
16011621
containerDebugPort = hostDebugPort = libertyDebugPort;
16021622
}
1603-
command.append(" -p " + hostDebugPort + ":" + containerDebugPort);
1623+
commandElements.add("-p");
1624+
commandElements.add(hostDebugPort+":"+containerDebugPort);
16041625
// set environment variables in the container to ensure debug mode does not suspend the server, and to enable a custom debug port to be used
16051626
// and to allow remote debugging into the container
1606-
command.append(" -e WLP_DEBUG_SUSPEND=n -e WLP_DEBUG_ADDRESS=" + containerDebugPort + " -e WLP_DEBUG_REMOTE=y");
1627+
commandElements.add("-e");
1628+
commandElements.add("WLP_DEBUG_SUSPEND=n");
1629+
commandElements.add("-e");
1630+
commandElements.add("WLP_DEBUG_ADDRESS=" + containerDebugPort);
1631+
commandElements.add("-e");
1632+
commandElements.add("WLP_DEBUG_REMOTE=y");
16071633
}
16081634

16091635
// mount potential directories containing .war.xml from devc specific folder - override /config/apps and /config/dropins
16101636
File tempApps = new File(buildDirectory, DEVC_HIDDEN_FOLDER + "/apps");
16111637
File tempDropins = new File(buildDirectory, DEVC_HIDDEN_FOLDER + "/dropins");
1612-
command.append(" -v " + tempApps + ":/config/apps");
1613-
command.append(" -v " + tempDropins + ":/config/dropins");
1638+
commandElements.add("-v");
1639+
commandElements.add(tempApps + ":/config/apps");
1640+
1641+
commandElements.add("-v");
1642+
commandElements.add(tempDropins + ":/config/dropins");
16141643

16151644
// mount the loose application resources in the container using the appropriate project root
16161645
File looseApplicationProjectRoot = getLooseAppProjectRoot(projectDirectory, multiModuleProjectDirectory);
1617-
command.append(" -v " + looseApplicationProjectRoot.getAbsolutePath() + ":" + DEVMODE_DIR_NAME);
1646+
commandElements.add("-v");
1647+
commandElements.add(looseApplicationProjectRoot.getAbsolutePath() + ":" + DEVMODE_DIR_NAME);
16181648

16191649
// mount the server logs directory over the /logs used by the open liberty container as defined by the LOG_DIR env. var.
16201650
File logsDir = new File(serverDirectory.getAbsolutePath(), "logs");
1621-
command.append(" -v " + logsDir + ":/logs");
1651+
commandElements.add("-v");
1652+
commandElements.add(logsDir + ":/logs");
16221653

16231654
// mount the Maven .m2 cache directory for featureUtility to use. For now, featureUtility does not support Gradle cache.
1624-
command.append(" -v " + mavenCacheLocation + ":/devmode-maven-cache");
1655+
commandElements.add("-v");
1656+
commandElements.add(mavenCacheLocation + ":/devmode-maven-cache");
16251657

16261658
// mount all files from COPY commands in the Containerfile to allow for hot deployment
1627-
command.append(getCopiedFiles());
1659+
addCopiedFiles(commandElements);
16281660

16291661
// Add a --user option when running Linux
1630-
command.append(getUserId());
1662+
addUserId(commandElements);
16311663

16321664
// Do not generate a name if the user has specified a name
16331665
String name = getContainerOption("--name");
@@ -1637,26 +1669,44 @@ private String getContainerCommand() throws IOException, PluginExecutionExceptio
16371669
// now generate a name so that the container errors make some sense to the user.
16381670
}
16391671
containerName = generateNewContainerName();
1640-
command.append(" --name " + containerName);
1672+
commandElements.add("--name");
1673+
commandElements.add(containerName);
16411674
} else {
16421675
containerName = name;
16431676
}
16441677
debug("containerName: " + containerName + ".");
16451678

16461679
// Allow the user to add their own options to this command via a system property.
16471680
if (containerRunOpts != null) {
1648-
command.append(" "+containerRunOpts);
1681+
// If something in containerRunOpts contains spaces and needs quoting/escaping, this getCommandTokens method won't handle it correctly.
1682+
// But what was here before would not either.
1683+
String[] runOpts = getCommandTokens(containerRunOpts);
1684+
for (int i=0; i < runOpts.length; i++) {
1685+
commandElements.add(runOpts[i]);
1686+
}
16491687
}
16501688

16511689
// Options must precede this in any order. Image name and command code follows.
1652-
command.append(" " + imageName);
1690+
commandElements.add(imageName);
1691+
16531692
// Command to start the server
1654-
command.append(" server" + ((libertyDebug) ? " debug " : " run ") + "defaultServer");
1693+
commandElements.add("server");
1694+
if (libertyDebug) {
1695+
commandElements.add("debug");
1696+
} else {
1697+
commandElements.add("run");
1698+
}
1699+
commandElements.add("defaultServer");
1700+
16551701
// All the Liberty variable definitions must appear after the -- option.
16561702
// Important: other Liberty options must appear before --
1657-
command.append(" -- --"+DEVMODE_PROJECT_ROOT+"="+DEVMODE_DIR_NAME);
1703+
commandElements.add("--");
1704+
commandElements.add("--"+DEVMODE_PROJECT_ROOT+"="+DEVMODE_DIR_NAME);
16581705

1659-
return command.toString();
1706+
//return command.toString();
1707+
String[] newCommand = commandElements.toArray(new String[commandElements.size()]);
1708+
info("Container command: "+String.join(" ", newCommand));
1709+
return newCommand;
16601710
}
16611711

16621712
/**
@@ -1769,33 +1819,32 @@ protected static String removeSurroundingQuotes(String str) {
17691819
}
17701820

17711821
// Read all the files from the array list.
1772-
private String getCopiedFiles() {
1773-
StringBuilder param = new StringBuilder(256); // estimate of size needed
1822+
private void addCopiedFiles(List<String> commandElements) {
17741823
for (int i=0; i < srcMount.size(); i++) {
17751824
if (new File(srcMount.get(i)).exists()) { // only Files are in this list
1776-
param.append(" -v ").append(srcMount.get(i)).append(":").append(destMount.get(i));
1825+
commandElements.add("-v");
1826+
commandElements.add(srcMount.get(i)+":"+destMount.get(i));
17771827
} else {
17781828
error("A file referenced by the Containerfile is not found: " + srcMount.get(i) +
17791829
". Update the Containerfile or ensure the file is in the correct location.");
17801830
}
17811831
}
1782-
return param.toString();
17831832
}
17841833

1785-
private String getUserId() {
1834+
private void addUserId(List<String> commandElements) {
17861835
if (OSUtil.isLinux() || !isDocker) {
17871836
try {
17881837
String id = runCmd("id -u");
17891838
if (id != null) {
1790-
return " --user " + id;
1839+
commandElements.add("--user");
1840+
commandElements.add(id);
17911841
}
17921842
} catch (IOException e) {
17931843
// can't get user id. runCmd has printed an error message.
17941844
} catch (InterruptedException e) {
17951845
// can't get user id. runCmd has printed an error message.
17961846
}
17971847
}
1798-
return "";
17991848
}
18001849

18011850
public abstract void libertyCreate() throws PluginExecutionException;

0 commit comments

Comments
 (0)