/*******************************************************************************
* Copyright (c) 2010, 2016 Wind River Systems 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:
* Wind River Systems - Initial API and implementation
* James Blackburn (Broadcom Corp.)
* Andrew Gvozdev
* IBM Corporation
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.core;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext;
import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set;
import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ErrorParserManager;
import org.eclipse.cdt.core.ICommandLauncher;
import org.eclipse.cdt.core.IConsoleParser;
import org.eclipse.cdt.core.IMarkerGenerator;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariableManager;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.internal.core.BuildRunnerHelper;
import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2;
import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoConsoleParser;
import org.eclipse.cdt.make.internal.core.scannerconfig.ScannerInfoConsoleParserFactory;
import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages;
import org.eclipse.cdt.managedbuilder.macros.BuildMacroException;
import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider;
import org.eclipse.cdt.utils.CommandLineUtil;
import org.eclipse.cdt.utils.EFSExtensionManager;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
/**
* @author dschaefer
* @since 8.0
*/
public class ExternalBuildRunner extends AbstractBuildRunner {
private static final int PROGRESS_MONITOR_SCALE = 100;
private static final int TICKS_STREAM_PROGRESS_MONITOR = 1 * PROGRESS_MONITOR_SCALE;
private static final int TICKS_DELETE_MARKERS = 1 * PROGRESS_MONITOR_SCALE;
private static final int TICKS_EXECUTE_COMMAND = 1 * PROGRESS_MONITOR_SCALE;
private static final int TICKS_REFRESH_PROJECT = 1 * PROGRESS_MONITOR_SCALE;
@Override
public boolean invokeBuild(int kind, IProject project, IConfiguration configuration,
IBuilder builder, IConsole console, IMarkerGenerator markerGenerator,
IncrementalProjectBuilder projectBuilder, IProgressMonitor monitor) throws CoreException {
return invokeExternalBuild(kind, project, configuration, builder, console,
markerGenerator, projectBuilder, monitor);
}
protected boolean invokeExternalBuild(int kind, IProject project, IConfiguration configuration,
IBuilder builder, IConsole console, IMarkerGenerator markerGenerator,
IncrementalProjectBuilder projectBuilder, IProgressMonitor monitor) throws CoreException {
boolean isClean = false;
BuildRunnerHelper buildRunnerHelper = new BuildRunnerHelper(project);
try {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask(ManagedMakeMessages.getResourceString("MakeBuilder.Invoking_Make_Builder") + project.getName(), //$NON-NLS-1$
TICKS_STREAM_PROGRESS_MONITOR + TICKS_DELETE_MARKERS + TICKS_EXECUTE_COMMAND + TICKS_REFRESH_PROJECT);
IPath buildCommand = builder.getBuildCommand();
if (buildCommand != null) {
String cfgName = configuration.getName();
String toolchainName = configuration.getToolChain().getName();
boolean isSupported = configuration.isSupported();
ICommandLauncher launcher = builder.getCommandLauncher();
String[] targets = getTargets(kind, builder);
if (targets.length != 0 && targets[targets.length - 1].equals(builder.getCleanBuildTarget()))
isClean = true;
boolean isOnlyClean = isClean && (targets.length == 1);
String[] args = getCommandArguments(builder, targets);
URI workingDirectoryURI = ManagedBuildManager.getBuildLocationURI(configuration, builder);
Map<String, String> envMap = getEnvironment(builder);
String[] envp = BuildRunnerHelper.envMapToEnvp(envMap);
String[] errorParsers = builder.getErrorParsers();
ErrorParserManager epm = new ErrorParserManager(project, workingDirectoryURI, markerGenerator, errorParsers);
List<IConsoleParser> parsers = new ArrayList<IConsoleParser>();
if (!isOnlyClean) {
ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(configuration);
ManagedBuildManager.collectLanguageSettingsConsoleParsers(cfgDescription, epm, parsers);
if (ScannerDiscoveryLegacySupport.isLegacyScannerDiscoveryOn(cfgDescription)) {
collectScannerInfoConsoleParsers(project, configuration, workingDirectoryURI, markerGenerator, parsers);
}
}
buildRunnerHelper.setLaunchParameters(launcher, buildCommand, args, workingDirectoryURI, envp);
buildRunnerHelper.prepareStreams(epm, parsers, console, new SubProgressMonitor(monitor, TICKS_STREAM_PROGRESS_MONITOR));
buildRunnerHelper.removeOldMarkers(project, new SubProgressMonitor(monitor, TICKS_DELETE_MARKERS, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
buildRunnerHelper.greeting(kind, cfgName, toolchainName, isSupported);
int state = buildRunnerHelper.build(new SubProgressMonitor(monitor, TICKS_EXECUTE_COMMAND, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
buildRunnerHelper.close();
buildRunnerHelper.goodbye();
if (state != ICommandLauncher.ILLEGAL_COMMAND) {
buildRunnerHelper.refreshProject(cfgName, new SubProgressMonitor(monitor, TICKS_REFRESH_PROJECT, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK));
}
} else {
String msg = ManagedMakeMessages.getFormattedString("ManagedMakeBuilder.message.undefined.build.command", builder.getId()); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, msg, new Exception()));
}
} catch (Exception e) {
String msg = ManagedMakeMessages.getFormattedString("ManagedMakeBuilder.message.error.build", //$NON-NLS-1$
new String[] { project.getName(), configuration.getName() });
throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.PLUGIN_ID, msg, e));
} finally {
try {
buildRunnerHelper.close();
} catch (IOException e) {
ManagedBuilderCorePlugin.log(e);
}
monitor.done();
}
return isClean;
}
private String[] getCommandArguments(IBuilder builder, String[] targets) {
String[] builderArgs = CommandLineUtil.argumentsToArray(builder.getBuildArguments());
String[] args = new String[targets.length + builderArgs.length];
System.arraycopy(builderArgs, 0, args, 0, builderArgs.length);
System.arraycopy(targets, 0, args, builderArgs.length, targets.length);
return args;
}
protected String[] getTargets(int kind, IBuilder builder) {
String targetsArray[] = null;
if(kind != IncrementalProjectBuilder.CLEAN_BUILD && !builder.isCustomBuilder() && builder.isManagedBuildOn()){
IConfiguration cfg = builder.getParent().getParent();
String preBuildStep = cfg.getPrebuildStep();
try {
preBuildStep = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(
preBuildStep,
"", //$NON-NLS-1$
" ", //$NON-NLS-1$
IBuildMacroProvider.CONTEXT_CONFIGURATION,
cfg);
} catch (BuildMacroException e) {
}
if(preBuildStep != null && preBuildStep.length() != 0){
targetsArray = new String[]{"pre-build", "main-build"}; //$NON-NLS-1$ //$NON-NLS-2$
}
}
if(targetsArray == null){
String targets = ""; //$NON-NLS-1$
switch (kind) {
case IncrementalProjectBuilder.AUTO_BUILD :
targets = builder.getAutoBuildTarget();
break;
case IncrementalProjectBuilder.INCREMENTAL_BUILD : // now treated as the same!
case IncrementalProjectBuilder.FULL_BUILD :
targets = builder.getIncrementalBuildTarget();
break;
case IncrementalProjectBuilder.CLEAN_BUILD :
targets = builder.getCleanBuildTarget();
break;
}
targetsArray = CommandLineUtil.argumentsToArray(targets);
}
return targetsArray;
}
protected Map<String, String> getEnvironment(IBuilder builder) throws CoreException {
Map<String, String> envMap = new HashMap<String, String>();
if (builder.appendEnvironment()) {
ICConfigurationDescription cfgDes = ManagedBuildManager.getDescriptionForConfiguration(builder.getParent().getParent());
IEnvironmentVariableManager mngr = CCorePlugin.getDefault().getBuildEnvironmentManager();
IEnvironmentVariable[] vars = mngr.getVariables(cfgDes, true);
for (IEnvironmentVariable var : vars) {
envMap.put(var.getName(), var.getValue());
}
}
// Add variables from build info
Map<String, String> builderEnv = builder.getExpandedEnvironment();
if (builderEnv != null)
envMap.putAll(builderEnv);
return envMap;
}
@Deprecated
protected static String[] getEnvStrings(Map<String, String> env) {
// Convert into env strings
List<String> strings= new ArrayList<String>(env.size());
for (Entry<String, String> entry : env.entrySet()) {
StringBuilder buffer= new StringBuilder(entry.getKey());
buffer.append('=').append(entry.getValue());
strings.add(buffer.toString());
}
return strings.toArray(new String[strings.size()]);
}
private static void collectScannerInfoConsoleParsers(IProject project, IConfiguration cfg, URI workingDirectoryURI,
IMarkerGenerator markerGenerator, List<IConsoleParser> parsers) {
ICfgScannerConfigBuilderInfo2Set container = CfgScannerConfigProfileManager.getCfgScannerConfigBuildInfo(cfg);
Map<CfgInfoContext, IScannerConfigBuilderInfo2> map = container.getInfoMap();
String pathFromURI = EFSExtensionManager.getDefault().getPathFromURI(workingDirectoryURI);
if(pathFromURI == null) {
// fallback to CWD
pathFromURI = System.getProperty("user.dir"); //$NON-NLS-1$
}
IPath workingDirectory = new Path(pathFromURI);
int oldSize = parsers.size();
if(container.isPerRcTypeDiscovery()){
for (IResourceInfo rcInfo : cfg.getResourceInfos()) {
ITool tools[];
if(rcInfo instanceof IFileInfo){
tools = ((IFileInfo)rcInfo).getToolsToInvoke();
} else {
tools = ((IFolderInfo)rcInfo).getFilteredTools();
}
for (ITool tool : tools) {
IInputType[] types = tool.getInputTypes();
if(types.length != 0){
for (IInputType type : types) {
CfgInfoContext context = new CfgInfoContext(rcInfo, tool, type);
IScannerInfoConsoleParser parser = getScannerInfoConsoleParser(project, map, context, workingDirectory, markerGenerator);
if (parser != null) {
parsers.add(parser);
}
}
} else {
CfgInfoContext context = new CfgInfoContext(rcInfo, tool, null);
IScannerInfoConsoleParser parser = getScannerInfoConsoleParser(project, map, context, workingDirectory, markerGenerator);
if (parser != null) {
parsers.add(parser);
}
}
}
}
}
if(parsers.size() == oldSize){
CfgInfoContext context = new CfgInfoContext(cfg);
IScannerInfoConsoleParser parser = getScannerInfoConsoleParser(project, map, context, workingDirectory, markerGenerator);
if (parser != null) {
parsers.add(parser);
}
}
}
private static IScannerInfoConsoleParser getScannerInfoConsoleParser(IProject project, Map<CfgInfoContext, IScannerConfigBuilderInfo2> map,
CfgInfoContext context, IPath workingDirectory, IMarkerGenerator markerGenerator) {
return ScannerInfoConsoleParserFactory.getScannerInfoConsoleParser(project, context.toInfoContext(), workingDirectory, map.get(context), markerGenerator, null);
}
}