blob: a7ab8b0a6b358168b7210f289ebb4323919075b1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 477527
* Martin Karpisek <martin.karpisek@gmail.com> - Bug 438509
*******************************************************************************/
package org.eclipse.pde.internal.core.exports;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.plugin.*;
import org.eclipse.pde.internal.build.*;
import org.eclipse.pde.internal.core.*;
import org.eclipse.pde.internal.core.ifeature.IFeature;
import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
import org.eclipse.pde.internal.core.iproduct.IJREInfo;
import org.eclipse.pde.internal.core.iproduct.ILauncherInfo;
import org.eclipse.pde.internal.core.iproduct.IProduct;
import org.eclipse.pde.internal.core.util.CoreUtility;
import org.w3c.dom.Element;
public class ProductExportOperation extends FeatureExportOperation {
private static final String STATUS_MESSAGE = "!MESSAGE"; //$NON-NLS-1$
private static final String STATUS_ENTRY = "!ENTRY"; //$NON-NLS-1$
private static final String STATUS_SUBENTRY = "!SUBENTRY"; //$NON-NLS-1$
private static final String ECLIPSE_APP_MACOS = "Eclipse.app/Contents/MacOS"; //$NON-NLS-1$
private static final String ECLIPSE_APP_CONTENTS = "Eclipse.app/Contents"; //$NON-NLS-1$
private static final String MAC_JAVA_FRAMEWORK = "/System/Library/Frameworks/JavaVM.framework"; //$NON-NLS-1$
private String fFeatureLocation;
private String fRoot;
private IProduct fProduct;
protected static String errorMessage;
public static void setErrorMessage(String message) {
errorMessage = message;
}
public static String getErrorMessage() {
return errorMessage;
}
public static IStatus parseErrorMessage(CoreException e) {
if (errorMessage == null)
return null;
MultiStatus status = null;
StringTokenizer tokenizer = new StringTokenizer(errorMessage, "\n"); //$NON-NLS-1$
for (; tokenizer.hasMoreTokens();) {
String line = tokenizer.nextToken().trim();
if (line.startsWith(STATUS_ENTRY) && tokenizer.hasMoreElements()) {
String next = tokenizer.nextToken();
if (next.startsWith(STATUS_MESSAGE)) {
status = new MultiStatus(PDECore.PLUGIN_ID, 0, next.substring(8), null);
}
} else if (line.startsWith(STATUS_SUBENTRY) && tokenizer.hasMoreElements() && status != null) {
String next = tokenizer.nextToken();
if (next.startsWith(STATUS_MESSAGE)) {
status.add(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, next.substring(8)));
}
}
}
if (status != null)
return status;
//parsing didn't work, just set the message
return new MultiStatus(PDECore.PLUGIN_ID, 0, new IStatus[] {e.getStatus()}, errorMessage, null);
}
public ProductExportOperation(FeatureExportInfo info, String name, IProduct product, String root) {
super(info, name);
fProduct = product;
fRoot = root;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
String[][] configurations = fInfo.targets;
if (configurations == null)
configurations = new String[][] {{TargetPlatform.getOS(), TargetPlatform.getWS(), TargetPlatform.getOSArch(), TargetPlatform.getNL()}};
cleanupBuildRepo();
errorMessage = null;
SubMonitor subMonitor = SubMonitor.convert(monitor, 9);
try {
// create a feature to wrap all plug-ins and features
String featureID = "org.eclipse.pde.container.feature"; //$NON-NLS-1$
fFeatureLocation = fBuildTempLocation + File.separator + featureID;
createFeature(featureID, fFeatureLocation, configurations, fProduct.includeLaunchers());
createBuildPropertiesFile(fFeatureLocation, configurations);
doExport(featureID, null, fFeatureLocation, configurations, subMonitor.split(8));
} catch (IOException e) {
PDECore.log(e);
} catch (InvocationTargetException e) {
return new Status(IStatus.ERROR, PDECore.PLUGIN_ID, PDECoreMessages.FeatureBasedExportOperation_ProblemDuringExport, e.getTargetException());
} catch (CoreException e) {
if (errorMessage != null)
return parseErrorMessage(e);
return e.getStatus();
} finally {
// Clean up generated files
for (int j = 0; j < fInfo.items.length; j++) {
try {
deleteBuildFiles(fInfo.items[j]);
} catch (CoreException e) {
PDECore.log(e);
}
}
cleanup(subMonitor.split(1));
}
if (hasAntErrors()) {
return new Status(IStatus.WARNING, PDECore.PLUGIN_ID, NLS.bind(PDECoreMessages.FeatureExportOperation_CompilationErrors, fInfo.destinationDirectory));
}
errorMessage = null;
return Status.OK_STATUS;
}
@Override
protected boolean groupedConfigurations() {
// we never group product exports
return false;
}
private void cleanupBuildRepo() {
File metadataTemp = new File(fBuildTempMetadataLocation);
if (metadataTemp.exists()) {
//make sure our build metadata repo is clean
deleteDir(metadataTemp);
}
}
@Override
protected String[] getPaths() {
String[] paths = super.getPaths();
String[] all = new String[paths.length + 1];
all[0] = fFeatureLocation + File.separator + ICoreConstants.FEATURE_FILENAME_DESCRIPTOR;
System.arraycopy(paths, 0, all, 1, paths.length);
return all;
}
private void createBuildPropertiesFile(String featureLocation, String[][] configurations) {
File file = new File(featureLocation);
if (!file.exists() || !file.isDirectory())
file.mkdirs();
boolean hasLaunchers = PDECore.getDefault().getFeatureModelManager().getDeltaPackFeature() != null;
Properties properties = new Properties();
if (fProduct.includeLaunchers() && !hasLaunchers && configurations.length > 0) {
String rootPrefix = IBuildPropertiesConstants.ROOT_PREFIX + configurations[0][0] + "." + configurations[0][1] + "." + configurations[0][2]; //$NON-NLS-1$ //$NON-NLS-2$
properties.put(rootPrefix, getRootFileLocations(hasLaunchers));
if (TargetPlatform.getOS().equals("macosx")) { //$NON-NLS-1$
String plist = createMacInfoPList();
if (plist != null)
properties.put(rootPrefix + ".folder." + ECLIPSE_APP_CONTENTS, "absolute:file:" + plist); //$NON-NLS-1$ //$NON-NLS-2$
properties.put(rootPrefix + ".folder." + ECLIPSE_APP_MACOS, getLauncherLocations(hasLaunchers)); //$NON-NLS-1$
properties.put(rootPrefix + ".permissions.755", "Contents/MacOS/" + getLauncherName()); //$NON-NLS-1$ //$NON-NLS-2$
} else {
properties.put(rootPrefix, getLauncherLocations(hasLaunchers)); //To copy a folder
properties.put(rootPrefix + ".permissions.755", getLauncherName()); //$NON-NLS-1$
if (TargetPlatform.getWS().equals("motif") && TargetPlatform.getOS().equals("linux")) { //$NON-NLS-1$ //$NON-NLS-2$
properties.put(rootPrefix + ".permissions.755", "libXm.so.2"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
IJREInfo jreInfo = fProduct.getJREInfo();
if (jreInfo != null) {
for (int i = 0; i < configurations.length; i++) {
String[] config = configurations[i];
// Only include the JRE if product config says to do so
if (!jreInfo.includeJREWithProduct(config[0])) {
continue;
}
File vm = jreInfo.getJVMLocation(config[0]);
if (vm != null) {
if (config[0].equals("macosx") && vm.getPath().startsWith(MAC_JAVA_FRAMEWORK)) { //$NON-NLS-1$
continue;
}
String rootPrefix = IBuildPropertiesConstants.ROOT_PREFIX + config[0] + "." + config[1] + //$NON-NLS-1$
"." + config[2]; //$NON-NLS-1$
properties.put(rootPrefix + ".folder.jre", "absolute:" + vm.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$
String perms = (String) properties.get(rootPrefix + ".permissions.755"); //$NON-NLS-1$
if (perms != null) {
StringBuffer buffer = new StringBuffer(perms);
buffer.append(","); //$NON-NLS-1$
buffer.append("jre/bin/java"); //$NON-NLS-1$
properties.put(rootPrefix + ".permissions.755", buffer.toString()); //$NON-NLS-1$
}
}
}
}
if (fInfo.exportSource && fInfo.exportSourceBundle) {
properties.put(IBuildPropertiesConstants.PROPERTY_INDIVIDUAL_SOURCE, "true"); //$NON-NLS-1$
List<IPluginModelBase> workspacePlugins = Arrays.asList(PluginRegistry.getWorkspaceModels());
for (int i = 0; i < fInfo.items.length; i++) {
if (fInfo.items[i] instanceof IFeatureModel) {
IFeature feature = ((IFeatureModel) fInfo.items[i]).getFeature();
properties.put("generate.feature@" + feature.getId().trim() + ".source", feature.getId()); //$NON-NLS-1$ //$NON-NLS-2$
} else {
BundleDescription bundle = null;
if (fInfo.items[i] instanceof IPluginModelBase) {
bundle = ((IPluginModelBase) fInfo.items[i]).getBundleDescription();
}
if (bundle == null) {
if (fInfo.items[i] instanceof BundleDescription)
bundle = (BundleDescription) fInfo.items[i];
}
if (bundle == null)
continue;
//it doesn't matter if we generate extra properties for platforms we aren't exporting for
if (workspacePlugins.contains(PluginRegistry.findModel(bundle))) {
properties.put("generate.plugin@" + bundle.getSymbolicName().trim() + ".source", bundle.getSymbolicName()); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
}
save(new File(file, ICoreConstants.BUILD_FILENAME_DESCRIPTOR), properties, "Build Configuration"); //$NON-NLS-1$
}
@Override
protected boolean publishingP2Metadata() {
return fInfo.exportMetadata;
}
private String getLauncherLocations(boolean hasLaunchers) {
//get the launchers for the eclipse install
StringBuffer buffer = new StringBuffer();
if (!hasLaunchers) {
File homeDir = new File(TargetPlatform.getLocation());
if (homeDir.exists() && homeDir.isDirectory()) {
// try to retrieve the exact eclipse launcher path
// see bug 205833
File file = null;
if (System.getProperties().get("eclipse.launcher") != null) { //$NON-NLS-1$
String launcherPath = System.getProperties().get("eclipse.launcher").toString(); //$NON-NLS-1$
file = new File(launcherPath);
}
if (file != null && file.exists() && !file.isDirectory()) {
appendAbsolutePath(buffer, file);
} else if (TargetPlatform.getOS().equals("macosx")) { //$NON-NLS-1$)
appendEclipsePath(buffer, new File(homeDir, "../MacOS/")); //$NON-NLS-1$
} else {
appendEclipsePath(buffer, homeDir);
}
}
}
return buffer.toString();
}
private String getRootFileLocations(boolean hasLaunchers) {
//Get the files that go in the root of the eclipse install, excluding the launcher
StringBuffer buffer = new StringBuffer();
if (!hasLaunchers) {
File homeDir = new File(TargetPlatform.getLocation());
if (homeDir.exists() && homeDir.isDirectory()) {
File file = new File(homeDir, "startup.jar"); //$NON-NLS-1$
if (file.exists())
appendAbsolutePath(buffer, file);
file = new File(homeDir, "libXm.so.2"); //$NON-NLS-1$
if (file.exists()) {
appendAbsolutePath(buffer, file);
}
}
}
return buffer.toString();
}
private void appendEclipsePath(StringBuffer buffer, File homeDir) {
File file = null;
file = new File(homeDir, "eclipse"); //$NON-NLS-1$
if (file.exists()) {
appendAbsolutePath(buffer, file);
}
file = new File(homeDir, "eclipse.exe"); //$NON-NLS-1$
if (file.exists()) {
appendAbsolutePath(buffer, file);
}
}
private void appendAbsolutePath(StringBuffer buffer, File file) {
if (buffer.length() > 0)
buffer.append(","); //$NON-NLS-1$
buffer.append("absolute:file:"); //$NON-NLS-1$
buffer.append(file.getAbsolutePath());
}
@Override
protected HashMap<String, String> createAntBuildProperties(String[][] configs) {
HashMap<String, String> properties = super.createAntBuildProperties(configs);
properties.put(IXMLConstants.PROPERTY_LAUNCHER_NAME, getLauncherName());
ILauncherInfo info = fProduct.getLauncherInfo();
if (info != null) {
String icons = ""; //$NON-NLS-1$
for (int i = 0; i < configs.length; i++) {
String images = null;
if (configs[i][0].equals("win32")) { //$NON-NLS-1$
images = getWin32Images(info);
} else if (configs[i][0].equals("linux")) { //$NON-NLS-1$
images = getExpandedPath(info.getIconPath(ILauncherInfo.LINUX_ICON));
} else if (configs[i][0].equals("macosx")) { //$NON-NLS-1$
images = getExpandedPath(info.getIconPath(ILauncherInfo.MACOSX_ICON));
}
if (images != null) {
if (icons.length() > 0)
icons += ","; //$NON-NLS-1$
icons += images;
}
}
if (icons.length() > 0)
properties.put(IXMLConstants.PROPERTY_LAUNCHER_ICONS, icons);
}
fAntBuildProperties.put(IXMLConstants.PROPERTY_COLLECTING_FOLDER, fRoot);
fAntBuildProperties.put(IXMLConstants.PROPERTY_ARCHIVE_PREFIX, fRoot);
return properties;
}
@Override
protected void setP2MetaDataProperties(Map<String, String> map) {
if (fInfo.exportMetadata) {
if (PDECore.getDefault().getFeatureModelManager().getDeltaPackFeature() == null)
map.put(IXMLConstants.PROPERTY_LAUNCHER_PROVIDER, "org.eclipse.pde.container.feature"); //$NON-NLS-1$
map.put(IXMLConstants.TARGET_P2_METADATA, IBuildPropertiesConstants.TRUE);
map.put(IBuildPropertiesConstants.PROPERTY_P2_FLAVOR, P2Utils.P2_FLAVOR_DEFAULT);
map.put(IBuildPropertiesConstants.PROPERTY_P2_PUBLISH_ARTIFACTS, IBuildPropertiesConstants.TRUE);
map.put(IBuildPropertiesConstants.PROPERTY_P2_COMPRESS, IBuildPropertiesConstants.TRUE);
map.put(IBuildPropertiesConstants.PROPERTY_P2_GATHERING, Boolean.toString(publishingP2Metadata()));
try {
map.put(IBuildPropertiesConstants.PROPERTY_P2_BUILD_REPO, new File(fBuildTempMetadataLocation).toURL().toString());
map.put(IBuildPropertiesConstants.PROPERTY_P2_METADATA_REPO, new File(fInfo.destinationDirectory + "/repository").toURL().toString()); //$NON-NLS-1$
map.put(IBuildPropertiesConstants.PROPERTY_P2_ARTIFACT_REPO, new File(fInfo.destinationDirectory + "/repository").toURL().toString()); //$NON-NLS-1$
map.put(IBuildPropertiesConstants.PROPERTY_P2_METADATA_REPO_NAME, NLS.bind(PDECoreMessages.ProductExportOperation_0, fProduct.getProductId()));
map.put(IBuildPropertiesConstants.PROPERTY_P2_ARTIFACT_REPO_NAME, NLS.bind(PDECoreMessages.ProductExportOperation_0, fProduct.getProductId()));
} catch (MalformedURLException e) {
PDECore.log(e);
}
}
}
private String getLauncherName() {
ILauncherInfo info = fProduct.getLauncherInfo();
if (info != null) {
String name = info.getLauncherName();
if (name != null && name.length() > 0) {
name = name.trim();
if (name.endsWith(".exe")) //$NON-NLS-1$
name = name.substring(0, name.length() - 4);
return name;
}
}
return "eclipse"; //$NON-NLS-1$
}
private String getWin32Images(ILauncherInfo info) {
StringBuffer buffer = new StringBuffer();
if (info.usesWinIcoFile()) {
append(buffer, info.getIconPath(ILauncherInfo.P_ICO_PATH));
} else {
append(buffer, info.getIconPath(ILauncherInfo.WIN32_16_LOW));
append(buffer, info.getIconPath(ILauncherInfo.WIN32_16_HIGH));
append(buffer, info.getIconPath(ILauncherInfo.WIN32_32_HIGH));
append(buffer, info.getIconPath(ILauncherInfo.WIN32_32_LOW));
append(buffer, info.getIconPath(ILauncherInfo.WIN32_48_HIGH));
append(buffer, info.getIconPath(ILauncherInfo.WIN32_48_LOW));
append(buffer, info.getIconPath(ILauncherInfo.WIN32_256_HIGH));
}
return buffer.length() > 0 ? buffer.toString() : null;
}
private void append(StringBuffer buffer, String path) {
path = getExpandedPath(path);
if (path != null) {
if (buffer.length() > 0)
buffer.append(","); //$NON-NLS-1$
buffer.append(path);
}
}
private String getExpandedPath(String path) {
if (path == null || path.length() == 0)
return null;
IResource resource = PDECore.getWorkspace().getRoot().findMember(new Path(path));
if (resource != null) {
IPath fullPath = resource.getLocation();
return fullPath == null ? null : fullPath.toOSString();
}
return null;
}
@Override
protected void setupGenerator(BuildScriptGenerator generator, String featureID, String versionId, String[][] configs, String featureLocation) throws CoreException {
super.setupGenerator(generator, featureID, versionId, configs, featureLocation);
generator.setGenerateVersionsList(true);
if (fProduct != null)
generator.setProduct(fProduct.getModel().getInstallLocation());
}
private String createMacInfoPList() {
String entryName = TargetPlatformHelper.getTargetVersion() >= 3.3 ? "macosx/Info.plist" //$NON-NLS-1$
: "macosx/Info.plist.32"; //$NON-NLS-1$
URL url = PDECore.getDefault().getBundle().getEntry(entryName);
if (url == null)
return null;
File plist = null;
InputStream in = null;
String location = fFeatureLocation;
try {
in = url.openStream();
File dir = new File(location, ECLIPSE_APP_CONTENTS);
dir.mkdirs();
plist = new File(dir, "Info.plist"); //$NON-NLS-1$
CoreUtility.readFile(in, plist);
return plist.getAbsolutePath();
} catch (IOException e) {
// nothing to do
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
}
}
return null;
}
@Override
protected void setAdditionalAttributes(Element plugin, BundleDescription bundle) {
plugin.setAttribute("unpack", Boolean.toString(CoreUtility.guessUnpack(bundle))); //$NON-NLS-1$
}
}