| /******************************************************************************* |
| * Copyright (c) 2010, 2021 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 |
| *******************************************************************************/ |
| package org.eclipse.equinox.p2.tests.reconciler.dropins; |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.URIUtil; |
| import org.eclipse.equinox.frameworkadmin.BundleInfo; |
| import org.eclipse.equinox.internal.p2.update.Configuration; |
| import org.eclipse.equinox.internal.p2.update.Site; |
| import org.eclipse.equinox.p2.core.ProvisionException; |
| |
| public class AbstractSharedBundleProductTest extends AbstractReconcilerTest { |
| |
| public static final String PLATFORM_BASE = "platform:/base/"; |
| protected static String sharedLocationURL = null; |
| |
| public AbstractSharedBundleProductTest(String name) { |
| super(name); |
| } |
| |
| public AbstractSharedBundleProductTest(String name, String location) { |
| super(name, location); |
| } |
| |
| private Map<String, BundleInfo> getBootstrapBundles() { |
| Map<String, BundleInfo> result = new HashMap<>(); |
| |
| // TODO deal with fragments |
| // list.add("org.eclipse.core.net.win32.x86"); |
| // list.add("org.eclipse.equinox.security.win32.x86"); |
| final String[] bootstrap = new String[] { // |
| "org.eclipse.core.contenttype", // |
| "org.eclipse.core.expressions", // |
| "org.eclipse.core.jobs", // |
| "org.eclipse.core.net", // |
| "org.eclipse.core.runtime", // |
| "org.eclipse.core.runtime.compatibility.registry", // |
| "org.eclipse.ecf", // |
| "org.eclipse.ecf.filetransfer", // |
| "org.eclipse.ecf.identity", // |
| "org.eclipse.ecf.provider.filetransfer", // |
| "org.eclipse.ecf.provider.filetransfer.ssl", // |
| "org.eclipse.ecf.ssl", // |
| "org.eclipse.equinox.app", // |
| "org.eclipse.equinox.common", // |
| "org.apache.felix.scr", // |
| "org.eclipse.equinox.frameworkadmin", // |
| "org.eclipse.equinox.frameworkadmin.equinox", // |
| "org.eclipse.equinox.p2.artifact.repository", // |
| "org.eclipse.equinox.p2.core", // |
| "org.eclipse.equinox.p2.director", // |
| "org.eclipse.equinox.p2.directorywatcher", // |
| "org.eclipse.equinox.p2.engine", // |
| "org.eclipse.equinox.p2.extensionlocation", // |
| "org.eclipse.equinox.p2.garbagecollector", // |
| "org.eclipse.equinox.p2.jarprocessor", // |
| "org.eclipse.equinox.p2.metadata", // |
| "org.eclipse.equinox.p2.metadata.repository", // |
| "org.eclipse.equinox.p2.publisher", // |
| "org.eclipse.equinox.p2.ql", // |
| "org.eclipse.equinox.p2.reconciler.dropins", // |
| "org.eclipse.equinox.p2.repository", // |
| "org.eclipse.equinox.p2.touchpoint.eclipse", // |
| "org.eclipse.equinox.p2.touchpoint.natives", // |
| "org.eclipse.equinox.preferences", // |
| "org.eclipse.equinox.registry", // |
| "org.eclipse.equinox.security", // |
| "org.eclipse.equinox.simpleconfigurator", // |
| "org.eclipse.equinox.simpleconfigurator.manipulator", // |
| "org.eclipse.equinox.util", // |
| "org.eclipse.osgi", // |
| "org.eclipse.osgi.services", // |
| "org.sat4j.core", // |
| "org.sat4j.pb"}; |
| |
| // load the bundles.info and put the results into a map for easier lookup |
| BundleInfo[] infos = null; |
| try { |
| infos = loadBundlesInfo(getBundlesInfo()); |
| } catch (IOException e) { |
| fail("Exception occurred loading bundles.info file from: " + getBundlesInfo().getAbsolutePath(), e); |
| } |
| Map<String, BundleInfo> map = new HashMap<>(); |
| for (int i = 0; infos != null && i < infos.length; i++) { |
| map.put(infos[i].getSymbolicName(), infos[i]); |
| // always add the launcher bundles. do it here because we don't know what os/ws config we will have |
| if (infos[i].getSymbolicName().contains("equinox.launcher")) |
| result.put(infos[i].getSymbolicName(), infos[i]); |
| } |
| |
| // just add the bootstrap bundles into the result before returning |
| for (String bundle : bootstrap) { |
| BundleInfo info = map.get(bundle); |
| if (info != null) |
| result.put(info.getSymbolicName(), info); |
| } |
| return result; |
| } |
| |
| @Override |
| public void initialize() throws Exception { |
| |
| // extract the platform archive to the output folder |
| super.initialize(); |
| |
| // setup the shared bundle location |
| File shared = new File(output, "shared"); |
| shared.mkdirs(); |
| assertTrue("0.0", shared.isDirectory()); |
| |
| // move all features to the shared location |
| File features = new File(output, "eclipse/features"); |
| File sharedFeatureLocation = new File(shared, "features"); |
| move("1.0", features, sharedFeatureLocation); |
| |
| // move all bundles (except launchers) to the shared location |
| File bundles = new File(output, "eclipse/plugins"); |
| File sharedBundleLocation = new File(shared, "plugins"); |
| FileFilter filter = pathname -> !pathname.getName().contains("equinox.launcher"); |
| move("2.0", bundles, sharedBundleLocation, filter); |
| |
| // update the bundles.info file to contain only the boostrap bundles |
| // and also update their locations. |
| Map<String, BundleInfo> infos = getBootstrapBundles(); |
| updateBundlesInfo(infos, sharedBundleLocation); |
| |
| // update the platform.xml file to a user-include policy pointing |
| // to the bundles in the shared location. |
| updateConfiguration(infos, shared); |
| |
| // update the config.ini file to make sure the framework JAR |
| // is pointing to the right location |
| updateConfigIni(infos); |
| |
| // reconcile to ensure everything is ok |
| reconcile("5.0"); |
| } |
| |
| private void updateConfigIni(Map<String, BundleInfo> infos) { |
| File location = new File(output, "eclipse/configuration/config.ini"); |
| Properties ini = new Properties(); |
| try (InputStream input = new BufferedInputStream(new FileInputStream(location))) { |
| ini.load(input); |
| } catch (IOException e) { |
| fail("Exception while loading config.ini from: " + location.getAbsolutePath(), e); |
| } |
| BundleInfo framework = infos.get("org.eclipse.osgi"); |
| assertNotNull("Unable to find framework in list of bootstrap bundles.", framework); |
| ini.put("osgi.framework", framework.getLocation().toString()); |
| try (OutputStream out = new BufferedOutputStream(new FileOutputStream(location));) { |
| ini.store(out, null); |
| } catch (IOException e) { |
| fail("Exception while saving config.ini to: " + location.getAbsolutePath(), e); |
| } |
| } |
| |
| private void updateConfiguration(Map<String, BundleInfo> infos, File shared) { |
| Configuration config = new Configuration(); |
| config.setTransient(false); |
| config.setVersion("3.0"); |
| |
| // add site containing all the bootstrap bundles |
| Site site = new Site(); |
| try { |
| sharedLocationURL = shared.toURI().toURL().toExternalForm(); |
| site.setUrl(sharedLocationURL); |
| } catch (MalformedURLException e) { |
| fail("Exception occurred while converting site location to URL: " + shared.getAbsolutePath(), e); |
| } |
| site.setPolicy(Site.POLICY_USER_INCLUDE); |
| site.setUpdateable(false); |
| site.setEnabled(true); |
| URI sharedURI = shared.toURI(); |
| for (BundleInfo info : infos.values()) { |
| URI relative = URIUtil.makeRelative(info.getLocation(), sharedURI); |
| site.addPlugin(relative.toString()); |
| } |
| config.add(site); |
| |
| // add a site for platform:/base/ |
| site = new Site(); |
| site.setUrl(PLATFORM_BASE); |
| site.setPolicy(Site.POLICY_USER_EXCLUDE); |
| site.setUpdateable(true); |
| site.setEnabled(true); |
| config.add(site); |
| |
| // save the new config |
| saveConfiguration(config); |
| } |
| |
| public void removeBundlesFromConfiguration(Configuration config, String[] locations) { |
| for (String location : locations) |
| removeBundleFromConfiguration(config, location); |
| } |
| |
| protected Site getSharedSite(Configuration config) { |
| for (Site site : config.getSites()) { |
| if (sharedLocationURL != null && sharedLocationURL.equals(site.getUrl())) |
| return site; |
| } |
| return null; |
| } |
| |
| public boolean removeBundleFromConfiguration(Configuration config, String location) { |
| Site shared = getSharedSite(config); |
| assertNotNull("Unable to determine shared site from configuration.", shared); |
| boolean removed = shared.removePlugin(location); |
| if (removed) |
| return true; |
| // try again with a relative path |
| URI relative = null; |
| try { |
| relative = URIUtil.makeRelative(new URI(location), new URI(sharedLocationURL)); |
| } catch (URISyntaxException e) { |
| fail("Exception while converting location to URI.", e); |
| } |
| return shared.removePlugin(relative.toString()); |
| } |
| |
| public void addBundlesToConfigurations(Configuration config, String[] locations) { |
| for (String location : locations) |
| addBundleToConfiguration(config, location); |
| } |
| |
| public void addBundleToConfiguration(Configuration config, String location) { |
| Site shared = getSharedSite(config); |
| assertNotNull("Unable to determine shared site from configuration.", shared); |
| URI relative = null; |
| try { |
| relative = URIUtil.makeRelative(new URI(location), new URI(sharedLocationURL)); |
| } catch (URISyntaxException e) { |
| fail("Exception while converting location to URI.", e); |
| } |
| shared.addPlugin(relative.toString()); |
| } |
| |
| protected File getPlatformXMLLocation() { |
| return new File(output, "eclipse/configuration/org.eclipse.update/platform.xml"); |
| } |
| |
| public void saveConfiguration(Configuration config) { |
| File configLocation = getPlatformXMLLocation(); |
| try { |
| config.save(configLocation, null); |
| } catch (ProvisionException e) { |
| fail("Exception occurred while saving configuration: " + configLocation.getAbsolutePath(), e); |
| } |
| } |
| |
| public Configuration loadConfiguration() { |
| File configLocation = getPlatformXMLLocation(); |
| try { |
| return Configuration.load(configLocation, null); |
| } catch (ProvisionException e) { |
| fail("Exception loading configuration.", e); |
| } |
| // avoid compile error |
| return null; |
| } |
| |
| private void updateBundlesInfo(Map<String, BundleInfo> infos, File sharedBundleLocation) { |
| for (BundleInfo info : infos.values()) { |
| if (info.getSymbolicName().contains("equinox.launcher")) |
| continue; |
| File location = new File(sharedBundleLocation, new Path(info.getLocation().toString()).lastSegment()); |
| assertTrue("3.1." + location.getAbsolutePath(), location.exists()); |
| info.setLocation(location.toURI()); |
| } |
| // re-write the bundles.info file with the new information |
| try { |
| saveBundlesInfo(infos.values().toArray(new BundleInfo[infos.size()]), getBundlesInfo()); |
| } catch (IOException e) { |
| fail("Exception occurred while saving bundles.info to: " + getBundlesInfo().getAbsolutePath(), e); |
| } |
| } |
| |
| } |