@@ -1267,21 +1267,30 @@ private void buildContainerImage(File tempContainerfile, File userContainerfile,
1267
1267
// Name rules: may contain lowercase letters, digits and a period, one or two underscores, or one or more dashes. Cannot start with dash.
1268
1268
imageName = imageName .replaceAll ("[^a-zA-Z0-9]" , "-" ).replaceAll ("^[\\ -]+" , "" ).toLowerCase ();
1269
1269
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
+
1273
1276
if (pullParentImage ) {
1274
- sb . append ("--pull " );
1277
+ commandElements . add ("--pull" );
1275
1278
}
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
+
1279
1288
if (hasFeaturesSh .get ()) {
1280
1289
info ("The RUN features.sh command is detected in the Containerfile and extra time may be necessary when installing features." );
1281
1290
}
1282
1291
long startTime = System .currentTimeMillis ();
1283
1292
1284
- execContainerCmdAndLog (getRunProcess (buildCmd ), containerBuildTimeout , false );
1293
+ execContainerCmdAndLog (getRunProcess (newCommand ), containerBuildTimeout , false );
1285
1294
1286
1295
checkContainerBuildTime (startTime , buildContext );
1287
1296
info ("Completed building container image." );
@@ -1337,8 +1346,8 @@ private void startContainer() throws PluginExecutionException {
1337
1346
new File (buildDirectory , DEVC_HIDDEN_FOLDER + "/dropins" ).mkdirs ();
1338
1347
1339
1348
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.
1342
1351
containerRunProcess = getRunProcess (startContainerCommand );
1343
1352
execContainerCmdAndLog (containerRunProcess , 0 , true );
1344
1353
} catch (IOException e ) {
@@ -1359,9 +1368,11 @@ private void startContainer() throws PluginExecutionException {
1359
1368
}
1360
1369
}
1361
1370
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 {
1363
1374
ProcessBuilder processBuilder = new ProcessBuilder ();
1364
- processBuilder .command (getCommandTokens ( command ) );
1375
+ processBuilder .command (command );
1365
1376
Map <String , String > env = processBuilder .environment ();
1366
1377
if (!OSUtil .isLinux ()){
1367
1378
if (!env .keySet ().contains ("DOCKER_BUILDKIT" )) { // don't touch if already set
@@ -1569,8 +1580,14 @@ protected static File getLongestCommonDir(File dir1, File dir2) {
1569
1580
* the CMD attribute of the Open Liberty docker image.
1570
1581
* @return the command string to use to start the container
1571
1582
*/
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
+
1574
1591
if (!skipDefaultPorts ) {
1575
1592
int httpPortToUse , httpsPortToUse ;
1576
1593
try {
@@ -1581,8 +1598,11 @@ private String getContainerCommand() throws IOException, PluginExecutionExceptio
1581
1598
httpPortToUse = LIBERTY_DEFAULT_HTTP_PORT ;
1582
1599
httpsPortToUse = LIBERTY_DEFAULT_HTTPS_PORT ;
1583
1600
}
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 );
1586
1606
}
1587
1607
1588
1608
if (libertyDebug ) {
@@ -1600,34 +1620,46 @@ private String getContainerCommand() throws IOException, PluginExecutionExceptio
1600
1620
} catch (IOException x ) {
1601
1621
containerDebugPort = hostDebugPort = libertyDebugPort ;
1602
1622
}
1603
- command .append (" -p " + hostDebugPort + ":" + containerDebugPort );
1623
+ commandElements .add ("-p" );
1624
+ commandElements .add (hostDebugPort +":" +containerDebugPort );
1604
1625
// 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
1605
1626
// 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" );
1607
1633
}
1608
1634
1609
1635
// mount potential directories containing .war.xml from devc specific folder - override /config/apps and /config/dropins
1610
1636
File tempApps = new File (buildDirectory , DEVC_HIDDEN_FOLDER + "/apps" );
1611
1637
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" );
1614
1643
1615
1644
// mount the loose application resources in the container using the appropriate project root
1616
1645
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 );
1618
1648
1619
1649
// mount the server logs directory over the /logs used by the open liberty container as defined by the LOG_DIR env. var.
1620
1650
File logsDir = new File (serverDirectory .getAbsolutePath (), "logs" );
1621
- command .append (" -v " + logsDir + ":/logs" );
1651
+ commandElements .add ("-v" );
1652
+ commandElements .add (logsDir + ":/logs" );
1622
1653
1623
1654
// 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" );
1625
1657
1626
1658
// mount all files from COPY commands in the Containerfile to allow for hot deployment
1627
- command . append ( getCopiedFiles () );
1659
+ addCopiedFiles ( commandElements );
1628
1660
1629
1661
// Add a --user option when running Linux
1630
- command . append ( getUserId () );
1662
+ addUserId ( commandElements );
1631
1663
1632
1664
// Do not generate a name if the user has specified a name
1633
1665
String name = getContainerOption ("--name" );
@@ -1637,26 +1669,44 @@ private String getContainerCommand() throws IOException, PluginExecutionExceptio
1637
1669
// now generate a name so that the container errors make some sense to the user.
1638
1670
}
1639
1671
containerName = generateNewContainerName ();
1640
- command .append (" --name " + containerName );
1672
+ commandElements .add ("--name" );
1673
+ commandElements .add (containerName );
1641
1674
} else {
1642
1675
containerName = name ;
1643
1676
}
1644
1677
debug ("containerName: " + containerName + "." );
1645
1678
1646
1679
// Allow the user to add their own options to this command via a system property.
1647
1680
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
+ }
1649
1687
}
1650
1688
1651
1689
// Options must precede this in any order. Image name and command code follows.
1652
- command .append (" " + imageName );
1690
+ commandElements .add (imageName );
1691
+
1653
1692
// 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
+
1655
1701
// All the Liberty variable definitions must appear after the -- option.
1656
1702
// 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 );
1658
1705
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 ;
1660
1710
}
1661
1711
1662
1712
/**
@@ -1769,33 +1819,32 @@ protected static String removeSurroundingQuotes(String str) {
1769
1819
}
1770
1820
1771
1821
// 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 ) {
1774
1823
for (int i =0 ; i < srcMount .size (); i ++) {
1775
1824
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 ));
1777
1827
} else {
1778
1828
error ("A file referenced by the Containerfile is not found: " + srcMount .get (i ) +
1779
1829
". Update the Containerfile or ensure the file is in the correct location." );
1780
1830
}
1781
1831
}
1782
- return param .toString ();
1783
1832
}
1784
1833
1785
- private String getUserId ( ) {
1834
+ private void addUserId ( List < String > commandElements ) {
1786
1835
if (OSUtil .isLinux () || !isDocker ) {
1787
1836
try {
1788
1837
String id = runCmd ("id -u" );
1789
1838
if (id != null ) {
1790
- return " --user " + id ;
1839
+ commandElements .add ("--user" );
1840
+ commandElements .add (id );
1791
1841
}
1792
1842
} catch (IOException e ) {
1793
1843
// can't get user id. runCmd has printed an error message.
1794
1844
} catch (InterruptedException e ) {
1795
1845
// can't get user id. runCmd has printed an error message.
1796
1846
}
1797
1847
}
1798
- return "" ;
1799
1848
}
1800
1849
1801
1850
public abstract void libertyCreate () throws PluginExecutionException ;
0 commit comments