blob: 90e954d622764914b57947316538a9344f49be8a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Pascal Rapicault - Support for bundled macosx http://bugs.eclipse.org/57349
*******************************************************************************/
package org.eclipse.equinox.internal.p2.touchpoint.eclipse;
import java.io.File;
import java.net.*;
import java.util.List;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.frameworkadmin.BundleInfo;
import org.eclipse.equinox.internal.p2.update.*;
import org.eclipse.equinox.internal.provisional.frameworkadmin.LauncherData;
import org.eclipse.equinox.internal.provisional.frameworkadmin.Manipulator;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.osgi.service.environment.Constants;
import org.eclipse.osgi.util.NLS;
/**
* This class provides a wrapper for reading and writing platform.xml.
*
* Only a minimal set of operations is exposed.
*/
public class PlatformConfigurationWrapper {
private Configuration configuration = null;
private Site poolSite = null;
private File configFile;
private URI poolURI;
private Manipulator manipulator;
private static String FEATURES = "features/"; //$NON-NLS-1$
/*
* Use the given manipulator to calculate the OSGi install location. We can't
* just use the Location service here because we may not be installing into
* ourselves. (see https://bugs.eclipse.org/354552)
*
* First try and calculate the location based relative to the data provided in
* the manipulator's launcher data. If that doesn't work then calculate it based
* on the location of known JARs. If that still doesn't work then return null.
*/
private static URL getOSGiInstallArea(Manipulator manipulator) {
// first see if the launcher home is set
LauncherData launcherData = manipulator.getLauncherData();
File home = launcherData.getHome();
if (home != null) {
try {
return home.toURI().toURL();
} catch (MalformedURLException e) {
// ignore - shouldn't happen
}
}
// next try and calculate the value based on the location of the framework
// (OSGi) jar.
File fwkJar = launcherData.getFwJar();
if (fwkJar != null) {
try {
return fromOSGiJarToOSGiInstallArea(fwkJar.getAbsolutePath()).toURI().toURL();
} catch (MalformedURLException e) {
// ignore - shouldn't happen
}
}
// finally calculate the value based on the location of the launcher executable
// itself
File launcherFile = launcherData.getLauncher();
if (launcherFile != null) {
if (Constants.OS_MACOSX.equals(launcherData.getOS())) {
// the equinox launcher will look 3 levels up on the mac when going from
// executable to launcher.jar
// see org.eclipse.equinox.executable/library/eclipse.c : findStartupJar();
IPath launcherPath = new Path(launcherFile.getAbsolutePath());
if (launcherPath.segmentCount() > 2) {
// removing "Eclipse.app/Contents/MacOS/eclipse"
launcherPath = launcherPath.removeLastSegments(2);
try {
return launcherPath.toFile().toURI().toURL();
} catch (MalformedURLException e) {
// ignore - shouldn't happen
}
}
}
try {
return launcherFile.getParentFile().toURI().toURL();
} catch (MalformedURLException e) {
// ignore - shouldn't happen
}
}
// we couldn't calculate it based on the info in the launcher data, so
// try to do it based on the location of known JARs.
final String OSGI = "org.eclipse.osgi"; //$NON-NLS-1$
BundleInfo[] bis = manipulator.getConfigData().getBundles();
String searchFor = "org.eclipse.equinox.launcher"; //$NON-NLS-1$
for (int i = 0; i < bis.length; i++) {
if (bis[i].getSymbolicName().equals(searchFor)) {
if (bis[i].getLocation() != null) {
try {
if (bis[i].getLocation().getScheme().equals("file")) //$NON-NLS-1$
return fromOSGiJarToOSGiInstallArea(bis[i].getLocation().getPath()).toURI().toURL();
} catch (MalformedURLException e) {
// do nothing
}
}
if (searchFor.equals(OSGI))
return null;
searchFor = OSGI;
i = -1;
}
}
return null;
}
private static File fromOSGiJarToOSGiInstallArea(String path) {
IPath parentFolder = new Path(path).removeLastSegments(1);
if (parentFolder.lastSegment().equals("plugins")) //$NON-NLS-1$
return parentFolder.removeLastSegments(1).toFile();
return parentFolder.toFile();
}
public PlatformConfigurationWrapper(File configDir, URI featurePool, Manipulator manipulator) {
this.configuration = null;
this.configFile = new File(configDir, "/org.eclipse.update/platform.xml"); //$NON-NLS-1$
this.poolURI = featurePool;
this.manipulator = manipulator;
}
private void loadDelegate() {
if (configuration != null)
return;
try {
if (configFile.exists()) {
configuration = Configuration.load(configFile, getOSGiInstallArea(manipulator));
} else {
configuration = new Configuration();
}
} catch (ProvisionException pe) {
// TODO: Make this a real message
throw new IllegalStateException(Messages.error_parsing_configuration);
}
if (poolURI == null)
throw new IllegalStateException("Error creating platform configuration. No bundle pool defined."); //$NON-NLS-1$
poolSite = getSite(poolURI);
if (poolSite == null) {
poolSite = createSite(poolURI, getDefaultPolicy());
configuration.add(poolSite);
}
}
/*
* Return the default policy to use when creating a new site. If there are any
* sites with the MANAGED-ONLY policy, then that is the default. Otherwise the
* default is USER-EXCLUDE.
*/
private String getDefaultPolicy() {
for (Site site : configuration.getSites()) {
if (Site.POLICY_MANAGED_ONLY.equals(site.getPolicy()))
return Site.POLICY_MANAGED_ONLY;
}
return Site.POLICY_USER_EXCLUDE;
}
/*
* Create and return a site object based on the given location.
*/
private static Site createSite(URI location, String policy) {
Site result = new Site();
result.setUrl(location.toString());
result.setPolicy(policy);
result.setEnabled(true);
return result;
}
/*
* Look in the configuration and return the site object whose location matches
* the given URL. Return null if there is no match.
*/
private Site getSite(URI url) {
List<Site> sites = configuration.getSites();
File file = URIUtil.toFile(url);
for (Site nextSite : sites) {
try {
File nextFile = URIUtil.toFile(new URI(nextSite.getUrl()));
if (nextFile == null)
continue;
if (nextFile.equals(file))
return nextSite;
} catch (URISyntaxException e) {
// ignore incorrectly formed site
}
}
return null;
}
/*
* Look in the configuration and return the site which contains the feature with
* the given identifier and version. Return null if there is none.
*/
private Site getSite(String id, String version) {
List<Site> sites = configuration.getSites();
for (Site site : sites) {
Feature[] features = site.getFeatures();
for (int i = 0; i < features.length; i++) {
if (id.equals(features[i].getId()) && version.equals(features[i].getVersion()))
return site;
}
}
return null;
}
public IStatus addFeatureEntry(File file, String id, String version, String pluginIdentifier, String pluginVersion,
boolean primary, String application, URL[] root, String linkFile) {
loadDelegate();
if (configuration == null)
return new Status(IStatus.WARNING, Activator.ID, Messages.platform_config_unavailable, null);
URI fileURL = null;
File featureDir = file.getParentFile();
if (featureDir == null || !featureDir.getName().equals("features")) //$NON-NLS-1$
return new Status(IStatus.ERROR, Activator.ID,
NLS.bind(Messages.parent_dir_features, file.getAbsolutePath()), null);
File locationDir = featureDir.getParentFile();
if (locationDir == null)
return new Status(IStatus.ERROR, Activator.ID,
NLS.bind(Messages.cannot_calculate_extension_location, file.getAbsolutePath()), null);
fileURL = locationDir.toURI();
Site site = getSite(fileURL);
if (site == null) {
site = createSite(fileURL, getDefaultPolicy());
if (linkFile != null)
site.setLinkFile(linkFile);
configuration.add(site);
} else {
// check to see if the feature already exists in this site
if (site.getFeature(id, version) != null)
return Status.OK_STATUS;
}
Feature addedFeature = new Feature(site);
addedFeature.setId(id);
addedFeature.setVersion(version);
addedFeature.setUrl(makeFeatureURL(id, version));
addedFeature.setApplication(application);
addedFeature.setPluginIdentifier(pluginIdentifier);
addedFeature.setPluginVersion(pluginVersion);
addedFeature.setRoots(root);
addedFeature.setPrimary(primary);
site.addFeature(addedFeature);
return Status.OK_STATUS;
}
public IStatus removeFeatureEntry(String id, String version) {
loadDelegate();
if (configuration == null)
return new Status(IStatus.WARNING, Activator.ID, Messages.platform_config_unavailable, null);
Site site = getSite(id, version);
if (site == null)
site = poolSite;
site.removeFeature(makeFeatureURL(id, version));
// if we weren't able to remove the feature from the site because it
// didn't exist, then someone already did our job for us and it is ok.
return Status.OK_STATUS;
}
public boolean containsFeature(URI siteURI, String featureId, String featureVersion) {
loadDelegate();
if (configuration == null)
return false;
Site site = getSite(siteURI);
if (site == null)
return false;
return site.getFeature(featureId, featureVersion) != null;
}
public void save() throws ProvisionException {
if (configuration != null) {
configFile.getParentFile().mkdirs();
configuration.save(configFile, getOSGiInstallArea(manipulator));
}
}
private static String makeFeatureURL(String id, String version) {
return FEATURES + id + "_" + version + "/"; //$NON-NLS-1$ //$NON-NLS-2$ ;
}
}