1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 533222 - Add Container Build support to Std Make Core Build

- add new getConsoleHeader() method to ICBuildCommandLauncher
  interface and ContainerCommandLauncher class
- modify MakefileBuildConfigurationProvider to create build
  configurations based on an Image name when building for Container
  and as well support the linux-container os that is used for
  Container targets
- add new IConsoleParser2 interface that extends IConsoleParser
  and adds new processLine method that takes a List of Job as
  a parameter
- make CBuildConfiguration implement IConsoleParser2 and add new
  processLine method
- modify watchProcess to recognize an IConsoleParser2 and pass
  a Job List then wait for all jobs to finish before calling
  shutdown() and possibly reindex
- add new IToolChain2 interface with startBuildProcess() method
- add new startBuildProcess() method to CBuildConfiguration
  to look for new IToolChain2 and use its startBuildProcess()
  method to perform the build
- make ContainerGCCToolChain implement IToolChain2 and add
  new startBuildProcess() method to build in Container
- change StandardBuildConfiguration to use startBuildProcess()
  to do build and clean

Change-Id: Icae9a55ef6abfa1b7f611544ad591b6062c72585
This commit is contained in:
Jeff Johnston 2018-04-04 12:50:19 -04:00
parent 864b305ff4
commit 2e99babe5b
11 changed files with 272 additions and 69 deletions

View file

