Skip to content

Commit 3fc221a

Browse files
authored
Use CommandLineUtil to split and join command lines in CBS Makefile support (#1073)
Without this the build and clean command entered in the CBS settings could be parsed and re-assembled incorrectly. A simple example is that an extra space (e.g. "make clean") would lead to an error when running make like: ``` make: *** empty string invalid as file name. Stop. ``` This happened because the code used trivial split on " " and join with " " to handle parsing that command line string into array of arguments. This change fixes that by using the functionality already available in CommandLineUtil Fixes #1072
1 parent 7cb2d69 commit 3fc221a

File tree

4 files changed

+70
-40
lines changed

4 files changed

+70
-40
lines changed

NewAndNoteworthy/CHANGELOG-API.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ The following classes have been removed or modified in API breaking ways:
179179
- spelling corrected for methods with Uninitialized in the name
180180
- setWarnUnused renamed to setWarnUnusedVars and isWarnUnused renamed to isWarnUnusedVars
181181

182+
### StandardBuildConfiguration.setBuildCommand(String[]) and StandardBuildConfiguration.setCleanCommand(String[]) removed
183+
184+
These methods (in `org.eclipse.cdt.core.build.StandardBuildConfiguration`) made it difficult to save and load users build and clean command without modifying it.
185+
They have been replaced with methods that take only a `String` for consistent parsing of command lines.
186+
See [#1072](https://github.com/eclipse-cdt/cdt/issues/1072) for more details on motivation for this change.
182187

183188
## API Changes in CDT 11.5.
184189

build/org.eclipse.cdt.make.ui/src/org/eclipse/cdt/make/internal/ui/MakeBuildSettingsTab.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,19 +198,8 @@ public void performApply(ILaunchConfigurationWorkingCopy configuration) {
198198
stdConfig.setBuildContainer(stdConfig.getProject());
199199
}
200200

201-
String buildCommand = buildCmdText.getText().trim();
202-
if (!buildCommand.isEmpty()) {
203-
stdConfig.setBuildCommand(buildCommand.split(" ")); //$NON-NLS-1$
204-
} else {
205-
stdConfig.setBuildCommand(null);
206-
}
207-
208-
String cleanCommand = cleanCmdText.getText().trim();
209-
if (!cleanCommand.isEmpty()) {
210-
stdConfig.setCleanCommand(cleanCommand.split(" ")); //$NON-NLS-1$
211-
} else {
212-
stdConfig.setCleanCommand(null);
213-
}
201+
stdConfig.setBuildCommand(buildCmdText.getText());
202+
stdConfig.setCleanCommand(cleanCmdText.getText());
214203
}
215204
} catch (CoreException e) {
216205
MakeUIPlugin.log(e.getStatus());

core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/build/StandardBuildConfiguration.java

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.eclipse.cdt.core.model.ICModelMarker;
3030
import org.eclipse.cdt.core.resources.IConsole;
3131
import org.eclipse.cdt.internal.core.build.Messages;
32+
import org.eclipse.cdt.utils.CommandLineUtil;
3233
import org.eclipse.core.resources.IBuildConfiguration;
3334
import org.eclipse.core.resources.IContainer;
3435
import org.eclipse.core.resources.IProject;
@@ -62,11 +63,11 @@ public class StandardBuildConfiguration extends CBuildConfiguration {
6263
*/
6364
public static final String CLEAN_COMMAND = "stdbuild.clean.command"; //$NON-NLS-1$
6465

65-
private static final String[] DEFAULT_BUILD_COMMAND = new String[] { "make" }; //$NON-NLS-1$
66-
private static final String[] DEFAULT_CLEAN_COMMAND = new String[] { "make", "clean" }; //$NON-NLS-1$ //$NON-NLS-2$
66+
private static final String DEFAULT_BUILD_COMMAND = "make"; //$NON-NLS-1$
67+
private static final String DEFAULT_CLEAN_COMMAND = "make clean"; //$NON-NLS-1$
6768

68-
private String[] buildCommand = DEFAULT_BUILD_COMMAND;
69-
private String[] cleanCommand = DEFAULT_CLEAN_COMMAND;
69+
private String buildCommand = DEFAULT_BUILD_COMMAND;
70+
private String cleanCommand = DEFAULT_CLEAN_COMMAND;
7071
private IContainer buildContainer;
7172
private IEnvironmentVariable[] envVars;
7273

@@ -101,18 +102,18 @@ private IContainer getContainer(String containerPath) {
101102
private void applyProperties() {
102103
setBuildContainer(getProperty(BUILD_CONTAINER));
103104

104-
String buildCmd = getProperty(BUILD_COMMAND);
105-
if (buildCmd != null && !buildCmd.trim().isEmpty()) {
106-
buildCommand = buildCmd.split(" "); //$NON-NLS-1$
105+
String buildCommand = getProperty(BUILD_COMMAND);
106+
if (buildCommand != null && !buildCommand.isBlank()) {
107+
this.buildCommand = buildCommand;
107108
} else {
108-
buildCommand = DEFAULT_BUILD_COMMAND;
109+
this.buildCommand = DEFAULT_BUILD_COMMAND;
109110
}
110111

111-
String cleanCmd = getProperty(CLEAN_COMMAND);
112-
if (cleanCmd != null && !cleanCmd.trim().isEmpty()) {
113-
cleanCommand = cleanCmd.split(" "); //$NON-NLS-1$
112+
String cleanCommand = getProperty(CLEAN_COMMAND);
113+
if (cleanCommand != null && !cleanCommand.isBlank()) {
114+
this.cleanCommand = cleanCommand;
114115
} else {
115-
cleanCommand = DEFAULT_CLEAN_COMMAND;
116+
this.cleanCommand = DEFAULT_CLEAN_COMMAND;
116117
}
117118
}
118119

@@ -165,20 +166,32 @@ public void setBuildContainer(IContainer buildContainer) {
165166
}
166167
}
167168

168-
public void setBuildCommand(String[] buildCommand) {
169-
if (buildCommand != null) {
169+
/**
170+
* Set the build command to use. The string will be converted to
171+
* command line arguments using {@link CommandLineUtil}
172+
*
173+
* @since 9.0
174+
*/
175+
public void setBuildCommand(String buildCommand) {
176+
if (buildCommand != null && !buildCommand.isBlank()) {
170177
this.buildCommand = buildCommand;
171-
setProperty(BUILD_COMMAND, String.join(" ", buildCommand)); //$NON-NLS-1$
178+
setProperty(BUILD_COMMAND, buildCommand);
172179
} else {
173180
this.buildCommand = DEFAULT_BUILD_COMMAND;
174181
removeProperty(BUILD_COMMAND);
175182
}
176183
}
177184

178-
public void setCleanCommand(String[] cleanCommand) {
179-
if (cleanCommand != null) {
185+
/**
186+
* Set the build command to use. The string will be converted to
187+
* command line arguments using {@link CommandLineUtil}
188+
*
189+
* @since 9.0
190+
*/
191+
public void setCleanCommand(String cleanCommand) {
192+
if (cleanCommand != null && !cleanCommand.isBlank()) {
180193
this.cleanCommand = cleanCommand;
181-
setProperty(CLEAN_COMMAND, String.join(" ", cleanCommand)); //$NON-NLS-1$
194+
setProperty(CLEAN_COMMAND, cleanCommand);
182195
} else {
183196
this.cleanCommand = DEFAULT_CLEAN_COMMAND;
184197
removeProperty(CLEAN_COMMAND);
@@ -216,9 +229,9 @@ public String getProperty(String name) {
216229
return null;
217230
}
218231
case BUILD_COMMAND:
219-
return String.join(" ", buildCommand); //$NON-NLS-1$
232+
return buildCommand;
220233
case CLEAN_COMMAND:
221-
return String.join(" ", cleanCommand); //$NON-NLS-1$
234+
return cleanCommand;
222235
}
223236

224237
return null;
@@ -246,8 +259,9 @@ public IProject[] build(int kind, Map<String, String> args, IConsole console, IP
246259

247260
infoStream.write(String.format(Messages.StandardBuildConfiguration_0, buildDir.toString()));
248261

262+
String[] parsedBuildCommand = CommandLineUtil.argumentsToArray(buildCommand);
249263
List<String> command = new ArrayList<>();
250-
command.add(buildCommand[0]);
264+
command.add(parsedBuildCommand[0]);
251265

252266
if (!getBuildContainer().equals(getProject())) {
253267
Path makefile = Paths.get(getProject().getFile("Makefile").getLocationURI()); //$NON-NLS-1$
@@ -256,15 +270,16 @@ public IProject[] build(int kind, Map<String, String> args, IConsole console, IP
256270
command.add(relative.toString());
257271
}
258272

259-
for (int i = 1; i < buildCommand.length; i++) {
260-
command.add(buildCommand[i]);
273+
for (int i = 1; i < parsedBuildCommand.length; i++) {
274+
command.add(parsedBuildCommand[i]);
261275
}
262276

263277
try (ErrorParserManager epm = new ErrorParserManager(project, getProject().getLocationURI(), this,
264278
getToolChain().getErrorParserIds())) {
265279
epm.setOutputStream(console.getOutputStream());
266280
// run make
267-
console.getOutputStream().write(String.format("%s\n", String.join(" ", command))); //$NON-NLS-1$ //$NON-NLS-2$
281+
console.getOutputStream()
282+
.write(String.format("%s\n", CommandLineUtil.argumentsToString(command, false))); //$NON-NLS-1$
268283

269284
org.eclipse.core.runtime.Path workingDir = new org.eclipse.core.runtime.Path(
270285
getBuildDirectory().toString());
@@ -305,9 +320,9 @@ public void clean(IConsole console, IProgressMonitor monitor) throws CoreExcepti
305320
List<String> command = new ArrayList<>();
306321
List<String> buildCommand;
307322
if (cleanCommand != null) {
308-
buildCommand = Arrays.asList(cleanCommand);
323+
buildCommand = Arrays.asList(CommandLineUtil.argumentsToArray(cleanCommand));
309324
} else {
310-
buildCommand = Arrays.asList(DEFAULT_CLEAN_COMMAND);
325+
buildCommand = Arrays.asList(CommandLineUtil.argumentsToArray(DEFAULT_CLEAN_COMMAND));
311326
}
312327

313328
command.add(buildCommand.get(0));
@@ -325,7 +340,7 @@ public void clean(IConsole console, IProgressMonitor monitor) throws CoreExcepti
325340
}
326341

327342
// run make
328-
infoStream.write(String.format("%s\n", String.join(" ", command))); //$NON-NLS-1$ //$NON-NLS-2$
343+
infoStream.write(String.format("%s\n", CommandLineUtil.argumentsToString(command, false))); //$NON-NLS-1$
329344

330345
org.eclipse.core.runtime.Path workingDir = new org.eclipse.core.runtime.Path(
331346
getBuildDirectory().toString());

core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/CommandLineUtil.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package org.eclipse.cdt.utils;
1616

1717
import java.util.ArrayList;
18+
import java.util.Collection;
1819

1920
import org.eclipse.core.runtime.Platform;
2021
import org.eclipse.osgi.service.environment.Constants;
@@ -269,6 +270,26 @@ public static String[] argumentsToArrayWindowsStyle(String line) {
269270
return aList.toArray(new String[aList.size()]);
270271
}
271272

273+
/**
274+
* Converts argument array to a string suitable for passing to Bash like:
275+
*
276+
* This process reverses {@link #argumentsToArray(String)}, but does not
277+
* restore the exact same results.
278+
*
279+
* @param args
280+
* the arguments to convert and escape
281+
* @param encodeNewline
282+
* <code>true</code> if newline (<code>\r</code> or
283+
* <code>\n</code>) should be encoded
284+
*
285+
* @return args suitable for passing to some process that decodes the string
286+
* into an argument array
287+
* @since 9.0
288+
*/
289+
public static String argumentsToString(Collection<String> args, boolean encodeNewline) {
290+
return argumentsToString(args.toArray(String[]::new), encodeNewline);
291+
}
292+
272293
/**
273294
* Converts argument array to a string suitable for passing to Bash like:
274295
*

0 commit comments

Comments
 (0)