diff options
author | Ed Merks | 2016-05-17 16:21:21 +0000 |
---|---|---|
committer | Ed Merks | 2016-05-17 16:21:21 +0000 |
commit | 2d874b3247457318ae4af3381eb5c8d4314cff12 (patch) | |
tree | de5e7f30e2745f48505efdc9c677b6ce1bbbf0e3 | |
parent | 595cd198ec6874f4babfbb30da59940c5dcb51a0 (diff) | |
download | org.eclipse.oomph-2d874b3247457318ae4af3381eb5c8d4314cff12.tar.gz org.eclipse.oomph-2d874b3247457318ae4af3381eb5c8d4314cff12.tar.xz org.eclipse.oomph-2d874b3247457318ae4af3381eb5c8d4314cff12.zip |
[485476] Eclipse OOpmh Installed Eclipse.App fails when moved
https://bugs.eclipse.org/bugs/show_bug.cgi?id=485476
11 files changed, 565 insertions, 138 deletions
diff --git a/plugins/org.eclipse.oomph.p2.core/META-INF/MANIFEST.MF b/plugins/org.eclipse.oomph.p2.core/META-INF/MANIFEST.MF index 2aa02fd0c..967dd8857 100644 --- a/plugins/org.eclipse.oomph.p2.core/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.oomph.p2.core/META-INF/MANIFEST.MF @@ -24,6 +24,7 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", org.eclipse.equinox.p2.director;bundle-version="[2.0.0,3.0.0)", org.eclipse.equinox.p2.operations;bundle-version="[2.0.0,3.0.0)", org.eclipse.equinox.p2.touchpoint.natives;bundle-version="[1.0.0,2.0.0)", + org.eclipse.equinox.p2.touchpoint.eclipse;bundle-version="[2.0.0,3.0.0)", org.eclipse.oomph.p2;bundle-version="[1.4.0,2.0.0)";visibility:=reexport Bundle-ActivationPolicy: lazy Service-Component: META-INF/lazyProfileRegistry.xml, META-INF/lazyProfileRegistry_bug390470.xml diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/core/Profile.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/core/Profile.java index 081d443bd..c59f904ba 100644 --- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/core/Profile.java +++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/core/Profile.java @@ -27,6 +27,8 @@ public interface Profile extends IProfile, AgentElement public static final String PROP_PROFILE_REFERENCER = "org.eclipse.oomph.p2.profile.referencer"; //$NON-NLS-1$ + public static final String PROP_PROFILE_SHARED_POOL = "org.eclipse.oomph.p2.profile.shared.pool"; //$NON-NLS-1$ + public static final String PROP_IU_COMPATIBILITY = "org.eclipse.oomph.p2.iu.compatibility"; //$NON-NLS-1$ public static final String TYPE_INSTALLATION = "Installation"; diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/AgentImpl.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/AgentImpl.java index 58f5500ee..2cb5674b2 100644 --- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/AgentImpl.java +++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/AgentImpl.java @@ -14,14 +14,26 @@ import org.eclipse.oomph.p2.P2Exception; import org.eclipse.oomph.p2.core.Agent; import org.eclipse.oomph.p2.core.AgentManager; import org.eclipse.oomph.p2.core.BundlePool; +import org.eclipse.oomph.p2.core.P2Util; import org.eclipse.oomph.p2.core.Profile; import org.eclipse.oomph.p2.core.ProfileCreator; +import org.eclipse.oomph.util.IOUtil; import org.eclipse.oomph.util.PropertiesUtil; import org.eclipse.oomph.util.StringUtil; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.URIConverter; + import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Platform; +import org.eclipse.equinox.internal.p2.engine.CommitOperationEvent; import org.eclipse.equinox.internal.p2.repository.Transport; +import org.eclipse.equinox.internal.p2.touchpoint.eclipse.EclipseTouchpoint; +import org.eclipse.equinox.internal.p2.touchpoint.eclipse.Util; +import org.eclipse.equinox.internal.p2.update.Configuration; +import org.eclipse.equinox.internal.p2.update.Site; +import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus; +import org.eclipse.equinox.internal.provisional.p2.core.eventbus.SynchronousProvisioningListener; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.IProvisioningAgentProvider; import org.eclipse.equinox.p2.core.ProvisionException; @@ -29,7 +41,10 @@ import org.eclipse.equinox.p2.core.spi.IAgentService; import org.eclipse.equinox.p2.engine.IEngine; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.engine.IProfileRegistry; +import org.eclipse.equinox.p2.metadata.IArtifactKey; +import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.planner.IPlanner; +import org.eclipse.equinox.p2.query.QueryUtil; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; @@ -40,10 +55,15 @@ import org.osgi.framework.ServiceReference; import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.EventObject; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @author Eike Stepper @@ -53,6 +73,9 @@ public class AgentImpl extends AgentManagerElementImpl implements Agent { public static final String ENGINE_PATH = "org.eclipse.equinox.p2.engine"; + private static final Pattern ECLIPSE_INI_SECTION_PATTERN = Pattern.compile("^(-vmargs)([\n\r]+.*)\\z|^(-[^\\n\\r]*[\\n\\r]*)((?:^[^-][^\\n\\r]*)*[\\n\\r]*)", + Pattern.MULTILINE | Pattern.DOTALL); + private final AgentManagerImpl agentManager; private final File location; @@ -93,6 +116,13 @@ public class AgentImpl extends AgentManagerElementImpl implements Agent } @Override + protected BundlePool loadElement(String key, String extraInfo) + { + // TODO + return super.loadElement(key, extraInfo); + } + + @Override protected void initializeFirstTime() { IProfileRegistry profileRegistry = getProfileRegistry(); @@ -129,6 +159,13 @@ public class AgentImpl extends AgentManagerElementImpl implements Agent } @Override + protected Profile loadElement(String key, String extraInfo) + { + // TODO + return super.loadElement(key, extraInfo); + } + + @Override protected void initializeFirstTime() { fillProfileMap(this); @@ -467,7 +504,60 @@ public class AgentImpl extends AgentManagerElementImpl implements Agent provisioningAgent.registerService(IArtifactRepositoryManager.SERVICE_NAME, artifactRepositoryManager); } + IProvisioningEventBus eventBus = (IProvisioningEventBus)provisioningAgent.getService(IProvisioningEventBus.SERVICE_NAME); + if (eventBus != null) + { + eventBus.addListener(new SynchronousProvisioningListener() + { + public void notify(EventObject event) + { + if (event instanceof CommitOperationEvent) + { + CommitOperationEvent commitOperationEvent = (CommitOperationEvent)event; + IProfile profile = commitOperationEvent.getProfile(); + if (Profile.TYPE_INSTALLATION.equals(profile.getProperty(Profile.PROP_PROFILE_TYPE))) + { + // If this is a commit of an Oomph-created installation profile, then adjust the installation details. + adjustInstallation(profile); + } + } + } + }); + } + this.provisioningAgent = provisioningAgent; + + Profile currentProfile = getCurrentProfile(); + if (currentProfile instanceof ProfileImpl) + { + File cachedInstallFolder = currentProfile.getInstallFolder(); + if (cachedInstallFolder != null) + { + String actualInstallFolderLocation = currentProfile.getProperty(IProfile.PROP_INSTALL_FOLDER); + if (actualInstallFolderLocation != null) + { + File actualInstallFolder = new File(actualInstallFolderLocation); + if (!actualInstallFolder.equals(cachedInstallFolder)) + { + ((ProfileImpl)currentProfile).setInstallFolder(actualInstallFolder); + + BundlePool bundlePool = currentProfile.getBundlePool(); + if (bundlePool instanceof BundlePoolImpl) + { + File bundlePoolLocation = bundlePool.getLocation(); + if (bundlePoolLocation.equals(cachedInstallFolder)) + { + ((BundlePoolImpl)bundlePool).setLocation(actualInstallFolder); + bundlePoolMap.remap(cachedInstallFolder.toString(), actualInstallFolderLocation); + } + } + + String profileID = currentProfile.getProfileId(); + profileMap.save(profileID, profileID); + } + } + } + } } } @@ -661,4 +751,384 @@ public class AgentImpl extends AgentManagerElementImpl implements Agent return provisioningAgent; } + + private void adjustInstallation(IProfile profile) + { + // This property should always be in a well-formed profile. + String bundlePoolLocation = profile.getProperty(IProfile.PROP_CACHE); + if (bundlePoolLocation != null) + { + // There should always be a bundle pool for this location. + BundlePool bundlePool = getBundlePool(new File(bundlePoolLocation)); + if (bundlePool != null) + { + // And there should always be an install folder in a well-formed profile. + // On the Mac, this should point at the Contents/Eclipse subfolder. + String installFolderLocation = profile.getProperty(IProfile.PROP_INSTALL_FOLDER); + if (installFolderLocation != null) + { + // The configuration folder should be nested in this install folder. + File installFolder = new File(installFolderLocation); + File configurationFolder = new File(installFolder, "configuration"); + + // If this is an installation based on a shared pool... + if ("true".equals(profile.getProperty(Profile.PROP_PROFILE_SHARED_POOL))) + { + try + { + adjustConfigIni(profile, bundlePool, configurationFolder); + } + catch (Exception ex) + { + // Ignore. + } + + try + { + adjustLauncherIni(profile, installFolder, true); + } + catch (Exception ex) + { + // Ignore. + } + + try + { + adjustBundlesInfo(configurationFolder); + } + catch (Exception ex) + { + // Ignore. + } + + try + { + adjustPlatformXML(bundlePoolLocation, configurationFolder); + } + catch (Exception ex) + { + // Ignore. + } + } + else + { + try + { + adjustLauncherIni(profile, installFolder, false); + } + catch (Exception ex) + { + // Ignore. + } + } + } + } + } + } + + private void adjustConfigIni(IProfile profile, BundlePool bundlePool, File configurationFolder) + { + // It should have a config.ini file to set various system properties. + // If it doesn't exist, it's not a well-formed installation so an exception will be thrown loading it and we'll exit this method as a result. + File configIniFile = new File(configurationFolder, "config.ini"); + Map<String, String> configProperties = PropertiesUtil.loadProperties(configIniFile); + + // The OSGi slash path might be specified using platform:/base/<bundle-id> + // but that doesn't work for a shared installation because the referenced bundle doesn't physically exist in the installation. + boolean changed = false; + String splashPath = configProperties.get("osgi.splashPath"); + if (splashPath != null) + { + // If there is a splash path with a URI of this form... + org.eclipse.emf.common.util.URI uri = org.eclipse.emf.common.util.URI.createURI(splashPath); + if ("platform".equals(uri.scheme()) && uri.segmentCount() >= 2 && "base".equals(uri.segment(0))) + { + // Determine which IU resolves for bundle-id... + LOOP: for (IInstallableUnit installableUnit : P2Util.asIterable(profile.query(QueryUtil.createIUQuery(uri.lastSegment()), null))) + { + // Look at all that IU's artifacts. + for (IArtifactKey artifactKey : installableUnit.getArtifacts()) + { + // If the file slash.bmp exists in that artifact jar or folder... + File artifactFile = bundlePool.getFileArtifactRepository().getArtifactFile(artifactKey); + if (artifactFile.isDirectory() ? new File(artifactFile, "splash.bmp").exists() + : URIConverter.INSTANCE.exists(URI.createURI("archive:" + URI.createFileURI(artifactFile.getAbsolutePath() + "!/splash.bmp")), null)) + { + // Replace the value with the absolute URI of the artifact in the shared bundle pool. + // The launcher and p2 have a bad habit of using URL.getPath which does not decode encoded character, e.g., %20 is not decode to the space + // character. + // So better we not produce an encoded URI. + configProperties.put("osgi.splashPath", createFileURI(artifactFile)); + changed = true; + break LOOP; + } + } + } + } + } + + // The OSGi framework property might be a relative path, e.g., file:../<path-to-shared-pool>. + String osgiFramework = configProperties.get("osgi.framework"); + if (osgiFramework != null) + { + // If file: is not followed by a '/', the URI won't be considered hierarchical even though it has file scheme. + URI uri = URI.createURI(osgiFramework); + if (uri.hasOpaquePart() && "file".equals(uri.scheme())) + { + // Resolve the relative path in the URI against the configuration folder's URI. + // If that file exists, as expected will be the case. + URI configurationFolderURI = URI.createFileURI(configurationFolder.toString()); + URI absoluteOSGiFrameworkLocation = URI.createURI(uri.opaquePart()).resolve(configurationFolderURI); + if (new File(absoluteOSGiFrameworkLocation.toFileString()).exists()) + { + // Replace the value with the absolute URI of the OSGi framework bundle. + // The launcher and p2 have a bad habit of using URL.getPath which does not decode encoded character, e.g., %20 is not decode to the space character. + // So better we not produce an encoded URI. + configProperties.put("osgi.framework", createFileURI(absoluteOSGiFrameworkLocation.toFileString())); + changed = true; + } + } + } + + // If there were changes made, save the configuration. + if (changed) + { + PropertiesUtil.saveProperties(configIniFile, configProperties, false, true, "This configuration file was written by: " + AgentImpl.class.getName()); + } + } + + private void adjustLauncherIni(IProfile profile, File installFolder, boolean sharedPool) + { + // We need to modify the eclipse.ini. + // For generality we'll check the launcher name property to compute the name of the launcher ini. + String launcherName = profile.getProperty(EclipseTouchpoint.PROFILE_PROP_LAUNCHER_NAME); + File iniFile = new File(installFolder, launcherName == null ? "eclipse.ini" : launcherName + ".ini"); + String contents = new String(IOUtil.readFile(iniFile)); + + // We will process all the sections, keeping them in a map from which we'll compute the modified contents. + Map<String, String> map = new LinkedHashMap<String, String>(); + for (Matcher matcher = ECLIPSE_INI_SECTION_PATTERN.matcher(contents); matcher.find();) + { + // Depending on which part of the pattern matched, we'll need to select the argument and extension from the constituent parts. + String argument = matcher.group(3); + String extension; + if (argument == null) + { + // If there is no third group, then the first part of the pattern matched, i.e., the -vmargs and the associated args. + argument = matcher.group(1); + extension = matcher.group(2); + } + else + { + // Otherwise the fourth group is the value part of the argument; it could be an empty string. + extension = matcher.group(4); + } + + // This will remove duplicates as well. + if (!argument.startsWith("--launcher.XXMaxPermSize") && !argument.startsWith("-startup") || !map.containsKey(argument)) + { + map.put(argument, extension); + } + } + + // If there are relative paths, that needs to be made absolute, this is used as the base URI against which to resolve them. + // We will build the new contents from the entries in the map. + // And will preserve the existing line feed convention if we need to add new lines. + URI baseURI = URI.createFileURI(installFolder.toString()).appendSegment(""); + StringBuilder newContents = new StringBuilder(); + String nl = null; + for (Map.Entry<String, String> entry : map.entrySet()) + { + // The keys will generally include the line feed character, so we trim that off when inspecting the key. + String key = entry.getKey(); + String trimmedKey = key.trim(); + String value = entry.getValue(); + if (sharedPool) + { + if ("-startup".equals(trimmedKey)) + { + // For the -startup value, check if it's a relative path. + if (value.startsWith("../")) + { + // Resolve it against the base URI and check that this file actually exists. + URI absoluteBundleLocation = URI.createURI(value.trim()).resolve(baseURI); + if (new File(absoluteBundleLocation.toFileString()).exists()) + { + // We'll copy this to the installation folder. + // We do this because the Equinox launcher org.eclipse.equinox.launcher.Main.getInstallLocation() + // computes the installation location from the location of this bundle. + // If we leave it as a relative path that references something outside the installation, + // the installation can't roam. + File localStartBundle = new File(new File(installFolder, "plugins"), absoluteBundleLocation.lastSegment()); + IOUtil.copyFile(new File(absoluteBundleLocation.toFileString()), localStartBundle); + + // Remember the line feed convention used for this section. + nl = key.substring(trimmedKey.length()); + + // The value is therefore the relative path to this copied target. + value = (Platform.OS_MACOSX.equals(Util.getOSFromProfile(profile)) ? "../Eclipse/plugins/" : "plugins/") + absoluteBundleLocation.lastSegment() + + nl; + } + } + } + else if ("--launcher.library".equals(trimmedKey)) + { + // If the launcher library, where the companion shared library is located, is a relative path. + if (value.startsWith("../")) + { + // Resolve it against against the base to determine the absolute location, checking that actually exists. + URI absoluteBundleLocation = URI.createURI(value.trim()).resolve(baseURI); + if (new File(absoluteBundleLocation.toFileString()).exists()) + { + // Replace the value with this absolute path, preserving the existing line feed convention. + nl = key.substring(trimmedKey.length()); + value = absoluteBundleLocation.toFileString() + nl; + } + } + } + else if ("-install".equals(trimmedKey)) + { + // Omit the install argument. + // This is generally an absolute path that effectively points at the folder in which the launcher ini is located. + // This breaks the ability for this installation to roam. + // Instead of this argument, we've copied the startup bundle into the installation, eliminating the need for this value. + continue; + } + } + + newContents.append(key); + newContents.append(value); + } + + if (!contents.contentEquals(newContents)) + { + IOUtil.writeFile(iniFile, newContents.toString().getBytes()); + } + } + + private void adjustBundlesInfo(File configurationFolder) + { + // For an installation with a shared bundle pool, this will be a relative path that navigates outside of the installation. + // In that case, we want to make those references be absolute. + File bundlesInfoFile = new File(configurationFolder, "org.eclipse.equinox.simpleconfigurator/bundles.info"); + + // Read all the lines as UTF-8 as documented in a comment in that file. + List<String> lines = IOUtil.readLines(bundlesInfoFile, "UTF-8"); + List<String> result = new ArrayList<String>(); + boolean changed = false; + URI configurationFolderURI = URI.createFileURI(configurationFolder.toString()); + + for (String line : lines) + { + // Ignore the comment lines. + if (!line.startsWith("#")) + { + // Lines of of this form: + // <bundle-id>,<version>,<location-URI>,<start-level>,<true|false> + // As such, we can split the lines on ',' and generally expect 5 elements in the list. + List<String> elements = StringUtil.explode(line, ","); + if (elements.size() > 2) + { + // If the third element that needs to be modified it it's a relative path. + String bundleReference = elements.get(2); + if (bundleReference.startsWith("../")) + { + // Resolve it against the location of the configuration folder, and if that bundle exists, as expected... + URI absoluteBundleLocation = URI.createURI(bundleReference).resolve(configurationFolderURI); + if (new File(absoluteBundleLocation.toFileString()).exists()) + { + // Replace the element, with that absolute URI, + // add that replacement to the result, + // and continue with the next line. + elements.set(2, createFileURI(absoluteBundleLocation.toFileString())); + result.add(StringUtil.implode(elements, ',', (char)0)); + changed = true; + continue; + } + } + } + } + + // Otherwise add the line as-is to the result. + result.add(line); + } + + // If there are any changes... + if (changed) + { + // Write the modified result back out to the bundles.info file. + IOUtil.writeLines(bundlesInfoFile, "UTF-8", result); + } + } + + private void adjustPlatformXML(String bundlePoolLocation, File configurationFolder) throws ProvisionException + { + // The platform.xml, initially will have the wrong site policy. + // Also, regular p2 updates will mangle the site URL to be an poorly-formed relative file URI, + // which again breaks the ability for the installation to roam. + File platformXML = new File(configurationFolder, "org.eclipse.update/platform.xml"); + if (platformXML.isFile()) + { + URI configurationFolderURI = URI.createFileURI(configurationFolder.toString()); + Configuration configuration = Configuration.load(platformXML, null); + boolean changed = true; + for (Site site : configuration.getSites()) + { + // If the site URI is of the form file:../<path> then we need to make it absolute. + URI siteURI = URI.createURI(site.getUrl()); + if (siteURI.hasOpaquePart() && "file".equals(siteURI.scheme())) + { + // Resolve it against the location of the configuration folder, checking if the folder really exists. + URI absoluteSiteURI = URI.createURI(siteURI.opaquePart()).resolve(configurationFolderURI); + if (new File(absoluteSiteURI.toFileString()).exists()) + { + // If so, we use this absolute URI instead and change the configuration to specify it. + siteURI = absoluteSiteURI; + site.setUrl(absoluteSiteURI.toFileString()); + changed = true; + } + } + + // If the policy isn't managed all the bundles in the pool will be visible, which is very bad. + if (!Site.POLICY_MANAGED_ONLY.equals(site.getPolicy())) + { + // If this site refers to the shared bundle pool, change the policy to be managed. + File siteLocation = new File(siteURI.toFileString()); + if (siteLocation.equals(new File(bundlePoolLocation))) + { + site.setPolicy(Site.POLICY_MANAGED_ONLY); + changed = true; + break; + } + } + } + + // If something has changed, save the configuration. + if (changed) + { + configuration.save(platformXML, null); + } + } + } + + private static String createFileURI(String path) + { + return createFileURI(new File(path)); + } + + private static String createFileURI(File file) + { + String path = file.getPath(); + if (File.separatorChar != '/') + { + path = path.replace(File.separatorChar, '/'); + } + + if (file.isAbsolute() && !path.startsWith(File.separator)) + { + return "file:/" + path; + } + + return "file:" + path; + } } diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/BundlePoolImpl.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/BundlePoolImpl.java index eeb1c4861..539e1968d 100644 --- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/BundlePoolImpl.java +++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/BundlePoolImpl.java @@ -34,17 +34,16 @@ public class BundlePoolImpl extends AgentManagerElementImpl implements BundlePoo { private final Agent agent; - private final File location; + private File location; - private final String path; + private String path; private IFileArtifactRepository fileArtifactRepository; public BundlePoolImpl(AgentImpl agent, File location) { this.agent = agent; - this.location = location; - path = location.getAbsolutePath(); + setLocation(location); } @Override @@ -68,6 +67,12 @@ public class BundlePoolImpl extends AgentManagerElementImpl implements BundlePoo return location; } + public void setLocation(File location) + { + this.location = location; + path = location.getAbsolutePath(); + } + public Set<String> getClients() { return ((AgentManagerImpl)agent.getAgentManager()).getClientsFor(path); diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/LazyProfile.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/LazyProfile.java index 3141b5c27..36641c27c 100644 --- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/LazyProfile.java +++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/LazyProfile.java @@ -14,6 +14,7 @@ import org.eclipse.oomph.p2.P2Exception; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.equinox.internal.p2.engine.ISurrogateProfileHandler; +import org.eclipse.equinox.internal.p2.engine.Profile; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.metadata.IInstallableUnit; @@ -152,7 +153,20 @@ public final class LazyProfile extends org.eclipse.equinox.internal.p2.engine.Pr @Override public void setProperty(String key, String value) { - getDelegate().setProperty(key, value); + Profile delegate = getDelegate(); + if (IProfile.PROP_CACHE.equals(key)) + { + // If we're setting the cache property, + // and this is a profile for an Oomph installation with a shared bundle pool for which the cache property has already been set, + // we don't want org.eclipse.equinox.internal.p2.engine.SimpleProfileRegistry.updateRoamingProfile(Profile) + // to change the cache location to point to the installation. + if ("true".equals(delegate.getProperty(org.eclipse.oomph.p2.core.Profile.PROP_PROFILE_SHARED_POOL)) && delegate.getProperty(IProfile.PROP_CACHE) != null) + { + return; + } + } + + delegate.setProperty(key, value); } @Override diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/PersistentMap.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/PersistentMap.java index b037e2cc6..e73a0cb08 100644 --- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/PersistentMap.java +++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/PersistentMap.java @@ -159,6 +159,18 @@ public abstract class PersistentMap<E> return element; } + public final synchronized E remap(String oldKey, String newKey) + { + E element = elements.remove(oldKey); + if (element != null) + { + elements.put(newKey, element); + save(newKey, oldKey); + } + + return element; + } + public final synchronized void removeElement(String key) { E element = elements.remove(key); @@ -248,7 +260,7 @@ public abstract class PersistentMap<E> } } - private void save(String addedKey, final String removedKey) + public void save(String addedKey, final String removedKey) { if (file != null) { diff --git a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/ProfileImpl.java b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/ProfileImpl.java index 6b7749332..64be977f4 100644 --- a/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/ProfileImpl.java +++ b/plugins/org.eclipse.oomph.p2.core/src/org/eclipse/oomph/p2/internal/core/ProfileImpl.java @@ -132,9 +132,9 @@ public class ProfileImpl extends AgentManagerElementImpl implements Profile, Per private final String type; - private final File installFolder; + private File installFolder; - private final File referencer; + private File referencer; private IProfile delegate; @@ -198,11 +198,21 @@ public class ProfileImpl extends AgentManagerElementImpl implements Profile, Per return installFolder; } + public void setInstallFolder(File installFolder) + { + this.installFolder = installFolder; + } + public File getReferencer() { return referencer; } + public void setReferencer(File referencer) + { + this.referencer = referencer; + } + public String getExtraInfo() { List<String> tokens = new ArrayList<String>(); diff --git a/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupTaskPerformer.java b/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupTaskPerformer.java index 863a23121..aa14a96e7 100644 --- a/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupTaskPerformer.java +++ b/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/SetupTaskPerformer.java @@ -123,8 +123,6 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.equinox.internal.p2.update.Configuration; -import org.eclipse.equinox.internal.p2.update.Site; import org.eclipse.equinox.p2.metadata.VersionRange; import org.osgi.framework.Bundle; @@ -2890,26 +2888,6 @@ public class SetupTaskPerformer extends AbstractSetupTaskContext File bundlePool = profile.getBundlePool().getLocation(); if (!installFolder.equals(bundlePool)) { - File platformXML = new File(productConfigurationLocation, "org.eclipse.update/platform.xml"); - if (platformXML.isFile()) - { - Configuration configuration = Configuration.load(platformXML, null); - for (Site site : configuration.getSites()) - { - if (!Site.POLICY_MANAGED_ONLY.equals(site.getPolicy())) - { - File siteLocation = new File(URI.createURI(site.getUrl()).toFileString()); - if (siteLocation.equals(bundlePool)) - { - log("Changing " + platformXML + " (policy=" + Site.POLICY_MANAGED_ONLY + ")", false, Severity.OK); - site.setPolicy(Site.POLICY_MANAGED_ONLY); - configuration.save(platformXML, null); - break; - } - } - } - } - File garbageCollectorPreferences = new File(productConfigurationLocation, ".settings/org.eclipse.equinox.p2.garbagecollector.prefs"); IOUtil.writeLines(garbageCollectorPreferences, "8859_1", Arrays.asList(new String[] { "eclipse.preferences.version=1", "gc_enabled=false" })); } diff --git a/plugins/org.eclipse.oomph.setup.p2/src/org/eclipse/oomph/setup/p2/impl/P2TaskImpl.java b/plugins/org.eclipse.oomph.setup.p2/src/org/eclipse/oomph/setup/p2/impl/P2TaskImpl.java index 56626843c..8bb1036c5 100644 --- a/plugins/org.eclipse.oomph.setup.p2/src/org/eclipse/oomph/setup/p2/impl/P2TaskImpl.java +++ b/plugins/org.eclipse.oomph.setup.p2/src/org/eclipse/oomph/setup/p2/impl/P2TaskImpl.java @@ -30,10 +30,8 @@ import org.eclipse.oomph.setup.impl.SetupTaskImpl; import org.eclipse.oomph.setup.internal.p2.SetupP2Plugin; import org.eclipse.oomph.setup.p2.P2Task; import org.eclipse.oomph.setup.p2.SetupP2Package; -import org.eclipse.oomph.setup.util.DownloadUtil; import org.eclipse.oomph.util.Confirmer; import org.eclipse.oomph.util.Confirmer.Confirmation; -import org.eclipse.oomph.util.IORuntimeException; import org.eclipse.oomph.util.IOUtil; import org.eclipse.oomph.util.OS; import org.eclipse.oomph.util.Pair; @@ -60,7 +58,6 @@ import org.eclipse.equinox.p2.core.UIServices; import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.equinox.p2.engine.IProfileRegistry; import org.eclipse.equinox.p2.engine.IProvisioningPlan; -import org.eclipse.equinox.p2.metadata.IArtifactKey; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.metadata.ILicense; import org.eclipse.equinox.p2.metadata.VersionRange; @@ -72,7 +69,6 @@ import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; import java.security.cert.Certificate; @@ -81,12 +77,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * <!-- begin-user-doc --> @@ -638,8 +631,6 @@ public class P2TaskImpl extends SetupTaskImpl implements P2Task public void perform(final SetupTaskContext context) throws Exception { File eclipseDir = context.getProductLocation(); - File eclipseIni = new File(eclipseDir, "eclipse.ini"); - boolean eclipseIniExisted = eclipseIni.exists(); boolean offline = context.isOffline(); context.log("Offline = " + offline); @@ -754,53 +745,6 @@ public class P2TaskImpl extends SetupTaskImpl implements P2Task } } } - - if (eclipseIniExisted) - { - checkEclipseIniForDuplicates(context, eclipseIni); - } - - updateSplash(context, profile); - } - - private void updateSplash(final SetupTaskContext context, Profile profile) - { - BundlePool bundlePool = profile.getBundlePool(); - if (bundlePool != null) - { - File productConfigurationLocation = context.getProductConfigurationLocation(); - try - { - File configIniFile = new File(productConfigurationLocation, "config.ini"); - Map<String, String> properties = PropertiesUtil.loadProperties(configIniFile); - String splashPath = properties.get("osgi.splashPath"); - if (splashPath != null) - { - org.eclipse.emf.common.util.URI uri = org.eclipse.emf.common.util.URI.createURI(splashPath); - if ("platform".equals(uri.scheme()) && uri.segmentCount() >= 2 && "base".equals(uri.segment(0))) - { - for (IInstallableUnit installableUnit : P2Util.asIterable(profile.query(QueryUtil.createIUQuery(uri.lastSegment()), null))) - { - for (IArtifactKey artifactKey : installableUnit.getArtifacts()) - { - File artifactFile = bundlePool.getFileArtifactRepository().getArtifactFile(artifactKey); - if (new File(artifactFile, "splash.bmp").exists()) - { - properties.put("osgi.splashPath", org.eclipse.emf.common.util.URI.createFileURI(artifactFile.toString()).toString()); - saveConfigIni(configIniFile, properties, P2TaskImpl.class); - - return; - } - } - } - } - } - } - catch (IORuntimeException ex) - { - // Ignore. - } - } } private Profile getProfile(final SetupTaskContext context, String profileID) throws Exception @@ -811,8 +755,10 @@ public class P2TaskImpl extends SetupTaskImpl implements P2Task BundlePool bundlePool; String bundlePoolLocation = (String)context.get(AgentManager.PROP_BUNDLE_POOL_LOCATION); + boolean sharedPool; if (bundlePoolLocation != null) { + sharedPool = true; bundlePool = P2Util.getAgentManager().getBundlePool(new File(bundlePoolLocation)); // TODO Remove the following two lines after bug 485018 has been fixed. @@ -821,6 +767,7 @@ public class P2TaskImpl extends SetupTaskImpl implements P2Task } else { + sharedPool = false; File agentLocation = new File(context.getProductLocation(), "p2"); Agent agent = P2Util.createAgent(agentLocation); bundlePool = agent.addBundlePool(agentLocation.getParentFile()); @@ -846,6 +793,13 @@ public class P2TaskImpl extends SetupTaskImpl implements P2Task profileCreator.addOS(os.getOsgiOS()); profileCreator.addWS(os.getOsgiWS()); profileCreator.addArch(os.getOsgiArch()); + profileCreator.setRoaming(true); + + // This property is used in org.eclipse.oomph.p2.internal.core.LazyProfile.setProperty(String, String) + // to ensure that when org.eclipse.equinox.internal.p2.engine.SimpleProfileRegistry.updateRoamingProfile(Profile) + // updates the profile's install location, it doesn't also replace the shared pool location with a local pool. + // Of course if this is an installation with a local pool, it should be replace during a roaming update. + profileCreator.set(Profile.PROP_PROFILE_SHARED_POOL, sharedPool); profile = profileCreator.create(); } @@ -974,56 +928,6 @@ public class P2TaskImpl extends SetupTaskImpl implements P2Task } } - private static void checkEclipseIniForDuplicates(final SetupTaskContext context, File iniFile) - { - FileOutputStream out = null; - - try - { - org.eclipse.emf.common.util.URI uri = org.eclipse.emf.common.util.URI.createFileURI(iniFile.toString()); - String contents = DownloadUtil.load(context.getURIConverter(), uri, null); - Pattern section = Pattern.compile("^(-vmargs)([\n\r]+.*)\\z|^(-[^\\n\\r]*[\\n\\r]*)((?:^[^-][^\\n\\r]*)*[\\n\\r]*)", Pattern.MULTILINE | Pattern.DOTALL); - Map<String, String> map = new LinkedHashMap<String, String>(); - for (Matcher matcher = section.matcher(contents); matcher.find();) - { - String argument = matcher.group(3); - String extension; - if (argument == null) - { - argument = matcher.group(1); - extension = matcher.group(2); - } - else - { - extension = matcher.group(4); - } - - if (!argument.startsWith("--launcher.XXMaxPermSize") || !map.containsKey(argument)) - { - map.put(argument, extension); - } - } - - StringBuilder newContents = new StringBuilder(); - for (Map.Entry<String, String> entry : map.entrySet()) - { - newContents.append(entry.getKey()); - newContents.append(entry.getValue()); - } - - out = new FileOutputStream(iniFile); - out.write(newContents.toString().getBytes()); - } - catch (IOException ex) - { - // Ignore. - } - finally - { - IOUtil.close(out); - } - } - private static Set<IInstallableUnit> getInstalledUnits(Agent agent) { Set<IInstallableUnit> result = new HashSet<IInstallableUnit>(); diff --git a/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/SetupUIPlugin.java b/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/SetupUIPlugin.java index 800e33e86..0514449ad 100644 --- a/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/SetupUIPlugin.java +++ b/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/SetupUIPlugin.java @@ -70,6 +70,7 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.equinox.p2.engine.IProfile; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.PreferenceManager; import org.eclipse.swt.widgets.Display; @@ -362,12 +363,30 @@ public final class SetupUIPlugin extends OomphUIPlugin File bundlePoolLocation = bundlePool.getLocation(); if (bundlePoolLocation != null) { - File eclipseExtensionFeaturesFolder = new File(bundlePoolLocation, ".eclipseextension/features"); - eclipseExtensionFeaturesFolder.mkdirs(); + String installFolderLocation = currentProfile.getProperty(IProfile.PROP_INSTALL_FOLDER); + if (installFolderLocation != null && !bundlePoolLocation.equals(new File(installFolderLocation))) + { + File eclipseExtensionFeaturesFolder = new File(bundlePoolLocation, ".eclipseextension/features"); + eclipseExtensionFeaturesFolder.mkdirs(); + } } } } } + + Profile currentProfile = P2Util.getAgentManager().getCurrentAgent().getCurrentProfile(); + String installFolderLocation = currentProfile.getProperty(IProfile.PROP_INSTALL_FOLDER); + if (installFolderLocation != null) + { + BundlePool bundlePool = currentProfile.getBundlePool(); + File bundlePoolLocation = bundlePool.getLocation(); + + if (!bundlePoolLocation.equals(new File(installFolderLocation))) + { + File eclipseExtensionFeaturesFolder = new File(bundlePoolLocation, ".eclipseextension/features"); + eclipseExtensionFeaturesFolder.mkdirs(); + } + } } catch (Throwable throwable) { diff --git a/setups/OomphInstaller.setup b/setups/OomphInstaller.setup index 94665fd3d..939d45a47 100644 --- a/setups/OomphInstaller.setup +++ b/setups/OomphInstaller.setup @@ -22,6 +22,18 @@ <value>Eclipse Installer</value> </detail> </annotation> + <version name="local" + label="Local" + requiredJavaVersion="1.7"> + <setupTask + xsi:type="setup.p2:P2Task" + label="Eclipse Installer"> + <requirement + name="org.eclipse.oomph.setup.installer.product"/> + <repository + url="${oomph.product.update.url}"/> + </setupTask> + </version> <version name="mars" label="Mars" requiredJavaVersion="1.7"> |