blob: 143b0e6a1d123dee3c517c83f2ef340ec4a531e5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2015 Broadcom Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Broadcom Corporation - initial API and implementation
* Clare Richardson (Motorola) - Bug 281397 building specific configs
* Dmitry Kozlov (CodeSourcery) - Bug 309909 Headless build import fails
* silently with relative pathname
* - Bug 300554 Build status not propagated
* to exit code
* R. Zulliger, C. Walther (Indel AG) - Bug 355609 Disable indexer
* John Dallaway - Bug 513763 Save workspace on conclusion
* Torbjörn Svensson (STMicroelectronics) - bug #330204
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.core;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.IPDOMManager;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.resources.ACBuilder;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.internal.core.envvar.EnvironmentVariableManager;
import org.eclipse.cdt.internal.core.pdom.PDOMManager;
import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo;
import org.eclipse.cdt.managedbuilder.core.IManagedProject;
import org.eclipse.cdt.managedbuilder.core.IOption;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceDescription;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
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.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.osgi.service.datalocation.Location;
/**
* A headless builder for CDT with additional features.
*
* IApplication ID: org.eclipse.cdt.managedbuilder.core.headlessbuild
* Provides:
* - Import projects : -import {[uri:/]/path/to/project}
* - Import all projects in the tree : -importAll {[uri:/]/path/to/projectTreeURI}
* - Build projects / the workspace : -build {project_name_reg_ex/config_name_reg_ex | all}
* - Clean build projects / the workspace : -cleanBuild {project_name_reg_ex/config_name_reg_ex | all}
* - Add Include path to build : -I {include_path}
* - Add Include file to build : -include {include_file}
* - Add preprocessor define to build : -D {prepoc_define}
* - Replace environment variable in build : -E {var=value}
* - Append environment variable to build : -Ea {var=value}
* - Prepend environment variable to build : -Ep {var=value}
* - Remove environment variable in build : -Er {var}
* - Replace a tool option value: -T {toolid} {optionid=value}
* - Append to a tool option value: -Ta {toolid} {optionid=value}
* - Prepend to a tool option value: -Tp {toolid} {optionid=value}
* - Remove a tool option: -Tr {toolid} {optionid=value}
* - Disable indexer: -no-indexer
* - Error marker types to consider: -markerType {all | cdt | marker_id}
* where:
* all is all markers -- default
* cdt is C/C++ Problem markers
* marker_id, e.g. org.eclipse.cdt.core.problem
* - Display all error markers: -printErrorMarkers
*
* Build output is automatically sent to stdout.
* @since 6.0
*/
public class HeadlessBuilder implements IApplication {
/**
* IProgressMonitor to provide printing of task
*/
public static class PrintingProgressMonitor extends NullProgressMonitor {
@Override
public void beginTask(String name, int totalWork) {
if (name != null && name.length() > 0)
System.out.println(name);
}
}
/**
* A class representing a new tool option value
*/
protected static class ToolOption {
public static final int REPLACE = 0;
public static final int APPEND = 1;
public static final int PREPEND = 2;
public static final int REMOVE = 3;
final String toolId;
final String optionId;
final String value;
final int operation;
ToolOption(String toolId, String optionId, String value, int operation) {
this.toolId = toolId;
this.optionId = optionId;
this.value = value;
this.operation = operation;
}
}
/**
* A class representing a backed-up tool option to restored at the end of the build
*/
protected static class SavedToolOption {
final String toolId;
final String optionId;
final Object value;
SavedToolOption(String toolId, String optionId, Object value) {
this.toolId = toolId;
this.optionId = optionId;
this.value = value;
}
@Override
public int hashCode() {
return toolId.hashCode() + optionId.hashCode();
}
@Override
public boolean equals(Object obj) {
SavedToolOption option = (SavedToolOption) obj;
return toolId.equals(option.toolId) && optionId.equals(option.optionId);
}
}
/** Error return status */
public static final Integer ERROR = 1;
/** OK return status */
public static final Integer OK = IApplication.EXIT_OK;
/** Show usage return status */
public static final Integer SHOW_USAGE = 2;
/** Set of project URIs / paths to import */
protected final Set<String> projectsToImport = new HashSet<>();
/** Tree of projects to recursively import */
protected final Set<String> projectTreeToImport = new HashSet<>();
/** Set of project names to build */
protected final Set<String> projectRegExToBuild = new HashSet<>();
/** Set of project names to clean */
protected final Set<String> projectRegExToClean = new HashSet<>();
protected boolean buildAll = false;
protected boolean cleanAll = false;
protected boolean disableIndexer = false;
/** List of Tool Option values being set */
protected List<ToolOption> toolOptions = new ArrayList<>();
/** Map from configuration ID -> Set of SavedToolOptions */
protected Map<String, Set<SavedToolOption>> savedToolOptions = new HashMap<>();
protected boolean markerTypesDefault = true;
protected boolean markerTypesAll = false;
protected Set<String> markerTypes = new HashSet<>();
protected boolean printErrorMarkers = false;
protected static final String MATCH_ALL_CONFIGS = ".*"; //$NON-NLS-1$
/*
* Find all project build configurations that match the regular expression ("project/config")
*/
protected Map<IProject, Set<ICConfigurationDescription>> matchConfigurations(String regularExpression,
IProject[] projectList, Map<IProject, Set<ICConfigurationDescription>> cfgMap) {
try {
int separatorIndex = regularExpression.indexOf('/');
String projectRegEx;
String configRegEx;
if (separatorIndex == -1 || separatorIndex == regularExpression.length() - 1) {
// build all configurations for this project
projectRegEx = regularExpression;
configRegEx = MATCH_ALL_CONFIGS;
} else {
projectRegEx = regularExpression.substring(0, separatorIndex);
configRegEx = regularExpression.substring(separatorIndex + 1, regularExpression.length());
}
Pattern projectPattern = Pattern.compile(projectRegEx);
Pattern configPattern = Pattern.compile(configRegEx);
// Find the projects that match the regular expression
boolean projectMatched = false;
boolean configMatched = false;
for (IProject project : projectList) {
Matcher projectMatcher = projectPattern.matcher(project.getName());
if (projectMatcher.matches()) {
projectMatched = true;
// Find the configurations that match the regular expression
ICProjectDescription desc = CoreModel.getDefault().getProjectDescription(project, false);
if (desc == null) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_project + project.getName()
+ HeadlessBuildMessages.HeadlessBuilder_Not_CDT_Proj);
continue;
}
ICConfigurationDescription[] cfgs = desc.getConfigurations();
for (ICConfigurationDescription cfg : cfgs) {
Matcher cfgMatcher = configPattern.matcher(cfg.getName());
if (cfgMatcher.matches()) {
configMatched = true;
// Build this configuration for this project
Set<ICConfigurationDescription> set = cfgMap.get(project);
if (set == null)
set = new HashSet<>();
set.add(cfg);
cfgMap.put(project, set);
}
}
}
}
if (!projectMatched)
System.err.println(HeadlessBuildMessages.HeadlessBuilder_NoProjectMatched + regularExpression
+ HeadlessBuildMessages.HeadlessBuilder_Skipping2);
else if (!configMatched)
System.err.println(HeadlessBuildMessages.HeadlessBuilder_NoConfigMatched + regularExpression
+ HeadlessBuildMessages.HeadlessBuilder_Skipping2);
} catch (PatternSyntaxException e) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_RegExSyntaxError + e.toString());
System.err.println(HeadlessBuildMessages.HeadlessBuilder_Skipping + regularExpression
+ HeadlessBuildMessages.HeadlessBuilder_Quote);
}
return cfgMap;
}
/*
* Build the given configurations using the specified build type (FULL, CLEAN, INCREMENTAL)
*/
protected void buildConfigurations(Map<IProject, Set<ICConfigurationDescription>> projConfigs,
final IProgressMonitor monitor, final int buildType) throws CoreException {
for (Map.Entry<IProject, Set<ICConfigurationDescription>> entry : projConfigs.entrySet()) {
Set<ICConfigurationDescription> cfgDescs = entry.getValue();
IConfiguration[] configs = new IConfiguration[cfgDescs.size()];
int i = 0;
for (ICConfigurationDescription cfgDesc : cfgDescs)
configs[i++] = ManagedBuildManager.getConfigurationForDescription(cfgDesc);
ManagedBuildManager.buildConfigurations(configs, null, new SubProgressMonitor(monitor, 1), true, buildType);
}
}
/**
* Import a project into the workspace
* @param projURIStr base URI string
* @param recurse should we recurse down the URI importing all projects?
* @return int OK / ERROR
*/
protected int importProject(String projURIStr, boolean recurse) throws CoreException {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProgressMonitor monitor = new PrintingProgressMonitor();
InputStream in = null;
try {
URI project_uri = null;
try {
project_uri = URI.create(projURIStr);
} catch (Exception e) {
// Will be treated as straightforward path in the case below
}
// Handle local paths as well
if (project_uri == null || project_uri.getScheme() == null) {
IPath p = new Path(projURIStr).addTrailingSeparator();
project_uri = URIUtil.toURI(p);
// Handle relative paths as relative to cwd
if (project_uri.getScheme() == null) {
String cwd = System.getProperty("user.dir"); //$NON-NLS-1$
p = new Path(cwd).addTrailingSeparator();
p = p.append(projURIStr);
project_uri = URIUtil.toURI(p);
}
if (project_uri.getScheme() == null) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_invalid_uri + project_uri);
return ERROR;
}
}
if (recurse) {
if (!EFS.getStore(project_uri).fetchInfo().exists()) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_Directory + project_uri
+ HeadlessBuildMessages.HeadlessBuilder_cant_be_found);
return ERROR;
}
for (IFileStore info : EFS.getStore(project_uri).childStores(EFS.NONE, monitor)) {
if (!info.fetchInfo().isDirectory())
continue;
int status = importProject(info.toURI().toString(), recurse);
if (status != OK)
return status;
}
}
// Load the project description
IFileStore fstore = EFS.getStore(project_uri).getChild(".project"); //$NON-NLS-1$
if (!fstore.fetchInfo().exists()) {
if (!recurse) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_project + project_uri
+ HeadlessBuildMessages.HeadlessBuilder_cant_be_found);
return ERROR;
}
// .project not found; OK if we're not recursing
return OK;
}
in = fstore.openInputStream(EFS.NONE, monitor);
IProjectDescription desc = root.getWorkspace().loadProjectDescription(in);
// Check that a project with the same name doesn't already exist in the workspace
IProject project = root.getProject(desc.getName());
if (project.exists()) {
// It's ok if the project we're importing is the same as one already in the workspace
if (URIUtil.equals(project.getLocationURI(), project_uri)) {
project.open(monitor);
return OK;
}
System.err.println(HeadlessBuildMessages.HeadlessBuilder_project + desc.getName()
+ HeadlessBuildMessages.HeadlessBuilder_already_exists_in_workspace);
return ERROR;
}
// Create and open the project
// Note that if the project exists directly under the workspace root, we can't #setLocationURI(...)
if (!URIUtil.equals(
org.eclipse.core.runtime.URIUtil.append(ResourcesPlugin.getWorkspace().getRoot().getLocationURI(),
org.eclipse.core.runtime.URIUtil.lastSegment(project_uri)),
project_uri))
desc.setLocationURI(project_uri);
else
project_uri = null;
// Check the URI is valid for a project in this workspace
if (!root.getWorkspace().validateProjectLocationURI(project, project_uri).equals(Status.OK_STATUS)) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_URI + project_uri
+ HeadlessBuildMessages.HeadlessBuilder_is_not_valid_in_workspace);
return ERROR;
}
project.create(desc, monitor);
project.open(monitor);
} finally {
try {
if (in != null)
in.close();
} catch (IOException e2) {
/* don't care */ }
}
return OK;
}
protected boolean isProjectSuccesfullyBuild(IProject project) {
try {
for (String markerType : markerTypes) {
int findMaxProblemSeverity = project.findMaxProblemSeverity(markerType, true, IResource.DEPTH_INFINITE);
if (findMaxProblemSeverity >= IMarker.SEVERITY_ERROR) {
return false;
}
}
} catch (CoreException e) {
ManagedBuilderCorePlugin.log(e);
return false;
}
return true;
}
protected void accumulateErrorMarkers(IProject project, List<String> allBuildErrors) {
try {
for (String markerType : markerTypes) {
IMarker[] findMarkers = project.findMarkers(markerType, true, IResource.DEPTH_INFINITE);
for (IMarker marker : findMarkers) {
int severity = marker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
if (severity >= IMarker.SEVERITY_ERROR) {
// the string format of Markers is not API and recommended only for debugging, but
// it suits our purpose here.
allBuildErrors.add(marker.toString());
}
}
}
} catch (CoreException e) {
ManagedBuilderCorePlugin.log(e);
}
}
@Override
public Object start(IApplicationContext context) throws Exception {
// Build result: whether projects were built successfully
boolean buildSuccessful = true;
List<String> allBuildErrors = new ArrayList<>();
// Check its OK to use this workspace as IDEApplication does
if (!checkInstanceLocation())
return ERROR;
IProgressMonitor monitor = new PrintingProgressMonitor();
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
final boolean isAutoBuilding = root.getWorkspace().isAutoBuilding();
try {
{
// Turn off workspace auto-build
IWorkspaceDescription desc = root.getWorkspace().getDescription();
desc.setAutoBuilding(false);
root.getWorkspace().setDescription(desc);
}
if (!root.isAccessible()) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_Workspace + root.getLocationURI().toString()
+ HeadlessBuildMessages.HeadlessBuilder_is_not_accessible);
return ERROR;
}
// Handle user provided arguments
if (!getArguments((String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS)))
return SHOW_USAGE;
if (markerTypesDefault || markerTypesAll) {
markerTypes.clear();
markerTypes.add(IMarker.PROBLEM);
}
if (disableIndexer) {
CCorePlugin.getIndexManager().setDefaultIndexerId(IPDOMManager.ID_NO_INDEXER);
// yes, this is ugly - but I haven't found a way to "officially"
// stop the indexer.
// The problem is that the "workspace job" for the
// "index manager" (PDOMIndexerJob) is created and scheduled
// during plugin activation (CCorePlugin.start(BundleContext))
// and therefore, it may already be running when we first reach
// this line of code. Therefore, we do not just (temporarily)
// disable the indexer but also stop it.
if (CCorePlugin.getIndexManager() instanceof PDOMManager) {
PDOMManager man = (PDOMManager) CCorePlugin.getIndexManager();
man.shutdown();
}
}
// Set the console environment so build output is echo'd to stdout
if (System.getProperty("org.eclipse.cdt.core.console") == null) //$NON-NLS-1$
System.setProperty("org.eclipse.cdt.core.console", "org.eclipse.cdt.core.systemConsole"); //$NON-NLS-1$ //$NON-NLS-2$
/*
* Perform the project import
*/
// Import any projects that need importing
for (String projURIStr : projectsToImport) {
int status = importProject(projURIStr, false);
if (status != OK)
return status;
}
for (String projURIStr : projectTreeToImport) {
int status = importProject(projURIStr, true);
if (status != OK)
return status;
}
// Hook in our external settings to the build
HeadlessBuilderExternalSettingsProvider.hookExternalSettingsProvider();
IProject[] allProjects = root.getProjects();
// Map from Project -> Configurations to build. We also Build all projects which are clean'd
Map<IProject, Set<ICConfigurationDescription>> configsToBuild = new HashMap<>();
/*
* Perform the Clean / Build
*/
final boolean buildAllConfigs = ACBuilder.needAllConfigBuild();
try {
// Set the tool options for all project configurations
// (This can't be done just for the projects being built, as they
// may cause other projects to be built via references)
if (!toolOptions.isEmpty())
for (IProject project : allProjects) {
IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(project);
if (info == null)
continue;
IManagedProject mProj = info.getManagedProject();
IConfiguration[] cfgs = mProj.getConfigurations();
for (IConfiguration cfg : cfgs)
setToolOptions(cfg);
ManagedBuildManager.saveBuildInfo(project, true);
}
// Clean the projects
if (cleanAll) {
// Ensure we clean all the configurations
ACBuilder.setAllConfigBuild(true);
System.out.println(HeadlessBuildMessages.HeadlessBuilder_cleaning_all_projects);
root.getWorkspace().build(IncrementalProjectBuilder.CLEAN_BUILD, monitor);
// Reset the build_all_configs preference value to its previous state
ACBuilder.setAllConfigBuild(buildAllConfigs);
} else {
// Resolve the regular expression project names to build configurations
for (String regEx : projectRegExToClean)
matchConfigurations(regEx, allProjects, configsToBuild);
// Clean the list of configurations
buildConfigurations(configsToBuild, monitor, IncrementalProjectBuilder.CLEAN_BUILD);
}
// Build the projects the user wants building
if (buildAll) {
// Ensure we build all the configurations
ACBuilder.setAllConfigBuild(true);
System.out.println(HeadlessBuildMessages.HeadlessBuilder_building_all);
root.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, monitor);
for (IProject p : root.getProjects()) {
buildSuccessful = buildSuccessful && isProjectSuccesfullyBuild(p);
if (printErrorMarkers) {
accumulateErrorMarkers(p, allBuildErrors);
}
}
} else {
// Resolve the regular expression project names to build configurations
for (String regEx : projectRegExToBuild)
matchConfigurations(regEx, allProjects, configsToBuild);
// Build the list of configurations
buildConfigurations(configsToBuild, monitor, IncrementalProjectBuilder.FULL_BUILD);
for (IProject p : configsToBuild.keySet()) {
buildSuccessful = buildSuccessful && isProjectSuccesfullyBuild(p);
if (printErrorMarkers) {
accumulateErrorMarkers(p, allBuildErrors);
}
}
}
} finally {
// Reset the tool options
if (!savedToolOptions.isEmpty())
for (IProject project : allProjects) {
IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(project);
if (info == null)
continue;
IManagedProject mProj = info.getManagedProject();
IConfiguration[] cfgs = mProj.getConfigurations();
for (IConfiguration cfg : cfgs)
resetToolOptions(cfg);
ManagedBuildManager.saveBuildInfo(project, true);
}
// Reset the build_all_configs preference value to its previous state
ACBuilder.setAllConfigBuild(buildAllConfigs);
// Unhook the external settings provider
HeadlessBuilderExternalSettingsProvider.unhookExternalSettingsProvider();
}
} finally {
// Wait for any outstanding jobs to finish
while (!Job.getJobManager().isIdle())
Thread.sleep(10);
// Reset workspace auto-build preference
IWorkspaceDescription desc = root.getWorkspace().getDescription();
desc.setAutoBuilding(isAutoBuilding);
root.getWorkspace().setDescription(desc);
// Save modified workspace (bug 513763)
root.getWorkspace().save(true, monitor);
}
if (printErrorMarkers) {
if (buildSuccessful) {
System.out.println(HeadlessBuildMessages.HeadlessBuilder_completed_successfully);
} else {
System.out.println(HeadlessBuildMessages.HeadlessBuilder_encountered_errors);
for (String buildError : allBuildErrors) {
System.err.println(buildError);
}
}
}
return buildSuccessful ? OK : ERROR;
}
/**
* Verify that it's safe to use the specified workspace. i.e. that we can write to it and that it's not
* already locked / in-use.
*
* Return true if a valid workspace path has been set and false otherwise.
*
* @return true if a valid instance location has been set and false otherwise
*/
protected boolean checkInstanceLocation() {
// -data @none was specified but an ide requires workspace
Location instanceLoc = Platform.getInstanceLocation();
if (instanceLoc == null || !instanceLoc.isSet()) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_MustSpecifyWorkspace);
return false;
}
// -data "/valid/path", workspace already set
try {
// at this point its valid, so try to lock it to prevent concurrent use
if (!instanceLoc.lock()) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_WorkspaceInUse);
return false;
}
return true;
} catch (IOException e) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_CouldntLockWorkspace);
}
return false;
}
/**
* Helper method to process expected arguments
*
* Arguments
* -import {[uri:/]/path/to/project}
* -importAll {[uri:/]/path/to/projectTreeURI} Import all projects in the tree
* -build {project_name_reg_ex/config_name_reg_ex | all}
* -cleanBuild {project_name_reg_ex/config_name_reg_ex | all}
* -I {include_path} additional include_path to add to tools
* -include {include_file} additional include_file to pass to tools
* -D {prepoc_define} addition preprocessor defines to pass to the tools
* -E {var=value} replace/add value to environment variable when running all tools
* -Ea {var=value} append value to environment variable when running all tools
* -Ep {var=value} prepend value to environment variable when running all tools
* -Er {var} remove/unset the given environment variable
* -T {toolid} {optionid=value} replace a tool option value
* -Ta {toolid} {optionid=value} append to a tool option value
* -Tp {toolid} {optionid=value} prepend to a tool option value
* -Tr {toolid} {optionid=value} remove a tool option value
* -no-indexer Disable indexer
* -markerType Which markers to consider
* -printErrorMarkers Print all error markers that caused build to fail
*
* Each argument may be specified more than once
* @param args String[] of arguments to parse
* @return boolean indicating success
*/
public boolean getArguments(String[] args) {
try {
if (args == null || args.length == 0)
throw new Exception(HeadlessBuildMessages.HeadlessBuilder_no_arguments);
for (int i = 0; i < args.length; i++) {
if ("-help".equals(args[i])) { //$NON-NLS-1$
throw new Exception(HeadlessBuildMessages.HeadlessBuilder_help_requested);
} else if ("-import".equals(args[i])) { //$NON-NLS-1$
projectsToImport.add(args[++i]);
} else if ("-importAll".equals(args[i])) { //$NON-NLS-1$
projectTreeToImport.add(args[++i]);
} else if ("-build".equals(args[i])) { //$NON-NLS-1$
projectRegExToBuild.add(args[++i]);
} else if ("-cleanBuild".equals(args[i])) { //$NON-NLS-1$
projectRegExToClean.add(args[++i]);
} else if ("-D".equals(args[i])) { //$NON-NLS-1$
String macro = args[++i];
String macroVal = ""; //$NON-NLS-1$
if (macro.indexOf('=') != -1) {
macroVal = macro.substring(macro.indexOf('=') + 1);
macro = macro.substring(0, macro.indexOf('='));
}
HeadlessBuilderExternalSettingsProvider.additionalSettings
.add(CDataUtil.createCMacroEntry(macro, macroVal, 0));
} else if ("-I".equals(args[i])) { //$NON-NLS-1$
HeadlessBuilderExternalSettingsProvider.additionalSettings
.add(CDataUtil.createCIncludePathEntry(args[++i], 0));
} else if ("-include".equals(args[i])) { //$NON-NLS-1$
HeadlessBuilderExternalSettingsProvider.additionalSettings
.add(CDataUtil.createCIncludeFileEntry(args[++i], 0));
} else if ("-E".equals(args[i])) { //$NON-NLS-1$
addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_REPLACE);
} else if ("-Ea".equals(args[i])) { //$NON-NLS-1$
addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_APPEND);
} else if ("-Ep".equals(args[i])) { //$NON-NLS-1$
addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_PREPEND);
} else if ("-Er".equals(args[i])) { //$NON-NLS-1$
addEnvironmentVariable(args[++i], IEnvironmentVariable.ENVVAR_REMOVE);
} else if ("-T".equals(args[i])) { //$NON-NLS-1$
String toolId = args[++i];
String option = args[++i];
addToolOption(toolId, option, ToolOption.REPLACE);
} else if ("-Ta".equals(args[i])) { //$NON-NLS-1$
String toolId = args[++i];
String option = args[++i];
addToolOption(toolId, option, ToolOption.APPEND);
} else if ("-Tp".equals(args[i])) { //$NON-NLS-1$
String toolId = args[++i];
String option = args[++i];
addToolOption(toolId, option, ToolOption.PREPEND);
} else if ("-Tr".equals(args[i])) { //$NON-NLS-1$
String toolId = args[++i];
String option = args[++i];
addToolOption(toolId, option, ToolOption.REMOVE);
} else if ("-no-indexer".equals(args[i])) { //$NON-NLS-1$
disableIndexer = true;
} else if ("-markerType".equals(args[i])) { //$NON-NLS-1$
addMarkerType(args[++i]);
} else if ("-printErrorMarkers".equals(args[i])) { //$NON-NLS-1$
printErrorMarkers = true;
} else {
throw new Exception(HeadlessBuildMessages.HeadlessBuilder_unknown_argument + args[i]);
}
}
} catch (Exception e) {
System.err.println(HeadlessBuildMessages.HeadlessBuilder_invalid_argument + Arrays.toString(args));
System.err.println(HeadlessBuildMessages.HeadlessBuilder_Error + e.getMessage());
return false;
}
if (projectRegExToClean.contains("all") || projectRegExToClean.contains("*")) { //$NON-NLS-1$ //$NON-NLS-2$
cleanAll = true;
buildAll = true;
projectRegExToClean.remove("all"); //$NON-NLS-1$
projectRegExToClean.remove("*"); //$NON-NLS-1$
}
if (projectRegExToBuild.contains("all") || projectRegExToBuild.contains("*")) { //$NON-NLS-1$ //$NON-NLS-2$
buildAll = true;
projectRegExToBuild.remove("all"); //$NON-NLS-1$
projectRegExToBuild.remove("*"); //$NON-NLS-1$
}
return true;
}
protected void addEnvironmentVariable(String string, int op) throws Exception {
String[] parts = string.split("=", 2); //$NON-NLS-1$
String name = parts[0];
String value = ""; //$NON-NLS-1$
if (parts.length > 1)
value = parts[1];
EnvironmentVariableManager.fUserSupplier.createOverrideVariable(name, value, op, null);
}
protected void addToolOption(String toolId, String option, int operation) {
String optionId = option;
String value = ""; //$NON-NLS-1$
if (option.indexOf('=') != -1) {
value = option.substring(option.indexOf('=') + 1);
optionId = option.substring(0, option.indexOf('='));
}
toolOptions.add(new ToolOption(toolId, optionId, value, operation));
}
protected void addMarkerType(String markerType) {
markerTypesDefault = false;
if ("all".equals(markerType)) { //$NON-NLS-1$
markerTypesAll = true;
} else if ("cdt".equals(markerType)) { //$NON-NLS-1$
markerTypes.add(ICModelMarker.C_MODEL_PROBLEM_MARKER);
} else {
markerTypes.add(markerType);
}
}
/**
* Set the tool options in a configuration, and saves the current values so that
* they can be restored at the end of the build. These are reset after the build
* by calls to {@link #resetToolOptions(IConfiguration)}.
*/
@SuppressWarnings("unchecked")
protected void setToolOptions(IConfiguration configuration) throws BuildException {
if (!savedToolOptions.containsKey(configuration.getId()))
savedToolOptions.put(configuration.getId(), new HashSet<SavedToolOption>());
Set<SavedToolOption> savedToolOptionsSet = savedToolOptions.get(configuration.getId());
for (ToolOption toolOption : toolOptions) {
ITool[] tools = configuration.getToolsBySuperClassId(toolOption.toolId);
for (ITool tool : tools) {
IOption option = tool.getOptionBySuperClassId(toolOption.optionId);
if (option != null) {
// Save the tool option so that it can be reset later (does not overwrite existing
// saved options, so if an option is specified multiple times it will be reset to the
// correct value)
savedToolOptionsSet.add(new SavedToolOption(tool.getId(), option.getId(), option.getValue()));
// Update the value of the tool option in a type-dependent manner
switch (option.getValueType()) {
case IOption.BOOLEAN:
boolean booleanValue = (Boolean) option.getDefaultValue();
if (toolOption.operation != ToolOption.REMOVE)
booleanValue = Boolean.parseBoolean(toolOption.value);
ManagedBuildManager.setOption(configuration, tool, option, booleanValue);
break;
case IOption.STRING_LIST:
case IOption.INCLUDE_PATH:
case IOption.PREPROCESSOR_SYMBOLS:
case IOption.LIBRARIES:
case IOption.OBJECTS:
case IOption.INCLUDE_FILES:
case IOption.LIBRARY_PATHS:
case IOption.LIBRARY_FILES:
case IOption.MACRO_FILES:
case IOption.UNDEF_INCLUDE_PATH:
case IOption.UNDEF_PREPROCESSOR_SYMBOLS:
case IOption.UNDEF_INCLUDE_FILES:
case IOption.UNDEF_LIBRARY_PATHS:
case IOption.UNDEF_LIBRARY_FILES:
case IOption.UNDEF_MACRO_FILES:
List<String> listValue = new ArrayList<>();
switch (toolOption.operation) {
case ToolOption.APPEND:
listValue.addAll((List<String>) option.getValue());
listValue.addAll(Arrays.asList(toolOption.value.split(","))); //$NON-NLS-1$
break;
case ToolOption.PREPEND:
listValue.addAll(Arrays.asList(toolOption.value.split(","))); //$NON-NLS-1$
listValue.addAll((List<String>) option.getValue());
break;
case ToolOption.REMOVE:
listValue = (List<String>) option.getDefaultValue();
break;
default:
listValue = Arrays.asList(toolOption.value.split(",")); //$NON-NLS-1$
break;
}
ManagedBuildManager.setOption(configuration, tool, option,
listValue == null ? new String[0] : listValue.toArray(new String[listValue.size()]));
break;
default: // IOption.ENUMERATED, IOption.STRING
String stringValue = toolOption.value;
switch (toolOption.operation) {
case ToolOption.APPEND:
stringValue = option.getValue() + stringValue;
break;
case ToolOption.PREPEND:
stringValue = stringValue + option.getValue();
break;
case ToolOption.REMOVE:
stringValue = (String) option.getDefaultValue();
break;
}
ManagedBuildManager.setOption(configuration, tool, option, stringValue);
break;
}
}
}
}
}
/**
* Reset the tool options that were set using {@link #setToolOptions(IConfiguration)}
*/
protected void resetToolOptions(IConfiguration configuration) throws BuildException {
for (SavedToolOption toolOption : savedToolOptions.get(configuration.getId())) {
IOption option = configuration.getTool(toolOption.toolId).getOptionById(toolOption.optionId);
option.setValue(toolOption.value);
}
}
@Override
public void stop() {
}
}