builder/com.nokia.carbide.cdt.builder/src/com/nokia/carbide/cdt/builder/builder/CarbideCPPBuilder.java
/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.carbide.cdt.builder.builder;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.resources.IConsole;
import org.eclipse.cdt.utils.spawner.EnvironmentReader;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
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.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Display;
import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
import com.nokia.carbide.cdt.builder.DefaultMMPViewConfiguration;
import com.nokia.carbide.cdt.builder.DefaultViewConfiguration;
import com.nokia.carbide.cdt.builder.EpocEngineHelper;
import com.nokia.carbide.cdt.builder.EpocEnginePathHelper;
import com.nokia.carbide.cdt.builder.PKGViewPathHelper;
import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
import com.nokia.carbide.cdt.builder.project.IROMBuilderInfo;
import com.nokia.carbide.cdt.builder.project.ISISBuilderInfo;
import com.nokia.carbide.cdt.internal.api.builder.SISBuilderInfo2;
import com.nokia.carbide.cdt.internal.builder.CarbideSBSv1Builder;
import com.nokia.carbide.cdt.internal.builder.CarbideSBSv2Builder;
import com.nokia.carbide.cdt.internal.builder.ICarbideBuilder;
import com.nokia.carbide.cdt.internal.builder.ui.BuilderPreferencePage;
import com.nokia.carbide.cdt.internal.builder.ui.MMPSelectionDialog;
import com.nokia.carbide.cdt.internal.builder.ui.Messages;
import com.nokia.carbide.cpp.epoc.engine.EpocEnginePlugin;
import com.nokia.carbide.cpp.epoc.engine.MMPDataRunnableAdapter;
import com.nokia.carbide.cpp.epoc.engine.PKGViewRunnableAdapter;
import com.nokia.carbide.cpp.epoc.engine.model.bldinf.IExtension;
import com.nokia.carbide.cpp.epoc.engine.model.mmp.EMMPLanguage;
import com.nokia.carbide.cpp.epoc.engine.model.mmp.EMMPStatement;
import com.nokia.carbide.cpp.epoc.engine.model.mmp.IMMPData;
import com.nokia.carbide.cpp.epoc.engine.model.mmp.IMMPResource;
import com.nokia.carbide.cpp.epoc.engine.preprocessor.AcceptedNodesViewFilter;
import com.nokia.carbide.cpp.internal.qt.core.QtCorePlugin;
import com.nokia.carbide.cpp.internal.x86build.X86BuildPlugin;
import com.nokia.carbide.cpp.sdk.core.ISymbianBuildContext;
import com.nokia.carbide.internal.api.cpp.epoc.engine.model.pkg.EPKGLanguage;
import com.nokia.carbide.internal.api.cpp.epoc.engine.model.pkg.IPKGEmbeddedSISFile;
import com.nokia.carbide.internal.api.cpp.epoc.engine.model.pkg.IPKGHeader;
import com.nokia.carbide.internal.api.cpp.epoc.engine.model.pkg.IPKGInstallFile;
import com.nokia.carbide.internal.api.cpp.epoc.engine.model.pkg.IPKGView;
import com.nokia.carbide.internal.api.cpp.epoc.engine.model.pkg.PKGModelHelper;
import com.nokia.cpp.internal.api.utils.core.FileUtils;
import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
/**
* Main interface for invoking different build stages.
*
*/
public class CarbideCPPBuilder extends IncrementalProjectBuilder {
//TODO do we need to pipe output of compiles to files so we get then errors/warnings in order?
public static final String BUILDER_ID = "com.nokia.carbide.cdt.builder.carbideCPPBuilder"; //$NON-NLS-1$
public static final int BUILD_COMPONENT_ACTION = 0;
public static final int CLEAN_COMPONENT_ACTION = 1;
public static final int FREEZE_COMPONENT_ACTION = 2;
public static final String RESOLVED_PKG_PREFIX = "_resolved"; //$NON-NLS-1$
private static final boolean SHOW_ENV_VARS = true;
private static final String PKG_SYMBOL_EPOCROOT = "$(EPOCROOT)"; //$NON-NLS-1$
private static final String PKG_SYMBOL_PLATFORM = "$(PLATFORM)"; //$NON-NLS-1$
private static final String PKG_SYMBOL_TARGET = "$(TARGET)"; //$NON-NLS-1$
private static final String DEFAULT_KEY_NAME = "key-gen.key"; //$NON-NLS-1$
private static final String DEFAULT_CERT_NAME = "cert-gen.cer"; //$NON-NLS-1$
private static final String DEAULT_PASSWORD = "DefaultPassword"; //$NON-NLS-1$
private static final String MAKEKEYS_EXE = "makekeys.exe"; //$NON-NLS-1$
private static final String MAKESIS_EXE = "makesis.exe"; //$NON-NLS-1$
private static final String SIGNSIS_EXE = "signsis.exe"; //$NON-NLS-1$
private static List<IPath> normalMakMakePaths = Collections.synchronizedList(new ArrayList<IPath>());
private static List<IPath> testMakMakePaths = Collections.synchronizedList(new ArrayList<IPath>());
private static ICarbideBuilder v1Builder = new CarbideSBSv1Builder();
private static ICarbideBuilder v2Builder = new CarbideSBSv2Builder();
private static ICarbideBuilder getBuilder(IProject project) {
if (CarbideBuilderPlugin.getBuildManager().isCarbideSBSv2Project(project)) {
return v2Builder;
} else {
return v1Builder;
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.internal.events.InternalBuilder#build(int,
* java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
*/
@SuppressWarnings("unchecked")
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
IProject currentProject = getProject();
ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(currentProject);
if (cpi != null) {
if (cpi.incrementalBuilderEnabled()) {
// the callOnEmptyDelta builder attribute is set, so we get called
// not matter what, even with an empty delta. this means that when the
// incremental build option is disabled, we still get called. when it's
// enabled, we just check the delta. if null, we need to build. otherwise
// see what's changed and decide from that.
IResourceDelta delta = getDelta(currentProject);
if (delta != null) {
// something in the workspace has changed. see if a rebuild is needed.
if (!shouldRebuild(delta)) {
// also rebuild if the project has errors
boolean hasErrors = false;
try {
for (IMarker currMarker : getProject().findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE)){
if (currMarker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR) == IMarker.SEVERITY_ERROR){
hasErrors = true;
break;
}
}
} catch (CoreException e){
e.printStackTrace();
}
if (!hasErrors) {
return null;
}
}
}
}
ICarbideBuildConfiguration defaultConfig = cpi.getDefaultConfiguration();
if (defaultConfig != null) {
CarbideCommandLauncher launcher = new CarbideCommandLauncher(currentProject, monitor, getParserIdArray(defaultConfig.getErrorParserId()), cpi.getINFWorkingDirectory());
launcher.showCommand(true);
invokeBuild(defaultConfig, launcher, subMonitor.newChild(1), true);
} else {
CarbideBuilderPlugin.createCarbideProjectMarker(currentProject, IMarker.SEVERITY_ERROR, "Project has no configurations.", IMarker.PRIORITY_HIGH);
}
}
monitor.done();
return null;
}
protected boolean shouldRebuild(IResourceDelta delta) {
// check for any changed files. note that even if files are removed or added, they won't
// affect the build unless the bld.inf or mmp files change. those files will be picked up
// by this check, so no need to worry about checking for added and removed resources.
// I thought about maybe checking by file extension, but there's really no way for us to know the
// comprehensive list. note that they could change the input to a hlp file, any random
// header file with any extension, even .txt files that are included in a pkg file. so
// at least for now we'll leave it as rebuilding when any file in the workspace changes.
for (IResourceDelta child : delta.getAffectedChildren(IResourceDelta.CHANGED)) {
IResource resource = child.getResource();
if (resource != null) {
if (resource.getType() == IResource.FILE) {
// ignore changes to the .cproject and .project files
if (!resource.getName().equals(".project") && !resource.getName().equals(".cproject")) {
return true;
}
}
}
if (shouldRebuild(child)) {
return true;
}
}
return false;
}
protected void clean(IProgressMonitor monitor) throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
IProject currentProject = getProject();
ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(currentProject);
if (cpi != null) {
ICarbideBuildConfiguration defaultConfig = cpi.getDefaultConfiguration();
if (defaultConfig != null) {
invokeClean(defaultConfig, subMonitor.newChild(1), true);
} else {
CarbideBuilderPlugin.createCarbideProjectMarker(currentProject, IMarker.SEVERITY_ERROR, "Project has no configurations.", IMarker.PRIORITY_HIGH);
}
}
monitor.done();
}
/**
* Invokes a build for the given build configuration. Output is piped to the given console and progress is reported
* using the given monitor. Make files are created/updated if necessary.
* @param buildConfig the build configuration to build
* @param launcher the Carbide launcher
* @param monitor the progress monitor to use to report progress
* @param clearMarkers true if project markers should be cleared before action is taken
*/
public static void invokeBuild(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, IProgressMonitor monitor, boolean clearMarkers) {
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
if (clearMarkers) {
try {
removeAllMarkers(cpi.getProject());
} catch (CoreException e) {
e.printStackTrace();
}
}
calculateComponentLists(buildConfig, launcher);
launcher.startTimingStats();
launcher.writeToConsole("\n***Building project \"" + cpi.getProject().getName() + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n");
getBuilder(cpi.getProject()).preBuildStep(buildConfig, launcher);
runPreBuildChecks(buildConfig, launcher);
if (SHOW_ENV_VARS){
launcher.writeToConsole("\n***Printing environment variables modified from default:\n");
String[] modEnvVars = getModifiedEnvVars(buildConfig);
for (String envVar : modEnvVars){
launcher.writeToConsole(envVar + "\n");
}
launcher.writeToConsole("\n");
launcher.writeToConsole("Working Directory: " + cpi.getINFWorkingDirectory() + "\n\n");
}
boolean success = true;
if (cpi.isBuildingFromInf()) {
success = buildAllComponents(buildConfig, launcher, monitor);
} else {
success = buildComponentSubset(buildConfig, launcher, monitor);
}
// error codes are not always returned from abld.pl and the like.
// check for error markers on the project as well in case the error
// parsers picked anything up.
if (success && !projectHasBuildErrors(cpi.getProject())) {
launcher.writeToConsole("\n***Build Complete\n");
// build any sis files
SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
invokeSISBuilder(buildConfig, launcher, subMonitor.newChild(1));
// build ROM if necessary
subMonitor = SubMonitor.convert(monitor, 1);
invokeROMBuilder(buildConfig, launcher, subMonitor.newChild(1));
} else {
launcher.writeToConsole("\n***Errors were detected in build. See the Problems or Console view for details.\n");
}
launcher.writeToConsole(launcher.getTimingStats());
// only refresh if the auto refresh workspace pref is turned off
if (!ResourcesPlugin.getPlugin().getPluginPreferences().getBoolean(ResourcesPlugin.PREF_AUTO_REFRESH)) {
// refresh the file system to pick up any newly created files under the project
try {
cpi.getProject().refreshLocal(IResource.DEPTH_INFINITE, monitor);
} catch (CoreException e) {
// no file system refresh
e.printStackTrace();
}
}
}
/**
* Invokes a clean for the given build configuration. Output is piped to the given console and progress is reported
* using the given monitor. Make files are created/updated if necessary.
* @param buildConfig the build configuration to clean
* @param monitor the progress monitor to use to report progress
* @param clearMarkers true if project markers should be cleared before action is taken
*/
public static void invokeClean(ICarbideBuildConfiguration buildConfig, IProgressMonitor monitor, boolean clearMarkers) {
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
IProject project = cpi.getProject();
if (clearMarkers) {
try {
removeAllMarkers(project);
} catch (CoreException e) {
e.printStackTrace();
}
}
getBuilder(cpi.getProject()).preCleanStep(buildConfig);
CarbideCommandLauncher launcher = new CarbideCommandLauncher(project, monitor, getParserIdArray(buildConfig.getErrorParserId()), cpi.getINFWorkingDirectory());
launcher.showCommand(true);
calculateComponentLists(buildConfig, launcher);
launcher.startTimingStats();
launcher.writeToConsole("\n***Cleaning project \"" + project.getName() + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n");
if (cpi.isBuildingFromInf()) {
cleanAllComponents(buildConfig, launcher, monitor);
} else {
cleanComponentSubset(buildConfig, launcher, monitor);
}
launcher.writeToConsole("\n***Clean Complete\n");
launcher.writeToConsole(launcher.getTimingStats());
// only refresh if the auto refresh workspace pref is turned off
if (!ResourcesPlugin.getPlugin().getPluginPreferences().getBoolean(ResourcesPlugin.PREF_AUTO_REFRESH)) {
// refresh the file system to pick up any newly created files under the project
try {
cpi.getProject().refreshLocal(IResource.DEPTH_INFINITE, monitor);
} catch (CoreException e) {
// no file system refresh
e.printStackTrace();
}
}
}
/**
* Invokes a freeze for the given build configuration. Output is piped to the given console and progress is reported
* using the given monitor. Make files are created/updated if necessary.
* @param buildConfig the build configuration to freeze
* @param monitor the progress monitor to use to report progress
* @param clearMarkers true if project markers should be cleared before action is taken
*/
public static void invokeFreeze(ICarbideBuildConfiguration buildConfig, IProgressMonitor monitor, boolean clearMarkers) {
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
IProject project = cpi.getProject();
CarbideCommandLauncher launcher = new CarbideCommandLauncher(project, monitor, getParserIdArray(buildConfig.getErrorParserId()), cpi.getINFWorkingDirectory());
launcher.showCommand(true);
// make sure the project is built
launcher.writeToConsole("\n***Bringing project up to date before freezing\n");
invokeBuild(buildConfig, launcher, monitor, clearMarkers);
launcher.startTimingStats();
launcher.writeToConsole("\n***Freezing project \"" + project.getName() + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n");
if (cpi.isBuildingFromInf()) {
freezeAllComponents(buildConfig, launcher, monitor);
} else {
freezeComponentSubset(buildConfig, launcher, monitor);
}
launcher.writeToConsole("\n***Freeze Complete\n");
launcher.writeToConsole(launcher.getTimingStats());
}
/**
* Invoke the given action on the given Symbian mmp/make file for the given build configuration.
* @param buildConfig the build configuration to act upon
* @param action the action to perform, see {@link #BUILD_COMPONENT_ACTION}, {@link #CLEAN_COMPONENT_ACTION}, {@link #FREEZE_COMPONENT_ACTION}
* @param componentPath the full path of the mmp or make file
* @param launcher - The object to use for the process execution
* @param monitor the progress monitor to report progress to
* @param clearMarkers true if project markers should be cleared before action is taken
* @return true if successful, false otherwise
* @throws CoreException
*/
public static boolean invokeSymbianComponenetAction(ICarbideBuildConfiguration buildConfig, int action, IPath componentPath, CarbideCommandLauncher launcher, IProgressMonitor monitor, boolean clearMarkers) throws CoreException {
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
List<ISymbianBuildContext> buildConfigList = new ArrayList<ISymbianBuildContext>(1);
buildConfigList.add(buildConfig);
if (clearMarkers) {
try {
removeAllMarkers(cpi.getProject());
} catch (CoreException e) {
e.printStackTrace();
}
}
List<IPath> normalMakMakePaths = new ArrayList<IPath>();
List<IPath> testMakMakePaths = new ArrayList<IPath>();
// get the list of mmp/make files for this build configuration. note that we're not calling calculateComponentLists here
// because then the caller would only be able to build components that are build built by a full build. but that's kind of
// limiting. they may have build test components disabled but just want to verify that one test mmp still builds.
EpocEngineHelper.getMakMakeFiles(cpi.getAbsoluteBldInfPath(), buildConfigList, normalMakMakePaths, testMakMakePaths, new NullProgressMonitor());
boolean found = false;
boolean isTest = false;
// see if we can find the component
for (IPath path : normalMakMakePaths) {
if (path.equals(componentPath)) {
found = true;
break;
}
}
if (!found) {
// try the test components
for (IPath path : testMakMakePaths) {
if (path.equals(componentPath)) {
found = true;
isTest = true;
break;
}
}
}
if (!found) {
throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Component " + componentPath.toOSString() + " not found.", null)); //$NON-NLS-1$ //$NON-NLS-2$
}
launcher.startTimingStats();
String componentName = componentPath.removeFileExtension().lastSegment();
boolean result = false;
if (action == BUILD_COMPONENT_ACTION) {
runPreBuildChecks(buildConfig, launcher);
launcher.writeToConsole("\n***Building component \"" + componentName + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n");
result = getBuilder(cpi.getProject()).buildComponent(buildConfig, componentPath, isTest, launcher, monitor);
} else if (action == CLEAN_COMPONENT_ACTION) {
launcher.writeToConsole("\n***Cleaning component \"" + componentName + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n");
result = getBuilder(cpi.getProject()).cleanComponent(buildConfig, componentPath, isTest, launcher, monitor);
} else if (action == FREEZE_COMPONENT_ACTION) {
SubMonitor progress = SubMonitor.convert(monitor, 3);
progress.setTaskName("Freezing " + componentName);
// make sure the component is built
launcher.writeToConsole("\n***Bringing component up to date before freezing\n");
boolean success = invokeSymbianComponenetAction(buildConfig, BUILD_COMPONENT_ACTION, componentPath, launcher, progress.newChild(1), false);
if (success) {
launcher.writeToConsole("\n***Freezing component \"" + componentName + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n");
result = getBuilder(cpi.getProject()).freezeComponent(buildConfig, componentPath, isTest, launcher, progress);
}
}
return result;
}
/**
* Invokes a compile of the the given file for the given build configuration. Output is piped to the given console and
* progress is reported using the given monitor. Make files are created/updated if necessary.
* @param file the absolute file system path to the file to be compiled (source, resource)
* @param buildConfig the build configuration to build
* @param console the console to pipe build output to
* @param launcher - The object to use for the process execution
* @param monitor the progress monitor to use to report progress
* @param clearMarkers whether or not to clear project markers before compiling
* @throws CoreException
*/
public static void compileFile(IPath file, ICarbideBuildConfiguration buildConfig, IConsole console, CarbideCommandLauncher launcher, IProgressMonitor monitor, boolean clearMarkers) throws CoreException {
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
if (clearMarkers) {
try {
removeAllMarkers(cpi.getProject());
} catch (CoreException e) {
e.printStackTrace();
}
}
final SubMonitor progress = SubMonitor.convert(monitor, 5);
progress.setTaskName("Compiling " + file.lastSegment());
final List<IPath> parentMMPs = EpocEngineHelper.getMMPsForSource(cpi.getProject(), file);
if (parentMMPs.isEmpty()) {
throw new CoreException(new Status(IStatus.ERROR, CarbideBuilderPlugin.PLUGIN_ID, 0, "Unable to find parent MMP for file " + file.toOSString(), null)); //$NON-NLS-1$
}
progress.worked(1);
if (progress.isCanceled()) {
return;
}
final EpocEnginePathHelper helper = new EpocEnginePathHelper(cpi.getProject());
final List<IPath> tempPath = new ArrayList<IPath>();
tempPath.add(helper.convertToFilesystem(parentMMPs.get(0)));
// if there is more than one mmp that uses this file, ask the user which one to use
if (parentMMPs.size() > 1) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
List<String> mmps = new ArrayList<String>();
for (IPath mmp : parentMMPs) {
mmps.add(mmp.lastSegment());
}
MMPSelectionDialog dlg = new MMPSelectionDialog(WorkbenchUtils.getSafeShell(), mmps);
if (Window.OK == dlg.open()) {
tempPath.set(0, helper.convertToFilesystem(parentMMPs.get(dlg.getselectedIndex())));
} else {
progress.setCanceled(true);
}
}
});
}
if (progress.isCanceled()) {
return;
}
IPath fullMMPPath = tempPath.get(0);
launcher.writeToConsole("\n***Compiling file \"" + file.toOSString() + "\" for configuration \"" + buildConfig.getDisplayString() + "\"\n");
runPreBuildChecks(buildConfig, launcher);
getBuilder(cpi.getProject()).compileFile(file, buildConfig, fullMMPPath, launcher, monitor);
launcher.writeToConsole("\n***Compile Complete\n");
launcher.writeToConsole(launcher.getTimingStats());
}
protected static List<IPath> getMakeRulesForResource(final ICarbideBuildConfiguration buildConfig, final IPath workspaceRelativeMMPPath, final IPath projectRelativeResourcePath) {
final List<IPath> rules = new ArrayList<IPath>();
EpocEnginePlugin.runWithMMPData(workspaceRelativeMMPPath,
new DefaultMMPViewConfiguration(buildConfig.getCarbideProject().getProject(), buildConfig, new AcceptedNodesViewFilter()),
new MMPDataRunnableAdapter() {
public Object run(IMMPData mmpData) {
// read the project-wide target path
String targetPath = mmpData.getSingleArgumentSettings().get(EMMPStatement.TARGETPATH);
if (targetPath != null) {
// make sure it doesn't start with a "\" but ends with one
IPath targetP = new Path(targetPath).makeRelative().addTrailingSeparator();
targetPath = targetP.toOSString();
} else {
// for EKA1 just leave empty. for EKA2 use sys\bin\
if (buildConfig.getSDK().getOSVersion().getMajor() > 8) {
targetPath = "sys\\bin\\"; //$NON-NLS-1$
} else {
targetPath = ""; //$NON-NLS-1$
}
}
String dataZDir = buildConfig.getSDK().getReleaseRoot().removeLastSegments(1).toOSString() + "\\Data\\z\\"; //$NON-NLS-1$
IPath rezPath = null;
List<EMMPLanguage> languages = null;
// check the user resources
List<IPath> userResources = mmpData.getUserResources();
for (IPath userRes : userResources) {
if (userRes.equals(projectRelativeResourcePath)) {
if (buildConfig.getSDK().isEKA1()) {
rezPath = new Path(dataZDir + targetPath + userRes.removeFileExtension().lastSegment());
} else {
rezPath = new Path(dataZDir).removeLastSegments(1).append(userRes.removeFileExtension().lastSegment());
}
break;
}
}
if (rezPath == null) {
// check the system resources
List<IPath> systemResources = mmpData.getSystemResources();
for (IPath systemRes : systemResources) {
if (systemRes.equals(projectRelativeResourcePath)) {
// target path for system resources is \z\system\data\
rezPath = new Path(dataZDir + "system\\data\\" + systemRes.removeFileExtension().lastSegment());
break;
}
}
}
if (rezPath == null) {
// check the resource blocks
List<IMMPResource> resourceBlocks = mmpData.getResourceBlocks();
for (IMMPResource resourceBlock : resourceBlocks) {
if (resourceBlock.getSource().equals(projectRelativeResourcePath)) {
IPath resPath = resourceBlock.getTargetPath();
if (resPath == null) {
// if not specified in the resource block then get the global
// target path
String targetP = mmpData.getSingleArgumentSettings().get(EMMPStatement.TARGETPATH);
if (targetP != null) {
resPath = new Path(targetP);
}
}
if (resPath != null) {
resPath = resPath.makeRelative().addTrailingSeparator();
String filename = resourceBlock.getTargetFile();
if (filename == null) {
filename = resourceBlock.getSource().removeFileExtension().lastSegment();
} else {
filename = new Path(filename).removeFileExtension().toOSString();
}
rezPath = new Path(dataZDir + resPath.toOSString() + filename);
languages = resourceBlock.getLanguages();
if (languages.size() == 0)
languages = null;
break;
}
}
}
}
if (rezPath != null) {
if (languages == null) {
languages = mmpData.getLanguages();
if (languages.size() == 0) {
// default is non-localize
languages = Collections.singletonList(EMMPLanguage.SC_NonLocalized);
}
}
for (EMMPLanguage language : languages) {
String extension = "R" + language.getCodeString(); //$NON-NLS-1$
rules.add(rezPath.addFileExtension(extension));
}
}
return null;
}
});
return rules;
}
protected static void runPreBuildChecks(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher) {
if (buildConfig.getPlatformString().equals(ISymbianBuildContext.EMULATOR_PLATFORM) && BuilderPreferencePage.useBuiltInX86Vars()) {
X86BuildPlugin.checkForUpdates();
}
}
protected static void calculateComponentLists(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher) {
// this could potentially take some time, and this information is needed in a
// lot of different places, so just do it once and keep it cached for each user
// invoked builder operation. clear it at the start of each operation.
normalMakMakePaths.clear();
testMakMakePaths.clear();
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
List<ISymbianBuildContext> buildConfigList = new ArrayList<ISymbianBuildContext>(1);
buildConfigList.add(buildConfig);
// get the list of mmp/make files for this build configuration
EpocEngineHelper.getMakMakeFiles(cpi.getAbsoluteBldInfPath(), buildConfigList, normalMakMakePaths, testMakMakePaths, new NullProgressMonitor());
if (CarbideBuilderPlugin.getBuildManager().isCarbideSBSv2Project(cpi.getProject())) {
// add any named extensions
List<IExtension> normalNamedExtensionsList = new ArrayList<IExtension>();
List<IExtension> testNamedExtensionsList = new ArrayList<IExtension>();
EpocEngineHelper.getNamedExtensions(cpi.getAbsoluteBldInfPath(), buildConfigList,
normalNamedExtensionsList, testNamedExtensionsList, new NullProgressMonitor());
for (IExtension extension : normalNamedExtensionsList) {
normalMakMakePaths.add(new Path(extension.getName()));
}
for (IExtension extension : testNamedExtensionsList) {
testMakMakePaths.add(new Path(extension.getName()));
}
}
// if we're not supposed to build test components then clear the list
if (cpi.isBuildingFromInf() && !cpi.isBuildingTestComps()) {
testMakMakePaths.clear();
}
if (!cpi.isBuildingFromInf()) {
// issue a warning that extensions will not be built if they're building a subset of components
boolean buildingSubset = false;
// building a subset so we need to figure out which ones to check
List<String> normalComponentsToBeBuilt = cpi.getNormalInfBuildComponents();
for (Iterator<IPath> iter = normalMakMakePaths.iterator(); iter.hasNext();) {
if (!normalComponentsToBeBuilt.contains(iter.next().lastSegment())) {
iter.remove();
buildingSubset = true;
}
}
List<String> testComponentsToBeBuilt = cpi.getTestInfBuildComponents();
for (Iterator<IPath> iter = testMakMakePaths.iterator(); iter.hasNext();) {
if (!testComponentsToBeBuilt.contains(iter.next().lastSegment())) {
iter.remove();
buildingSubset = true;
}
}
if (buildingSubset && EpocEngineHelper.hasUnnamedExtensions(cpi.getAbsoluteBldInfPath(), buildConfigList, new NullProgressMonitor())) {
String warningText = "WARNING: PRJ_EXTENSIONS and PRJ_TESTEXTENSIONS will be excluded from the build because you've selected to build a subset of the bld.inf, and there is no way to specify unnamed components.";
if (CarbideBuilderPlugin.getBuildManager().isCarbideSBSv2Project(cpi.getProject())) {
warningText = warningText + " If you name the extensions then you can select them to be built from the UI.";
}
launcher.writeToConsole(warningText + "\n");
CarbideBuilderPlugin.createCarbideProjectMarker(cpi.getProject(), IMarker.SEVERITY_WARNING, warningText, IMarker.PRIORITY_LOW);
}
}
}
protected static boolean buildAllComponents(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, IProgressMonitor monitor) {
return getBuilder(buildConfig.getCarbideProject().getProject()).buildAllComponents(buildConfig, normalMakMakePaths, testMakMakePaths, launcher, monitor);
}
protected static boolean buildComponentSubset(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, IProgressMonitor monitor) {
return getBuilder(buildConfig.getCarbideProject().getProject()).buildComponentSubset(buildConfig, normalMakMakePaths, testMakMakePaths, launcher, monitor);
}
protected static void cleanAllComponents(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, IProgressMonitor monitor) {
getBuilder(buildConfig.getCarbideProject().getProject()).cleanAllComponents(buildConfig, normalMakMakePaths, testMakMakePaths, launcher, monitor);
}
protected static void cleanComponentSubset(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, IProgressMonitor monitor) {
getBuilder(buildConfig.getCarbideProject().getProject()).cleanComponentSubset(buildConfig, normalMakMakePaths, testMakMakePaths, launcher, monitor);
}
protected static void freezeAllComponents(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, IProgressMonitor monitor) {
getBuilder(buildConfig.getCarbideProject().getProject()).freezeAllComponents(buildConfig, normalMakMakePaths, testMakMakePaths, launcher, monitor);
}
protected static void freezeComponentSubset(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, IProgressMonitor monitor) {
getBuilder(buildConfig.getCarbideProject().getProject()).freezeComponentSubset(buildConfig, normalMakMakePaths, testMakMakePaths, launcher, monitor);
}
/**
* Call bldmake with the given arguments
* @param buildConfig the build configuration context
* @param launcher the command launcher
* @param bldmakeArgs array of String arguments to be passed to bldmake
* @param removeMarkers project markers will be removed when true
* @return true if operation was successful, false otherwise
*/
public static boolean invokeBldmakeCommand(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, String[] bldmakeArgs, boolean removeMarkers) {
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
IProject project = cpi.getProject();
if (removeMarkers) {
try {
removeAllMarkers(project);
} catch (CoreException e) {
e.printStackTrace();
}
}
return getBuilder(project).invokeBldmakeCommand(buildConfig, launcher, bldmakeArgs);
}
/**
* Call abld with the given arguments
* @param buildConfig the build configuration context
* @param launcher the command launcher
* @param abldArgs array of String arguments to be passed to abld
* @param removeMarkers project markers will be removed when true
* @return true if operation was successful, false otherwise
*/
public static boolean invokeAbldCommand(ICarbideBuildConfiguration buildConfig, CarbideCommandLauncher launcher, String[] abldArgs, boolean removeMarkers) {
ICarbideProjectInfo cpi = buildConfig.getCarbideProject();
IProject project = cpi.getProject();
if (removeMarkers) {
try {
removeAllMarkers(project);
} catch (CoreException e) {
e.printStackTrace();
}
}
return getBuilder(project).invokeAbldCommand(buildConfig, launcher, abldArgs);
}
/**
* Get the array of resolved environment variables. This the entire list of variables that should be
* used during a build for the given configuration
* @param config - The config whose environment variables you want.
* @return An array of environment variables of format <var>=<value>
*/
public static String [] getResolvedEnvVars(ICarbideBuildConfiguration config) {
if (config == null){
return new String[0];
}
return getBuilder(config.getCarbideProject().getProject()).getResolvedEnvVars(config);
}
/**
* Get the array of environment variables that are modified from their default values.
* @param config - Config you are building for.
* @return An array of environment variables of format <var>=<value>
*/
public static String[] getModifiedEnvVars(ICarbideBuildConfiguration config){
return config.getEnvironmentVarsInfo().getModifiedEnvironmentVariables();
}
/**
* Get the environement variables exactly as they come from the system.
* @return An array of environment variables of format <var>=<value>
*/
public static String [] getRawEnvVars(){
return EnvironmentReader.getRawEnvVars();
}
/**
* Generates the bldmake makefiles if necessary.
* If abld.bat or any makefiles don't exist, or if the bld.inf or any of its includes
* is newer than any of the makefiles, then generates the makefiles by running
* 'bldmake bldfiles platform'.
* @param config the build configuration context
* @param launcher the Carbide launcher
* @return false if makefile generation was necessary but failed, true otherwise
*/
public static boolean generateBldmakeMakefilesIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher) {
if (needsBldmakeMakefileGeneration(config)) {
List<String> argsList = new ArrayList<String>();
argsList.add("bldfiles");
argsList.add(config.getBasePlatformForVariation().toLowerCase());
for (String arg : config.getBuildArgumentsInfo().getBldmakeBldFilesArgs().split(" ")) {
argsList.add(arg);
}
if (!invokeBldmakeCommand(config, launcher, argsList.toArray(new String[argsList.size()]), false)) {
return false;
}
} else {
launcher.writeToConsole("***Makefile structures up to date. Skipping 'bldmake bldfiles'\n");
}
return true;
}
/**
* Check to see if abld.bat and the bldmake makefiles exists, or if they are stale.
* If abld.bat or any makefiles don't exist, or if the bld.inf or any of its includes
* is newer than any of the makefiles, then returns true.
* @param config - The build configuration to check the makefiles for
* @return true if makefiles need to be regenerated (bldmake bldfiles platform)
*/
protected static boolean needsBldmakeMakefileGeneration(ICarbideBuildConfiguration config) {
return getBuilder(config.getCarbideProject().getProject()).needsBldmakeMakefileGeneration(config);
}
/**
* Generates the abld makefiles if necessary.
* Loops through the mmp files to be built for the given build configuration and generates the makefile
* for the mmp if:
* 1) the makefile for the mmp does not exist
* 2) if the mmp or any of its includes is newer than the makefile
* 3) the makefile does not have the necessary Carbide changes
*
* The command used will be 'abld [test] makefile platform mmpname'
* @param config the build configuration context
* @param launcher the Carbide launcher
* @return false if any makefile generation was necessary but failed, true otherwise
*/
public static boolean generateAbldMakefilesIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher) {
return generateAbldMakefilesIfNecessary(config, launcher, true);
}
/**
* Generates the abld makefiles if necessary.
* Loops through the mmp files to be built for the given build configuration and generates the makefile
* for the mmp if:
* 1) the makefile for the mmp does not exist
* 2) if the mmp or any of its includes is newer than the makefile
* 3) the makefile does not have the necessary Carbide changes
*
* The command used will be 'abld [test] makefile platform mmpname'
* @param config the build configuration context
* @param launcher the Carbide launcher
* @param calculateComponentLists whether or not to calculate the list of makmake components
* @return false if any makefile generation was necessary but failed, true otherwise
* @since 2.0
* @deprecated Use {@link #generateAbldMakeFileIfNecessary(generateAbldMakefilesIfNecessary(ICarbideBuildConfiguration, CarbideCommandLauncher, boolean, IProgressMonitor)} instead
*/
public static boolean generateAbldMakefilesIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher, boolean calculateComponentLists) {
return generateAbldMakefilesIfNecessary(config, launcher, calculateComponentLists, new NullProgressMonitor());
}
/**
* Generates the abld makefiles if necessary.
* Loops through the mmp files to be built for the given build configuration and generates the makefile
* for the mmp if:
* 1) the makefile for the mmp does not exist
* 2) if the mmp or any of its includes is newer than the makefile
* 3) the makefile does not have the necessary Carbide changes
*
* The command used will be 'abld [test] makefile platform mmpname'
* @param config the build configuration context
* @param launcher the Carbide launcher
* @param calculateComponentLists whether or not to calculate the list of makmake components
* @param progress monitor to allow user to cancel
* @return false if any makefile generation was necessary but failed, true otherwise
* @since 2.0
*/
public static boolean generateAbldMakefilesIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher, boolean calculateComponentLists, IProgressMonitor progress) {
if (calculateComponentLists) {
calculateComponentLists(config, launcher);
}
// generate the makefiles if necessary
for (IPath path : normalMakMakePaths) {
if (!generateAbldMakefileIfNecessary(config, launcher, path, false, progress)) {
return false;
}
}
for (IPath path : testMakMakePaths) {
if (!generateAbldMakefileIfNecessary(config, launcher, path, true, progress)) {
return false;
}
}
return true;
}
/**
* Generates the abld makefile if necessary.
* Generates the makefile for the given mmp file if:
* 1) the makefile for the mmp does not exist
* 2) if the mmp or any of its includes is newer than the makefile
* 3) the makefile does not have the necessary Carbide changes
*
* The command used will be 'abld [test] makefile platform mmpname'
* @param config the build configuration context
* @param launcher the Carbide launcher
* @param componentPath the absolute file system path of the component
* @param isTest true for test components, false otherwise
* @return false if any makefile generation was necessary but failed, true otherwise
*
* @deprecated use {@link #generateAbldMakefileIfNecessary(ICarbideBuildConfiguration, CarbideCommandLauncher, IPath, boolean, IProgressMonitor)} instead
*/
protected static boolean generateAbldMakefileIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher, IPath componentPath, boolean isTest) {
return generateAbldMakefileIfNecessary(config, launcher, componentPath, isTest, new NullProgressMonitor());
}
/**
* Generates the abld makefile if necessary.
* Generates the makefile for the given mmp file if:
* 1) the makefile for the mmp does not exist
* 2) if the mmp or any of its includes is newer than the makefile
* 3) the makefile does not have the necessary Carbide changes
*
* The command used will be 'abld [test] makefile platform mmpname'
* @param config the build configuration context
* @param launcher the Carbide launcher
* @param componentPath the absolute file system path of the component
* @param isTest true for test components, false otherwise
* @return false if any makefile generation was necessary but failed, true otherwise
*/
protected static boolean generateAbldMakefileIfNecessary(ICarbideBuildConfiguration config, CarbideCommandLauncher launcher, IPath componentPath, boolean isTest, IProgressMonitor progress) {
return getBuilder(config.getCarbideProject().getProject()).generateAbldMakefileIfNecessary(config, launcher, componentPath, isTest, progress);
}
/**
* Get the array of parser ID's (extension ID from plugin.xml) that will be used to parse the output
* of a given process invoked by the CarbideCommandLauncher. If you don't know which parser to use
* you can use them all by passed ICarbideBuildeConfiguration.ERROR_PARSERS_ALL
* @param id - The id to use to get the parsers.
* @return An array of parser id's to iterate through to find matches in the stdout and stderrr
* @see CarbideCommandLauncher, ICarbideBuildConfiguration.ERROR_PARSERS*
*/
public static String[] getParserIdArray(int id) {
String[] parserIds = new String[0];
switch (id) {
case ICarbideBuildConfiguration.ERROR_PARSERS_WINSCW:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.MakmakeErrorParser",
"com.nokia.carbide.cdt.builder.SBSv2ErrorParser",
"com.nokia.carbide.cdt.builder.CarbideMakeErrorParser",
"com.nokia.carbide.cdt.builder.RCOMPErrorParser",
"org.eclipse.cdt.core.GCCErrorParser", // for cpp message from RCOMP
"com.nokia.carbide.cdt.builder.MWLDErrorParser",
"com.nokia.carbide.cdt.builder.MWCCErrorParser",
"com.nokia.carbide.cdt.builder.MakeDefErrorParser"
};
break;
case ICarbideBuildConfiguration.ERROR_PARSERS_ARMVx:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.MakmakeErrorParser",
"com.nokia.carbide.cdt.builder.SBSv2ErrorParser",
"com.nokia.carbide.cdt.builder.CarbideMakeErrorParser",
"com.nokia.carbide.cdt.builder.RVCTCompilerErrorParser",
"com.nokia.carbide.cdt.builder.RVCTLinkerErrorParser",
"com.nokia.carbide.cdt.builder.MakeDefErrorParser",
"com.nokia.carbide.cdt.builder.RCOMPErrorParser",
"org.eclipse.cdt.core.GCCErrorParser", // for cpp message from RCOMP
"com.nokia.carbide.cdt.builder.Elf2E32ErrorParser"
};
break;
case ICarbideBuildConfiguration.ERROR_PARSERS_GCCE:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.MakmakeErrorParser",
"com.nokia.carbide.cdt.builder.SBSv2ErrorParser",
"com.nokia.carbide.cdt.builder.CarbideMakeErrorParser",
"com.nokia.carbide.cdt.builder.RCOMPErrorParser",
"com.nokia.carbide.cdt.builder.GCCECompilerErrorParser", // also handles cpp message from RCOMP
"com.nokia.carbide.cdt.builder.GCCEAssemblerErrorParser",
"com.nokia.carbide.cdt.builder.GCCELinkerErrorParser",
"com.nokia.carbide.cdt.builder.MakeDefErrorParser",
"com.nokia.carbide.cdt.builder.Elf2E32ErrorParser"
};
break;
case ICarbideBuildConfiguration.ERROR_PARSERS_ARM_EKA1:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.MakmakeErrorParser",
"com.nokia.carbide.cdt.builder.SBSv2ErrorParser",
"com.nokia.carbide.cdt.builder.CarbideMakeErrorParser",
"com.nokia.carbide.cdt.builder.RCOMPErrorParser",
"org.eclipse.cdt.core.GCCErrorParser",
"org.eclipse.cdt.core.GLDErrorParser",
"com.nokia.carbide.cdt.builder.MakeDefErrorParser",
"com.nokia.carbide.cdt.builder.DLLToolErrorParser"
};
break;
case ICarbideBuildConfiguration.ERROR_PARSERS_SIS_BUILDER:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.MakeSisErrorParser"
};
break;
case ICarbideBuildConfiguration.ERROR_PARSERS_BLDMAKE_MAKE:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.BldmakeErrorParser",
"com.nokia.carbide.cdt.builder.SBSv2ErrorParser"
};
break;
case ICarbideBuildConfiguration.ERROR_PARSERS_ROM_BUILDER:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.RomBuildErrorParser"
};
break;
case ICarbideBuildConfiguration.ERROR_PARSERS_ALL:
default:
parserIds = new String[] {
"com.nokia.carbide.cdt.builder.BldmakeErrorParser",
"com.nokia.carbide.cdt.builder.MakeSisErrorParser",
"com.nokia.carbide.cdt.builder.MakmakeErrorParser",
"com.nokia.carbide.cdt.builder.SBSv2ErrorParser",
"com.nokia.carbide.cdt.builder.CarbideMakeErrorParser",
"com.nokia.carbide.cdt.builder.RVCTCompilerErrorParser",
"com.nokia.carbide.cdt.builder.RVCTLinkerErrorParser",
"com.nokia.carbide.cdt.builder.RCOMPErrorParser",
"org.eclipse.cdt.core.GCCErrorParser", // for cpp message from RCOMP
"com.nokia.carbide.cdt.builder.MWLDErrorParser",
"com.nokia.carbide.cdt.builder.MakeDefErrorParser",
"com.nokia.carbide.cdt.builder.Elf2E32ErrorParser",
"com.nokia.carbide.cdt.builder.RomBuildErrorParser"
};
break;
}
return parserIds;
}
/**
* Remove all the C/C++ markers for the current project.
* @param currProject - Project to remove markers for.
* @throws CoreException
*/
public static void removeAllMarkers(IProject currProject) throws CoreException {
IWorkspace workspace = currProject.getWorkspace();
// remove all markers
IMarker[] markers = currProject.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
if (markers != null) {
workspace.deleteMarkers(markers);
}
markers = currProject.findMarkers(CarbideBuilderPlugin.CARBIDE_PROJECT_MARKER, true, IResource.DEPTH_INFINITE);
if (markers != null) {
workspace.deleteMarkers(markers);
}
}
/**
* Invoke the SIS builder for all pkg files for the given build configuration
* @param config - The current configuration from where to get the settings from
* @param cmdLauncher - The object to use for the process execution
* @param monitor - An IProgressMonitor
*/
public static void invokeSISBuilder(ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor) {
int enabledSisInfos = 0;
List<ISISBuilderInfo> sisList = config.getSISBuilderInfoList();
for (ISISBuilderInfo sisInfo : sisList) {
if (sisInfo.isEnabled()) {
enabledSisInfos++;
}
}
if (enabledSisInfos < 1) {
return;
}
SubMonitor subMonitor = SubMonitor.convert(monitor, enabledSisInfos);
for (ISISBuilderInfo sisInfo : sisList) {
if (!sisInfo.isEnabled()) {
continue;
}
buildSisFile(sisInfo, config, cmdLauncher, subMonitor.newChild(1), false);
}
monitor.done();
}
/**
* Invoke the SIS builder for either EKA1 or EKA2 projects. Depending on the os version will
* determine if makesis or makeis/signsis will get called
* @param pkgPath - Full path to the PKG file to be used to generate the SIS file
* @param config - The current configuration from where to get the settings for
* @param cmdLauncher - The object to use for the process execution
* @param monitor - An IProgressMonitor
* @param createOutputFromPKGFileName - When true, only create output file name based on PKG file name, otherwise check the SIS build settings.
*/
public static void invokeSISBuilder(IPath pkgPath, ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor, boolean createOutputFromPKGFileName) {
int sisInfosForPkg = 0;
List<ISISBuilderInfo> sisList = config.getSISBuilderInfoList();
for (ISISBuilderInfo sisInfo : sisList) {
// ignoring enabled flag on purpose
if (sisInfo.getPKGFullPath().equals(pkgPath)) {
sisInfosForPkg++;
}
}
if (sisInfosForPkg < 1) {
cmdLauncher.writeToConsole("No SIS Builder info found for pkg file.");
return;
}
SubMonitor subMonitor = SubMonitor.convert(monitor, sisInfosForPkg);
for (ISISBuilderInfo sisInfo : sisList) {
// ignoring enabled flag on purpose
if (!sisInfo.getPKGFullPath().equals(pkgPath)) {
continue;
}
buildSisFile(sisInfo, config, cmdLauncher, subMonitor.newChild(1), createOutputFromPKGFileName);
}
monitor.done();
}
private static void buildSisFile(final ISISBuilderInfo sisInfo, final ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor, boolean createOutputFromPKGFileName) {
IPath pkgPath = sisInfo.getPKGFullPath();
if (pkgPath == null) {
cmdLauncher.writeToConsole("PKG file does not exist. Skipping...");
return;
} else if (!pkgPath.toFile().exists()) {
try {
// Check to see if this is a Qt project and if the template format could have changed.
IProject project = config.getCarbideProject().getProject();
if (project != null && project.hasNature(QtCorePlugin.QT_PROJECT_NATURE_ID)){
final String currentPKGName = pkgPath.lastSegment();
pkgPath = pkgPath.removeLastSegments(1).append(project.getName() + "_template.pkg" ); //$NON-NLS-N$
if (pkgPath.toFile().exists()){
final IPath finalPkgPath = pkgPath;
Display.getDefault().syncExec(new Runnable() {
public void run() {
if (true == MessageDialog.openQuestion(WorkbenchUtils.getSafeShell(), "Can not find PKG file for SIS builder", "The file \"" + currentPKGName + "\" does not exist for this Qt project. The suggested file is \"" + finalPkgPath.lastSegment() + "\".\n\nDo you want to update your build configuration to use this PKG file?")) { //$NON-NLS-1$ //$NON-NLS-2$
IWorkspace workspace= ResourcesPlugin.getWorkspace();
IFile ifile= workspace.getRoot().getFileForLocation(finalPkgPath);
sisInfo.setPKGFile(ifile.getLocation().toOSString());
config.getSISBuilderInfoList().remove(sisInfo);
config.getSISBuilderInfoList().add(sisInfo);
config.saveConfiguration(false);
}
}
});
}
}
} catch (CoreException e) {
e.printStackTrace();
}
if (!sisInfo.getPKGFullPath().toFile().exists()){
cmdLauncher.writeToConsole("PKG file " + pkgPath.toOSString() + " does not exist. Skipping..."); //$NON-NLS-N$
return;
}
}
// see if we need to rebuild the sis file
boolean shouldBuild = false;
String sisName = createOutputFromPKGFileName ? pkgPath.toOSString().substring(0, pkgPath.toOSString().lastIndexOf(".")) + ".sis" : sisInfo.getUnsignedSISFullPath().toOSString();
File sisFile = new File(sisName);
if (!sisFile.exists()) {
// no sis file - need to build
shouldBuild = true;
} else {
long sisFileTimestamp = sisFile.lastModified();
// see if the pkg file is newer than the sis
if (pkgPath.toFile().lastModified() > sisFileTimestamp) {
shouldBuild = true;
} else {
// get the list of files from the pkg file and check for their existence
for (IPath path : EpocEngineHelper.getFilesInPKG(pkgPath, config, sisInfo)) {
File file = path.toFile();
if (!file.exists()) {
shouldBuild = true;
break;
}
}
}
}
if (!shouldBuild) {
// see if they have changed any sis builder settings since the
// last build
if (sisInfo instanceof SISBuilderInfo2) {
SISBuilderInfo2 info = (SISBuilderInfo2)sisInfo;
if (info.hasSisChanges()) {
shouldBuild = true;
}
}
}
// check to see if any of the files listed in the pkg have changed since the sis file
// was last built. remember the list of files that have changed in case we're building
// a partial upgrade
boolean creatingPU = false;
boolean createPartialUpgradeEnabled = false;
if (sisInfo instanceof SISBuilderInfo2) {
createPartialUpgradeEnabled = ((SISBuilderInfo2)sisInfo).isPartialUpgrade();
}
final List<File> modifiedFiles = new ArrayList<File>();
if (!shouldBuild) {
long sisFileTimestamp = sisFile.lastModified();
for (IPath path : EpocEngineHelper.getFilesInPKG(pkgPath, config, sisInfo)) {
if (path.toFile().lastModified() > sisFileTimestamp) {
// file has changed since the sis was built
shouldBuild = true;
if (createPartialUpgradeEnabled) {
modifiedFiles.add(path.toFile());
} else {
break;
}
}
}
}
SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
if (shouldBuild) {
if (sisInfo instanceof SISBuilderInfo2) {
SISBuilderInfo2 info = (SISBuilderInfo2)sisInfo;
info.setHasSisChanges(false);
}
subMonitor.setTaskName("Building sis file");
// put temp _resolved.pkg file in epoc32/build tree
IPath buildDirPath = getBuilder(config.getCarbideProject().getProject()).getMakefileDirectory(config);
String prefix = RESOLVED_PKG_PREFIX;
IPath tmpPKGPath = buildDirPath.append(prefix + pkgPath.lastSegment());
IPath resolvedPKGPath = resolvePKGFile(pkgPath, config, tmpPKGPath);
List<String> args = new ArrayList<String>();
// add the search location if specified
String searchDir = sisInfo.getContentSearchLocation();
if (searchDir != null && searchDir.length() > 0) {
args.add("-d" + searchDir);
}
args.add(resolvedPKGPath.toOSString());
args.add(sisName);
IPath makeSisPath = config.getSDK().getToolsPath().append(MAKESIS_EXE);
cmdLauncher.writeToConsole("\n***Invoking " + MAKESIS_EXE + " ....\n");
cmdLauncher.setErrorParserManager(pkgPath.removeLastSegments(1), getParserIdArray(ICarbideBuildConfiguration.ERROR_PARSERS_SIS_BUILDER));
int retVal = cmdLauncher.executeCommand(makeSisPath, args.toArray(new String[args.size()]), getResolvedEnvVars(config), pkgPath.removeLastSegments(1));
subMonitor.worked(1);
if (subMonitor.isCanceled()) {
return;
}
if (retVal != 0){
cmdLauncher.writeToConsole("***Non-Zero Status: " + MAKESIS_EXE + " returned with exit value = " + retVal);
CarbideBuilderPlugin.createCarbideProjectMarker(config.getCarbideProject().getProject(), IMarker.SEVERITY_ERROR, MAKESIS_EXE + " returned with exit value = " + retVal, IMarker.PRIORITY_LOW);
return;
}
// now create the partial upgrade sis file if necessary
if (createPartialUpgradeEnabled && modifiedFiles.size() > 0) {
creatingPU = true;
if (!createPartialUpgradeSis(sisInfo, config, cmdLauncher, subMonitor, createOutputFromPKGFileName, modifiedFiles)) {
return;
}
} else {
// delete the partial upgrade files and links if they exist since they are now obsolete
IFile tempPkgFileLink = getTempPkgIFile(pkgPath, getTempPkgBuildTreePath(sisInfo, config), config);
if (tempPkgFileLink.exists()) {
try {
tempPkgFileLink.getRawLocation().toFile().delete();
tempPkgFileLink.delete(0, null);
} catch (CoreException e) {
e.printStackTrace();
CarbideBuilderPlugin.log(e);
}
}
IPath tempPkgBuildTreePath = getTempPkgBuildTreePath(sisInfo, config);
IFile tempSisFileLink = getTempSisIFile(pkgPath, getPUSisPath(sisInfo, tempPkgBuildTreePath, createOutputFromPKGFileName, false), config);
if (tempSisFileLink.exists()) {
try {
tempSisFileLink.getRawLocation().toFile().delete();
tempSisFileLink.delete(0, null);
} catch (CoreException e) {
e.printStackTrace();
CarbideBuilderPlugin.log(e);
}
}
}
} else {
subMonitor.worked(1);
if (subMonitor.isCanceled()) {
return;
}
cmdLauncher.writeToConsole("\nSIS file " + sisFile.getAbsolutePath() + " already up to date. Skipping...");
}
buildSisxFile(sisInfo, config, cmdLauncher, monitor, createOutputFromPKGFileName, sisFile, creatingPU);
cmdLauncher.writeToConsole("\n***SIS Creation Complete\n");
}
private static void buildSisxFile(ISISBuilderInfo sisInfo, ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor, boolean createOutputFromPKGFileName, File sisFile, boolean creatingPu) {
if (sisInfo.getSigningType() == ISISBuilderInfo.DONT_SIGN) {
return;
}
boolean shouldBuild = false;
IPath pkgPath = sisInfo.getPKGFullPath();
String sisxName = sisInfo.getSignedSISFullPath().toOSString();
if (createOutputFromPKGFileName){
sisxName = pkgPath.toOSString().substring(0, pkgPath.toOSString().lastIndexOf(".")) + ".sisx";
}
File sisxFile = new File(sisxName);
if (!sisxFile.exists()) {
// no sisx file - need to build
shouldBuild = true;
} else {
// see if the sis file is newer than the sisx
if (sisFile.lastModified() > sisxFile.lastModified()) {
shouldBuild = true;
}
}
if (!shouldBuild) {
// see if they have changed any sisx builder settings since the
// last build
if (sisInfo instanceof SISBuilderInfo2) {
SISBuilderInfo2 info = (SISBuilderInfo2)sisInfo;
if (info.hasSisxChanges()) {
shouldBuild = true;
}
}
}
SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
if (shouldBuild) {
if (sisInfo instanceof SISBuilderInfo2) {
SISBuilderInfo2 info = (SISBuilderInfo2)sisInfo;
info.setHasSisxChanges(false);
}
IPath buildDirPath = getBuilder(config.getCarbideProject().getProject()).getMakefileDirectory(config);
int signingMethod = sisInfo.getSigningType();
if (signingMethod != ISISBuilderInfo.DONT_SIGN) {
String password = sisInfo.getPassword();
if (signingMethod == ISISBuilderInfo.SELF_SIGN) {
// call makekeys
cmdLauncher.writeToConsole("\n...No key/cert defined. Generating dummy key/cert for self-signing (" + DEFAULT_KEY_NAME + "/" + DEFAULT_CERT_NAME + ")...\n");
if (password.length() == 0){
password = DEAULT_PASSWORD;
cmdLauncher.writeToConsole("No passphrase defined. Using: \"" + DEAULT_PASSWORD + "\"\n");
}
cmdLauncher.writeToConsole("\n***Invoking makekeys....\n");
IPath makekeys = config.getSDK().getToolsPath().append(MAKEKEYS_EXE);
List<String> makekeysArgList = new ArrayList<String>();
makekeysArgList.add("-cert");
makekeysArgList.add("-password");
makekeysArgList.add(password);
makekeysArgList.add("-len");
makekeysArgList.add("2048");
makekeysArgList.add("-dname");
makekeysArgList.add("\"CN=JoeBloggs OR=Acme\"");
makekeysArgList.add(DEFAULT_KEY_NAME);
makekeysArgList.add(DEFAULT_CERT_NAME);
String[] makeKeysArgs =
(String[]) makekeysArgList.toArray(new String[makekeysArgList.size()]);
// set the working directory to the epoc32/build directory so the temp file get generated there
subMonitor.setTaskName("Invoking makekeys...");
cmdLauncher.setErrorParserManager(pkgPath.removeLastSegments(1), getParserIdArray(ICarbideBuildConfiguration.ERROR_PARSERS_SIS_BUILDER));
int retVal = cmdLauncher.executeCommand(makekeys, makeKeysArgs, getResolvedEnvVars(config), buildDirPath);
if (retVal != 0){
cmdLauncher.writeToConsole("***Non-Zero Status: " + MAKEKEYS_EXE + " returned with exit value = " + retVal);
CarbideBuilderPlugin.createCarbideProjectMarker(config.getCarbideProject().getProject(), IMarker.SEVERITY_ERROR, MAKEKEYS_EXE + " returned with exit value = " + retVal, IMarker.PRIORITY_LOW);
return;
}
subMonitor.worked(1);
if (subMonitor.isCanceled()) {
return;
}
}
// call signsis...
cmdLauncher.writeToConsole("\n***Invoking " + SIGNSIS_EXE + "....\n");
IPath signsis = config.getSDK().getToolsPath().append(SIGNSIS_EXE);
List<String> signSISArgList = new ArrayList<String>();
if (sisInfo.getAdditionalOptions().length() > 0){
String additionalOpts = sisInfo.getAdditionalOptions();
String[] addOptsArray = additionalOpts.split(" ");
if (addOptsArray.length > 0){
for (String currOpt : addOptsArray) {
signSISArgList.add(currOpt);
}
}
}
signSISArgList.add("-s");
if (createOutputFromPKGFileName){
String sisName = pkgPath.toOSString().substring(0, pkgPath.toOSString().lastIndexOf(".")) + ".sis";
signSISArgList.add(sisName);
signSISArgList.add(sisName + "x");
} else {
signSISArgList.add(sisInfo.getUnsignedSISFullPath().toOSString());
signSISArgList.add(sisInfo.getSignedSISFullPath().toOSString());
}
if (signingMethod == ISISBuilderInfo.SELF_SIGN) {
signSISArgList.add(buildDirPath.append(DEFAULT_CERT_NAME).toOSString());
signSISArgList.add(buildDirPath.append(DEFAULT_KEY_NAME).toOSString());
} else {
signSISArgList.add("\"" + sisInfo.getCertificateFullPath().toOSString() + "\"");
signSISArgList.add("\"" + sisInfo.getKeyFullPath().toOSString() + "\"");
}
signSISArgList.add(password);
String[] signSisArgs = (String[]) signSISArgList.toArray(new String[signSISArgList.size()]);
subMonitor.setTaskName("Signing sisfile...");
cmdLauncher.setErrorParserManager(pkgPath.removeLastSegments(1), getParserIdArray(ICarbideBuildConfiguration.ERROR_PARSERS_SIS_BUILDER));
int retVal = cmdLauncher.executeCommand(signsis, signSisArgs, getResolvedEnvVars(config), pkgPath.removeLastSegments(1));
if (retVal != 0) {
cmdLauncher.writeToConsole("***Non-Zero Status: " + SIGNSIS_EXE + " returned with exit value = " + retVal);
CarbideBuilderPlugin.createCarbideProjectMarker(config.getCarbideProject().getProject(), IMarker.SEVERITY_ERROR, SIGNSIS_EXE + " returned with exit value = " + retVal, IMarker.PRIORITY_LOW);
return;
}
// now create the partial upgrade sisx file if necessary
if (creatingPu) {
if (!createPartialUpgradeSisx(sisInfo, config, cmdLauncher, subMonitor, createOutputFromPKGFileName)) {
return;
}
} else {
// delete the partial upgrade file and link if they exist since they are now obsolete
IPath tempPkgBuildTreePath = getTempPkgBuildTreePath(sisInfo, config);
IFile tempSisxFileLink = getTempSisIFile(pkgPath, getPUSisPath(sisInfo, tempPkgBuildTreePath, createOutputFromPKGFileName, true), config);
if (tempSisxFileLink.exists()) {
try {
tempSisxFileLink.getRawLocation().toFile().delete();
tempSisxFileLink.delete(0, null);
} catch (CoreException e) {
e.printStackTrace();
CarbideBuilderPlugin.log(e);
}
}
}
}
subMonitor.worked(1);
if (subMonitor.isCanceled()) {
return;
}
} else {
subMonitor.worked(2);
if (subMonitor.isCanceled()) {
return;
}
cmdLauncher.writeToConsole("\nSISX file " + sisxFile.getAbsolutePath() + " already up to date. Skipping...");
}
}
private static boolean createPartialUpgradeSis(final ISISBuilderInfo sisInfo, final ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor, boolean createOutputFromPKGFileName, final List<File> modifiedFiles) {
final IPath pkgPath = sisInfo.getPKGFullPath();
// make a copy of the pkg file and put it in the epoc32 build tree
IPath tempPkgBuildTreePath = getTempPkgBuildTreePath(sisInfo, config);
File tempPkgFile = tempPkgBuildTreePath.toFile();
try {
if (!tempPkgFile.exists()) {
tempPkgFile.createNewFile();
}
FileUtils.copyFile(pkgPath.toFile(), tempPkgFile);
} catch (IOException e) {
e.printStackTrace();
CarbideBuilderPlugin.log(e);
return false;
}
// update the temp pkg file by setting the PU flag and removing any files that have not been modified
PKGModelHelper.runWithPKGView(tempPkgBuildTreePath,
new DefaultViewConfiguration(config.getCarbideProject(), config),
new PKGViewRunnableAdapter() {
public Object run(IPKGView view) {
PKGViewPathHelper helper = new PKGViewPathHelper(view, config);
if (sisInfo != null) {
helper.setSISBuilderInfo(sisInfo);
}
// we moved the file so we need to set the main directory for the parser so it picks up
// relative paths correctly.
helper.setMainDirectory(pkgPath.removeLastSegments(1));
// set the PU flag in the package header
IPKGHeader header = view.getPackageHeader();
if (header != null) {
String puFlag = "TYPE=PU"; //$NON-NLS-1$
List<String> options = header.getOptions();
if (!options.contains(puFlag)) {
options.add(puFlag);
}
view.setPackageHeader(header);
}
// remove any files that haven't changed
for (IPKGInstallFile file : view.getAllInstallFiles()) {
Map<EPKGLanguage, IPath> sourceFiles = file.getSourceFiles();
// with multiple launguages, we need to keep the install file if any one of
// the language variant files has changed
boolean anyVariantHasChanged = false;
for (EPKGLanguage language : sourceFiles.keySet()) {
IPath path = helper.getAbsolutePathFromViewPath(sourceFiles.get(language));
if (path != null) {
if (modifiedFiles.contains(path.toFile())) {
anyVariantHasChanged = true;
break;
}
}
}
if (!anyVariantHasChanged) {
view.removeInstallFile(file);
}
}
// remove any embedded sis files that haven't changed
for (IPKGEmbeddedSISFile file : view.getAllEmbeddedSISFiles()) {
Map<EPKGLanguage, IPath> sourceFiles = file.getSourceFiles();
// with multiple launguages, we need to keep the embedded sis file if any one of
// the language variant files has changed
boolean anyVariantHasChanged = false;
for (EPKGLanguage language : sourceFiles.keySet()) {
IPath path = helper.getAbsolutePathFromViewPath(sourceFiles.get(language));
if (path != null) {
if (modifiedFiles.contains(path.toFile())) {
anyVariantHasChanged = true;
break;
}
}
}
if (!anyVariantHasChanged) {
view.removeEmbeddedSISFile(file);
}
}
// now commit the changes and release the file
while (true) {
try {
view.commit();
break;
} catch (IllegalStateException e) {
if (!view.merge()) {
view.revert();
}
}
}
return null;
}
});
tempPkgBuildTreePath = resolvePKGFile(tempPkgBuildTreePath, config, tempPkgBuildTreePath);
// create link to temp pkg file and mark it as derived.
IFile tempPkgFileLink = getTempPkgIFile(pkgPath, tempPkgBuildTreePath, config);
if (!tempPkgFileLink.exists()) {
try {
tempPkgFileLink.createLink(tempPkgBuildTreePath, 0, null);
tempPkgFileLink.setDerived(true);
} catch (CoreException e) {
e.printStackTrace();
CarbideBuilderPlugin.log(e);
return false;
}
}
// change the sis name and location as well
IPath puSisPath = getPUSisPath(sisInfo, tempPkgBuildTreePath, createOutputFromPKGFileName, false);
List<String> args = new ArrayList<String>();
// add the search location if specified
String searchDir = sisInfo.getContentSearchLocation();
if (searchDir != null && searchDir.length() > 0) {
args.add("-d" + searchDir);
}
args.add(tempPkgBuildTreePath.toOSString());
args.add(puSisPath.toOSString());
cmdLauncher.writeToConsole("\n***Invoking " + MAKESIS_EXE + " for partial upgrade....\n");
cmdLauncher.setErrorParserManager(pkgPath.removeLastSegments(1), getParserIdArray(ICarbideBuildConfiguration.ERROR_PARSERS_SIS_BUILDER));
IPath makeSisPath = config.getSDK().getToolsPath().append(MAKESIS_EXE);
int retVal = cmdLauncher.executeCommand(makeSisPath, args.toArray(new String[args.size()]), getResolvedEnvVars(config), pkgPath.removeLastSegments(1));
SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
subMonitor.setTaskName("Building partial upgrade sis file");
subMonitor.worked(1);
if (subMonitor.isCanceled()) {
return false;
}
if (retVal != 0){
cmdLauncher.writeToConsole("***Non-Zero Status: " + MAKESIS_EXE + " returned with exit value = " + retVal);
CarbideBuilderPlugin.createCarbideProjectMarker(config.getCarbideProject().getProject(), IMarker.SEVERITY_ERROR, MAKESIS_EXE + " returned with exit value = " + retVal, IMarker.PRIORITY_LOW);
return false;
} else {
// create link to sis file
IFile tempSisFile = getTempSisIFile(pkgPath, puSisPath, config);
if (!tempSisFile.exists()) {
try {
tempSisFile.createLink(puSisPath, 0, null);
} catch (CoreException e) {
e.printStackTrace();
CarbideBuilderPlugin.log(e);
return false;
}
}
}
return true;
}
private static boolean createPartialUpgradeSisx(final ISISBuilderInfo sisInfo, final ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor, boolean createOutputFromPKGFileName) {
if (sisInfo.getSigningType() == ISISBuilderInfo.DONT_SIGN) {
return true;
}
String sisxName = "PU_" + sisInfo.getSignedSISFullPath().lastSegment();
if (createOutputFromPKGFileName) {
String pkgName = sisInfo.getPKGFullPath().lastSegment();
sisxName = pkgName.substring(0, pkgName.lastIndexOf(".")) + ".sisx";
}
IPath buildDirPath = getBuilder(config.getCarbideProject().getProject()).getMakefileDirectory(config);
IPath puSisxPath = buildDirPath.append(sisxName);
SubMonitor subMonitor = SubMonitor.convert(monitor, 2);
// call signsis...
cmdLauncher.writeToConsole("\n***Invoking " + SIGNSIS_EXE + " for partial upgrade....\n");
IPath signsis = config.getSDK().getToolsPath().append(SIGNSIS_EXE);
List<String> signSISArgList = new ArrayList<String>();
if (sisInfo.getAdditionalOptions().length() > 0){
String additionalOpts = sisInfo.getAdditionalOptions();
String[] addOptsArray = additionalOpts.split(" ");
if (addOptsArray.length > 0){
for (String currOpt : addOptsArray) {
signSISArgList.add(currOpt);
}
}
}
signSISArgList.add("-s");
signSISArgList.add(getPUSisPath(sisInfo, getTempPkgBuildTreePath(sisInfo, config), createOutputFromPKGFileName, false).toOSString());
signSISArgList.add(puSisxPath.toOSString());
String password = sisInfo.getPassword();
if (sisInfo.getSigningType() == ISISBuilderInfo.SELF_SIGN) {
signSISArgList.add(buildDirPath.append(DEFAULT_CERT_NAME).toOSString());
signSISArgList.add(buildDirPath.append(DEFAULT_KEY_NAME).toOSString());
if (password.length() == 0){
password = DEAULT_PASSWORD;
cmdLauncher.writeToConsole("No passphrase defined. Using: \"" + DEAULT_PASSWORD + "\"\n");
}
} else {
signSISArgList.add("\"" + sisInfo.getCertificateFullPath().toOSString() + "\"");
signSISArgList.add("\"" + sisInfo.getKeyFullPath().toOSString() + "\"");
}
signSISArgList.add(password);
String[] signSisArgs = (String[]) signSISArgList.toArray(new String[signSISArgList.size()]);
subMonitor.setTaskName("Signing partial upgrade sisfile...");
IPath pkgPath = sisInfo.getPKGFullPath();
cmdLauncher.setErrorParserManager(pkgPath.removeLastSegments(1), getParserIdArray(ICarbideBuildConfiguration.ERROR_PARSERS_SIS_BUILDER));
int retVal = cmdLauncher.executeCommand(signsis, signSisArgs, getResolvedEnvVars(config), pkgPath.removeLastSegments(1));
if (retVal != 0){
cmdLauncher.writeToConsole("***Non-Zero Status: " + SIGNSIS_EXE + " returned with exit value = " + retVal);
CarbideBuilderPlugin.createCarbideProjectMarker(config.getCarbideProject().getProject(), IMarker.SEVERITY_ERROR, SIGNSIS_EXE + " returned with exit value = " + retVal, IMarker.PRIORITY_LOW);
return false;
} else {
// create link to sisx file
IFile tempSisxFile = getTempSisIFile(pkgPath, puSisxPath, config);
if (!tempSisxFile.exists()) {
try {
tempSisxFile.createLink(puSisxPath, 0, null);
} catch (CoreException e) {
e.printStackTrace();
CarbideBuilderPlugin.log(e);
return false;
}
}
}
subMonitor.worked(1);
return true;
}
private static IPath getTempPkgBuildTreePath(ISISBuilderInfo info, ICarbideBuildConfiguration config) {
IPath buildDirPath = getBuilder(config.getCarbideProject().getProject()).getMakefileDirectory(config);
return buildDirPath.append("PU_" + info.getPKGFullPath().lastSegment());
}
private static IPath getPUSisPath(ISISBuilderInfo sisInfo, IPath tempPkgBuildTreePath, boolean createOutputFromPKGFileName, boolean sisx) {
IPath puSisPath = tempPkgBuildTreePath.removeLastSegments(1);
if (createOutputFromPKGFileName) {
String name = tempPkgBuildTreePath.lastSegment();
if (sisx) {
puSisPath = puSisPath.append(name.substring(0, name.lastIndexOf(".")) + ".sisx");
} else {
puSisPath = puSisPath.append(name.substring(0, name.lastIndexOf(".")) + ".sis");
}
} else {
if (sisx) {
puSisPath = puSisPath.append("PU_" + sisInfo.getSignedSISFullPath().lastSegment());
} else {
puSisPath = puSisPath.append("PU_" + sisInfo.getUnsignedSISFullPath().lastSegment());
}
}
return puSisPath;
}
private static IFile getTempPkgIFile(IPath pkgPath, IPath tempPkgBuildTreePath, ICarbideBuildConfiguration config) {
// create the file is in the same directory as the real pkg file. if the pkg file is
// not under the project then create the file in the root of the project.
IPath tempPkgPath = null;
IProject project = config.getCarbideProject().getProject();
IPath projectRootPath = project.getLocation();
if (projectRootPath != null && projectRootPath.isPrefixOf(pkgPath)) {
IPath projectPathToPkg = pkgPath.removeFirstSegments(projectRootPath.segmentCount()).setDevice(null);
tempPkgPath = projectPathToPkg.removeLastSegments(1).append(tempPkgBuildTreePath.lastSegment());
} else {
tempPkgPath = new Path(tempPkgBuildTreePath.lastSegment());
}
return project.getFile(tempPkgPath);
}
private static IFile getTempSisIFile(IPath pkgPath, IPath puSisPath, ICarbideBuildConfiguration config) {
// create the file is in the same directory as the real pkg file. if the pkg file is
// not under the project then create the file in the root of the project.
IPath tempSisPath = null;
IProject project = config.getCarbideProject().getProject();
IPath projectRootPath = project.getLocation();
if (projectRootPath != null && projectRootPath.isPrefixOf(pkgPath)) {
IPath projectPathToPkg = pkgPath.removeFirstSegments(projectRootPath.segmentCount()).setDevice(null);
tempSisPath = projectPathToPkg.removeLastSegments(1).append(puSisPath.lastSegment());
} else {
tempSisPath = new Path(puSisPath.lastSegment());
}
return project.getFile(tempSisPath);
}
/**
* Given PKG file to be built, check to see if it has supported macros and if so replace them so
* the PKG file will contain current build context values.
* @param pkgFile - The PKG file input
* @param context - The sdk/plat/target currently building for
* @param tempPKGFileName - The name of the PKG file to generate. If null or empty string one will be generated for you
* @return IPath - If macros don't exist, the input path is returned others the new file
* that is created, fully resolved is returned.
*/
public static IPath resolvePKGFile(IPath pkgFile, ISymbianBuildContext context, IPath tempPKGFileName){
try {
String charset = null;
IFile iFile = FileUtils.convertFileToIFile(pkgFile.toFile());
if (iFile != null) {
charset = iFile.getCharset();
}
char[] pkgFileBuf = FileUtils.readFileContents(pkgFile.toFile(), charset);
String pkgFileStr = new String(pkgFileBuf);
if (pkgFileStr.contains(PKG_SYMBOL_EPOCROOT) ||
pkgFileStr.contains(PKG_SYMBOL_PLATFORM) ||
pkgFileStr.contains(PKG_SYMBOL_TARGET) ) {
// need to create a new PKG file, resolved...
pkgFileStr = pkgFileStr.replace(PKG_SYMBOL_EPOCROOT, context.getSDK().getEPOCROOT());
pkgFileStr = pkgFileStr.replace(PKG_SYMBOL_PLATFORM, context.getPlatformString());
pkgFileStr = pkgFileStr.replace(PKG_SYMBOL_TARGET, context.getTargetString());
IPath tmpPKGPath = pkgFile.removeLastSegments(1);
if (tempPKGFileName == null){
tmpPKGPath = tmpPKGPath.append(RESOLVED_PKG_PREFIX + pkgFile.lastSegment());
} else {
tmpPKGPath = tempPKGFileName;
}
FileUtils.writeFileContents(tmpPKGPath.toFile(), pkgFileStr.toCharArray(), charset);
return new Path(tmpPKGPath.toString());
}
} catch (CoreException e){
CarbideBuilderPlugin.log(e);
e.printStackTrace();
}
return pkgFile;
}
/**
* Given a sis/sisx path, returns the absolute file system path of the associated
* partial upgrade sis/sisx file if any, otherwise null. note that the file may or
* may not exist.
* @param config the build configuration
* @param sisPath the absolute file system path to the normal sis/sisx file
* @return absolute path to PU sis/sisx file, or null
* @since 2.0
*/
public static IPath getPartialUpgradeSisPath(ICarbideBuildConfiguration config, IPath sisPath) {
for (ISISBuilderInfo info : config.getSISBuilderInfoList()) {
if (info instanceof SISBuilderInfo2) {
SISBuilderInfo2 info2 = (SISBuilderInfo2)info;
if (info2.isPartialUpgrade()) {
if (info2.getFinalSISFullPath().equals(sisPath)) {
return getPUSisPath(info, getTempPkgBuildTreePath(info, config), false, info.getSigningType() != ISISBuilderInfo.DONT_SIGN);
}
}
}
}
return null;
}
/**
* Invoke the ROM builder for the given build configuration
* @param config - The current configuration from where to get the settings from
* @param cmdLauncher - The object to use for the process execution
* @param monitor - An IProgressMonitor
*/
public static void invokeROMBuilder(ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor) {
IROMBuilderInfo info = config.getROMBuildInfo();
if (info != null) {
String commandLine = info.getCommandLine().trim();
if (commandLine.length() > 0) {
monitor.setTaskName("Building ROM Image");
IPath workingDir = config.getCarbideProject().getINFWorkingDirectory();
String workingDirString = info.getWorkingDirectory().trim();
if (workingDirString.length() > 0) {
workingDir = new Path(workingDirString);
}
cmdLauncher.writeToConsole("\n***Building ROM Image ....\n");
List<String> args = tokenizeArgsWithQuotes(commandLine);
args.add(0, "/c");
cmdLauncher.setErrorParserManager(workingDir, getParserIdArray(ICarbideBuildConfiguration.ERROR_PARSERS_ROM_BUILDER));
int retVal = cmdLauncher.executeCommand(CarbideCommandLauncher.getCmdExeLocation(), args.toArray(new String[args.size()]), getResolvedEnvVars(config), workingDir);
if (retVal != 0){
cmdLauncher.writeToConsole("***Non-Zero Status: Specified rom build command returned with exit value = " + retVal); //$NON-NLS-1$
CarbideBuilderPlugin.createCarbideProjectMarker(config.getCarbideProject().getProject(), IMarker.SEVERITY_ERROR, "Specified rom build command returned with exit value = " + retVal, IMarker.PRIORITY_LOW); //$NON-NLS-1$
cmdLauncher.writeToConsole("\nRom build failed\n");
} else {
cmdLauncher.writeToConsole("\nRom build completed\n"); //$NON-NLS-1$
}
cmdLauncher.writeToConsole(cmdLauncher.getTimingStats());
monitor.worked(1);
if (monitor.isCanceled()) {
return;
}
}
}
monitor.done();
}
/**
* Returns a list of arguments as strings. The given string is basically split at spaces, but not if the space(s)
* is contained in quotes. Arguments are typically quoted if they contain spaces.
* @param line
* @return
*/
private static List<String> tokenizeArgsWithQuotes(String line) {
List<String> allTokens = new ArrayList<String>();
int tokenStart = 0;
boolean inQuotes = false;
for (int index = 0; index < line.length() - 1; index++) {
char c = line.charAt(index);
if (c == '"') {
inQuotes = !inQuotes;
} else if (c == ' ' && !inQuotes) {
allTokens.add(line.substring(tokenStart, index).replace("\"", ""));
tokenStart = index + 1;
}
}
// add the last token
allTokens.add(line.substring(tokenStart, line.length()));
return allTokens;
}
/**
* This method performs a build for a given Carbide build configuration.
* @param config - The Carbide configuration to build
* @param monitor - A progress monitor so user can cancel build (can be null)
* @param console - Where to pipe the output. If null, a new CConole will be created and existing console cleared.
* @param buildKind - FULL_BUILD, else incremental build assumed.
*
* @deprecated use {@link #invokeBuild(ICarbideBuildConfiguration, IConsole, IProgressMonitor)} instead
*/
public static void callAbldBuildForConfiguration(ICarbideBuildConfiguration config, IProgressMonitor monitor, IConsole console, int buildKind, boolean clearMarkers){
if (monitor == null) {
monitor = new NullProgressMonitor();
}
if (console == null){
console = CCorePlugin.getDefault().getConsole();
}
CarbideCommandLauncher launcher = new CarbideCommandLauncher(config.getCarbideProject().getProject(), monitor, console, getParserIdArray(config.getErrorParserId()), config.getCarbideProject().getINFWorkingDirectory());
launcher.showCommand(true);
invokeBuild(config, launcher, monitor, clearMarkers);
}
/**
* Invoke bldmake bldfiles on the current bld.inf and SDK.
* @param config - Config to generate makefiles for.
* @param cmdLauncher - The process launcher
* @param monitor - The progress monitor
* @param console - The console to write the messages to.
* @param env - The array of environment variables to be used for the process
* @param workingDir - The full path to the bld.inf file to be used as the current working directory
*
* @deprecated use {@link #generateBldmakeMakefilesIfNecessary(ICarbideBuildConfiguration, CarbideCommandLauncher, IConsole, IProgressMonitor, boolean)} instead
*/
public static boolean invokeBldmakeBldFiles(ICarbideBuildConfiguration config, CarbideCommandLauncher cmdLauncher, IProgressMonitor monitor, IConsole console, String[] env, IPath workingDir ){
return generateBldmakeMakefilesIfNecessary(config, cmdLauncher);
}
/**
* Check to see if abld.bat and the SDK's platform makefile exists. If either don't exist, re-generate makefiles
* This also tests to make sure the makefile target is OLDER than the bld.inf file.
* @param bldInfDir - The working dir of the bld.inf file (should not contain 'bld.inf')
* @param defaultConfig - The ISymbianBuildConfiguration to be built.
* @return true if makefiles need to be regenerated
*
* @deprecated use {@link #needsBldmakeMakefileGeneration(ICarbideBuildConfiguration)}
*/
public static boolean projectNeedsMakefileGeneration(IPath bldInfDir, ICarbideBuildConfiguration defaultConfig){
return needsBldmakeMakefileGeneration(defaultConfig);
}
/**
* Checks the Problems view for any error markers.
* @param project - IProject to check for problem markers
* @return true if at least one error marker exists on the project
*/
public static boolean projectHasBuildErrors(IProject project){
try {
IMarker [] errorMarkers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
for (IMarker currMarker : errorMarkers){
if (currMarker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR) == IMarker.SEVERITY_ERROR){
if (currMarker.isSubtypeOf(CarbideBuilderPlugin.CARBIDE_PROJECT_MARKER) ||
currMarker.isSubtypeOf(ICModelMarker.C_MODEL_PROBLEM_MARKER)) {
return true;
}
}
}
} catch (CoreException e){
e.printStackTrace();
}
return false;
}
public static IPath getBuilderMakefileDir(ICarbideBuildConfiguration config){
return getBuilder(config.getCarbideProject().getProject()).getMakefileDirectory(config);
}
}