@ -43,14 +43,20 @@ public class MakefileBuildConfigurationProvider implements ICBuildConfigurationP
StringBuilder configName = new StringBuilder("make."); //$NON-NLS-1$
configName.append(launchMode);
String os = toolChain.getProperty(IToolChain.ATTR_OS);
if (os != null) {
if ("linux-container".equals(os)) { //$NON-NLS-1$
String osConfigName = toolChain.getProperty("linux-container-id"); //$NON-NLS-1$
configName.append('.');
configName.append(os);
}
String arch = toolChain.getProperty(IToolChain.ATTR_ARCH);
if (arch != null && !arch.isEmpty()) {
configName.append('.');
configName.append(arch);
configName.append(osConfigName);
} else {
if (os != null) {
configName.append('.');
configName.append(os);
}
String arch = toolChain.getProperty(IToolChain.ATTR_ARCH);
if (arch != null && !arch.isEmpty()) {
configName.append('.');
configName.append(arch);
}
}
String name = configName.toString();
int i = 0;

View file

@ -68,24 +68,4 @@
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/cdt/core/build/StandardBuildConfiguration.java" type="org.eclipse.cdt.core.build.StandardBuildConfiguration">
<filter id="336658481">
<message_arguments>
<message_argument value="org.eclipse.cdt.core.build.StandardBuildConfiguration"/>
<message_argument value="BUILD_COMMAND"/>
</message_arguments>
</filter>
<filter comment="No one extends this yet." id="336658481">
<message_arguments>
<message_argument value="org.eclipse.cdt.core.build.StandardBuildConfiguration"/>
<message_argument value="BUILD_CONTAINER"/>
</message_arguments>
</filter>
<filter id="336658481">
<message_arguments>
<message_argument value="org.eclipse.cdt.core.build.StandardBuildConfiguration"/>
<message_argument value="CLEAN_COMMAND"/>
</message_arguments>
</filter>
</resource>
</component>

View file

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat - Initial Contribution
*******************************************************************************/
package org.eclipse.cdt.core;
import java.util.List;
import org.eclipse.core.runtime.jobs.Job;
/**
* @since 6.5
*
*/
public interface IConsoleParser2 extends IConsoleParser {
/**
* Process a line of output in a job
* @param s - String to process
* @param jobList - list of jobs to add to
* @return true if line processed, false otherwise
*/
boolean processLine (String s, List<Job> jobList);
}

View file

@ -34,6 +34,7 @@ import java.util.regex.Pattern;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.IBinaryParser;
import org.eclipse.cdt.core.IConsoleParser;
import org.eclipse.cdt.core.IConsoleParser2;
import org.eclipse.cdt.core.IMarkerGenerator;
import org.eclipse.cdt.core.ProblemMarkerInfo;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
@ -102,7 +103,7 @@ import com.google.gson.JsonParseException;
*/
public abstract class CBuildConfiguration extends PlatformObject
implements ICBuildConfiguration, ICBuildConfiguration2, IMarkerGenerator,
IConsoleParser, IElementChangedListener {
IConsoleParser2, IElementChangedListener {
private static final String LAUNCH_MODE = "cdt.launchMode"; //$NON-NLS-1$
@ -473,6 +474,32 @@ public abstract class CBuildConfiguration extends PlatformObject
}
return null;
}
/**
* @since 6.5
*/
public Process startBuildProcess(List<String> commands, IEnvironmentVariable[] envVars, IConsole console, IProgressMonitor monitor) throws IOException, CoreException {
Process process = null;
IToolChain tc = getToolChain();
if (tc instanceof IToolChain2) {
process = ((IToolChain2)tc).startBuildProcess(this, commands, getBuildDirectory().toString(), envVars, console, monitor);
} else {
// verify command can be found locally on path
Path commandPath = findCommand(commands.get(0));
if (commandPath == null) {
console.getErrorStream()
.write(String.format(Messages.CBuildConfiguration_CommandNotFound, commands.get(0)));
return null;
}
commands.set(0, commandPath.toString());
ProcessBuilder processBuilder = new ProcessBuilder(commands)
.directory(getBuildDirectory().toFile());
setBuildEnvironment(processBuilder.environment());
process = processBuilder.start();
}
return process;
}
@Deprecated
protected int watchProcess(Process process, IConsoleParser[] consoleParsers, IConsole console)
@ -503,8 +530,8 @@ public abstract class CBuildConfiguration extends PlatformObject
*/
protected int watchProcess(Process process, IConsoleParser[] consoleParsers)
throws CoreException {
new ReaderThread(process.getInputStream(), consoleParsers).start();
new ReaderThread(process.getErrorStream(), consoleParsers).start();
new ReaderThread(this, process.getInputStream(), consoleParsers).start();
new ReaderThread(this, process.getErrorStream(), consoleParsers).start();
try {
return process.waitFor();
} catch (InterruptedException e) {
@ -514,11 +541,13 @@ public abstract class CBuildConfiguration extends PlatformObject
}
private static class ReaderThread extends Thread {
CBuildConfiguration config;
private final BufferedReader in;
private final IConsoleParser[] consoleParsers;
private final PrintStream out;
public ReaderThread(InputStream in, IConsoleParser[] consoleParsers) {
public ReaderThread(CBuildConfiguration config, InputStream in, IConsoleParser[] consoleParsers) {
this.config = config;
this.in = new BufferedReader(new InputStreamReader(in));
this.out = null;
this.consoleParsers = consoleParsers;
@ -528,17 +557,25 @@ public abstract class CBuildConfiguration extends PlatformObject
this.in = new BufferedReader(new InputStreamReader(in));
this.out = new PrintStream(out);
this.consoleParsers = null;
this.config = null;
}
@Override
public void run() {
List<Job> jobList = new ArrayList<>();
try {
for (String line = in.readLine(); line != null; line = in.readLine()) {
if (consoleParsers != null) {
for (IConsoleParser consoleParser : consoleParsers) {
// Synchronize to avoid interleaving of lines
synchronized (consoleParser) {
consoleParser.processLine(line);
// if we have an IConsoleParser2, use the processLine method that
// takes a job list (Container Build support)
if (consoleParser instanceof IConsoleParser2) {
((IConsoleParser2)consoleParser).processLine(line, jobList);
} else {
consoleParser.processLine(line);
}
}
}
}
@ -546,6 +583,16 @@ public abstract class CBuildConfiguration extends PlatformObject
out.println(line);
}
}
for (Job j : jobList) {
try {
j.join();
} catch (InterruptedException e) {
// ignore
}
}
if (config != null) {
config.shutdown();
}
} catch (IOException e) {
CCorePlugin.log(e);
}
@ -939,7 +986,8 @@ public abstract class CBuildConfiguration extends PlatformObject
*
* @since 6.5
*/
protected boolean processLine(String line, List<Job> jobsArray) {
@Override
public boolean processLine(String line, List<Job> jobsArray) {
// Split line into args, taking into account quotes
List<String> command = stripArgs(line);
@ -1036,7 +1084,8 @@ public abstract class CBuildConfiguration extends PlatformObject
* @throws CoreException
*/
protected void refreshScannerInfo() throws CoreException {
// do nothing by default
CCorePlugin.getIndexManager().reindex(CoreModel.getDefault().create(getProject()));
infoChanged = false;
}
@Override

View file

@ -28,5 +28,10 @@ public interface ICBuildCommandLauncher {
* @param config - CBuildConfiguration to register
*/
public void setBuildConfiguration(ICBuildConfiguration config);
/**
* Get any special console header (e.g. Container Image used)
*/
public String getConsoleHeader();
}

View file

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2018 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat Inc. - initial version
*******************************************************************************/
package org.eclipse.cdt.core.build;
import java.io.IOException;
import java.util.List;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* @since 6.5
* @author jjohnstn
*
*/
public interface IToolChain2 {
public Process startBuildProcess(ICBuildConfiguration config, List<String> command, String buildDirectory, IEnvironmentVariable[] envVars,
IConsole console, IProgressMonitor monitor) throws CoreException, IOException;
}

View file

@ -229,26 +229,22 @@ public class StandardBuildConfiguration extends CBuildConfiguration {
project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
ConsoleOutputStream outStream = console.getOutputStream();
Path buildDir = getBuildDirectory();
outStream.write(String.format(Messages.StandardBuildConfiguration_0, buildDir.toString()));
Path make = findCommand(buildCommand[0]);
if (make == null) {
console.getErrorStream()
.write(String.format(Messages.StandardBuildConfiguration_CommandNotFound, buildCommand[0]));
return null;
}
List<String> command = new ArrayList<>();
command.add(make.toString());
command.add(buildCommand[0]);
if (!getBuildContainer().equals(getProject())) {
Path makefile = Paths.get(getProject().getFile("Makefile").getLocationURI()); //$NON-NLS-1$
Path relative = getBuildDirectory().relativize(makefile);
command.add("-f"); //$NON-NLS-1$
command.add(relative.toString());
}
for (int i = 1; i < buildCommand.length; i++) {
command.add(buildCommand[i]);
}
@ -258,19 +254,23 @@ public class StandardBuildConfiguration extends CBuildConfiguration {
epm.setOutputStream(console.getOutputStream());
// run make
console.getOutputStream().write(String.format("%s\n", String.join(" ", command))); //$NON-NLS-1$ //$NON-NLS-2$
ProcessBuilder processBuilder = new ProcessBuilder(command)
.directory(getBuildDirectory().toFile());
setBuildEnvironment(processBuilder.environment());
Process process = processBuilder.start();
Process p = startBuildProcess(command, envVars, console, monitor);
if (p == null) {
console.getErrorStream().write(String.format(Messages.StandardBuildConfiguration_Failure, "")); //$NON-NLS-1$
return null;
}
IConsoleParser[] consoleParsers = new IConsoleParser[] { epm, this };
watchProcess(process, consoleParsers);
watchProcess(p, consoleParsers);
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
outStream.write(String.format(Messages.StandardBuildConfiguration_1, epm.getErrorCount(),
epm.getWarningCount(), buildDir.toString()));
}
return new IProject[] { project };
} catch (IOException e) {
throw new CoreException(
@ -285,29 +285,45 @@ public class StandardBuildConfiguration extends CBuildConfiguration {
project.deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
ConsoleOutputStream outStream = console.getOutputStream();
Path buildDir = getBuildDirectory();
outStream.write(String.format(Messages.StandardBuildConfiguration_0, buildDir.toString()));
List<String> command;
List<String> command = new ArrayList<>();
List<String> buildCommand;
if (cleanCommand != null) {
command = Arrays.asList(cleanCommand);
buildCommand = Arrays.asList(cleanCommand);
} else {
command = new ArrayList<>();
command.add(findCommand("make").toString()); //$NON-NLS-1$
if (!getBuildContainer().equals(getProject())) {
Path makefile = Paths.get(getProject().getFile("Makefile").getLocationURI()); //$NON-NLS-1$
Path relative = getBuildDirectory().relativize(makefile);
command.add("-f"); //$NON-NLS-1$
command.add(relative.toString());
}
command.add("clean"); //$NON-NLS-1$
buildCommand = Arrays.asList(DEFAULT_CLEAN_COMMAND);
}
command.add(buildCommand.get(0));
// we need to add -f if the makefile isn't in the build directory
if (!getBuildContainer().equals(getProject())) {
Path makefile = Paths.get(getProject().getFile("Makefile").getLocationURI()); //$NON-NLS-1$
Path relative = getBuildDirectory().relativize(makefile);
command.add("-f"); //$NON-NLS-1$
command.add(relative.toString());
}
for (int i = 1; i < buildCommand.size(); ++i) {
command.add(buildCommand.get(i));
}
// run make
outStream.write(String.format("%s\n", String.join(" ", command))); //$NON-NLS-1$ //$NON-NLS-2$
ProcessBuilder processBuilder = new ProcessBuilder(command)
.directory(getBuildDirectory().toFile());
setBuildEnvironment(processBuilder.environment());
Process process = processBuilder.start();
watchProcess(process, console);
Process p = startBuildProcess(command, envVars, console, monitor);
if (p == null) {
console.getErrorStream().write(String.format(Messages.StandardBuildConfiguration_Failure, "")); //$NON-NLS-1$
return;
}
watchProcess(p, console);
outStream.write(Messages.CBuildConfiguration_BuildComplete);
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
} catch (IOException e) {

View file

@ -19,9 +19,11 @@ public class Messages extends NLS {
public static String CBuilder_ExceptionWhileBuilding2;
public static String CBuilder_NotConfiguredCorrectly;
public static String CBuilder_NotConfiguredCorrectly2;
public static String CBuildConfiguration_CommandNotFound;
public static String CBuildConfiguration_BuildComplete;
public static String StandardBuildConfiguration_0;
public static String StandardBuildConfiguration_1;
public static String StandardBuildConfiguration_CommandNotFound;
public static String StandardBuildConfiguration_Failure;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);

View file

@ -11,7 +11,9 @@ CBuilder_NotConfiguredCorrectly=Build not configured correctly\n
CBuilder_NotConfiguredCorrectly2=Build not configured correctly\n
StandardBuildConfiguration_0=Building in: %s\n
StandardBuildConfiguration_1=Build complete (%d errors, %d warnings): %s\n
StandardBuildConfiguration_CommandNotFound=Error: build command '%s' not found
StandardBuildConfiguration_Failure=Error: %s
CBuildConfiguration_BuildComplete=Build complete\n
CBuildConfiguration_CommandNotFound=Error: build command '%s' not found
CBuildConfiguration_CreateJob=Create Build Folder
CBuildConfiguration_Location=line %d, external location: %s
CBuildConfiguration_ToolchainMissing=Toolchain is missing for build configuration

View file

@ -322,6 +322,33 @@ public class ContainerCommandLauncher
return fProcess;
}
private String calculateImageName() {
ICBuildConfiguration buildCfg = getBuildConfiguration();
String imageName = ""; //$NON-NLS-1$
if (buildCfg != null) {
IToolChain toolChain;
try {
toolChain = buildCfg.getToolChain();
} catch (CoreException e) {
return imageName;
}
imageName = toolChain
.getProperty(IContainerLaunchTarget.ATTR_IMAGE_ID);
} else {
ICConfigurationDescription cfgd = CoreModel.getDefault()
.getProjectDescription(fProject).getActiveConfiguration();
IConfiguration cfg = ManagedBuildManager
.getConfigurationForDescription(cfgd);
if (cfg == null) {
return imageName;
}
IOptionalBuildProperties props = cfg.getOptionalBuildProperties();
imageName = props.getProperty(ContainerCommandLauncher.IMAGE_ID);
}
return imageName;
}
/**
* Parse array of "ENV=value" pairs to Properties.
*/
@ -427,6 +454,12 @@ public class ContainerCommandLauncher
}
}
@Override
public String getConsoleHeader() {
return NLS.bind(Messages.ContainerCommandLauncher_image_msg,
calculateImageName()) + NEWLINE;
}
protected void printCommandLine(OutputStream os) {
if (os != null) {
try {

View file

@ -29,8 +29,10 @@ import java.util.regex.Pattern;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CommandLauncherManager;
import org.eclipse.cdt.core.ICommandLauncher;
import org.eclipse.cdt.core.build.ICBuildCommandLauncher;
import org.eclipse.cdt.core.build.ICBuildConfiguration;
import org.eclipse.cdt.core.build.IToolChain;
import org.eclipse.cdt.core.build.IToolChain2;
import org.eclipse.cdt.core.build.IToolChainProvider;
import org.eclipse.cdt.core.dom.ast.gnu.c.GCCLanguage;
import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage;
@ -38,6 +40,7 @@ import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.model.ILanguage;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.docker.launcher.ContainerCommandLauncher;
import org.eclipse.cdt.docker.launcher.ContainerTargetTypeProvider;
import org.eclipse.cdt.docker.launcher.DockerLaunchUIPlugin;
@ -48,6 +51,7 @@ import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.PlatformObject;
@ -59,7 +63,8 @@ import org.eclipse.linuxtools.docker.ui.Activator;
*
* @since 1.2
*/
public class ContainerGCCToolChain extends PlatformObject implements IToolChain {
public class ContainerGCCToolChain extends PlatformObject
implements IToolChain, IToolChain2 {
public static final String TYPE_ID = "org.eclipse.cdt.docker.launcher.gcc"; //$NON-NLS-1$
@ -601,4 +606,47 @@ public class ContainerGCCToolChain extends PlatformObject implements IToolChain
return result;
}
@Override
public Process startBuildProcess(ICBuildConfiguration config,
List<String> command, String buildDirectory,
IEnvironmentVariable[] envVars, IConsole console,
IProgressMonitor monitor) throws CoreException, IOException {
IPath cmdPath = new org.eclipse.core.runtime.Path("/usr/bin/env"); //$NON-NLS-1$
List<String> argList = new ArrayList<>();
for (IEnvironmentVariable var : envVars) {
argList.add(var.getName() + "=" + var.getValue()); //$NON-NLS-1$
}
argList.add("sh"); //$NON-NLS-1$
argList.add("-c"); //$NON-NLS-1$
StringBuffer buf = new StringBuffer();
for (String s : command) {
buf.append(s);
buf.append(" "); //$NON-NLS-1$
}
buf.deleteCharAt(buf.length() - 1); // remove last blank;
argList.add(buf.toString());
ICommandLauncher launcher = CommandLauncherManager.getInstance()
.getCommandLauncher(config);
launcher.setProject(config.getBuildConfiguration().getProject());
if (launcher instanceof ICBuildCommandLauncher) {
((ICBuildCommandLauncher) launcher).setBuildConfiguration(config);
console.getOutputStream().write(
((ICBuildCommandLauncher) launcher).getConsoleHeader());
}
org.eclipse.core.runtime.Path workingDir = new org.eclipse.core.runtime.Path(
buildDirectory);
Process p = launcher.execute(cmdPath, argList.toArray(new String[0]),
new String[0], workingDir, monitor);
return p;
}
}