summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPascal Rapicault2013-02-16 09:37:50 (EST)
committerPascal Rapicault2013-02-16 09:37:50 (EST)
commit31e44d1b2d70d84078ff36f6498258693b6db7d7 (patch)
tree88b0fdc4fb83425adf4477ff8c4cc86b4fddbbaa
parent1ff11052e53d648dec8305eea7c51a111e53d39a (diff)
downloadrt.equinox.p2-31e44d1b2d70d84078ff36f6498258693b6db7d7.zip
rt.equinox.p2-31e44d1b2d70d84078ff36f6498258693b6db7d7.tar.gz
rt.equinox.p2-31e44d1b2d70d84078ff36f6498258693b6db7d7.tar.bz2
trigger migration when install movedv20130216-143750
-rw-r--r--bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdatePlugin.java12
-rw-r--r--bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java70
-rw-r--r--bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/PreviousConfigurationFinder.java306
3 files changed, 379 insertions, 9 deletions
diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdatePlugin.java b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdatePlugin.java
index a4dac61..c55d000 100644
--- a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdatePlugin.java
+++ b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdatePlugin.java
@@ -15,8 +15,7 @@ import java.net.URL;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus;
-import org.eclipse.equinox.p2.core.IAgentLocation;
-import org.eclipse.equinox.p2.core.IProvisioningAgent;
+import org.eclipse.equinox.p2.core.*;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.engine.ProfileScope;
import org.eclipse.equinox.p2.operations.ProvisioningSession;
@@ -182,4 +181,13 @@ public class AutomaticUpdatePlugin extends AbstractUIPlugin {
public ProvisioningSession getSession() {
return session;
}
+
+ public IProvisioningAgentProvider getAgentProvider() {
+ ServiceReference<?> ref = getContext().getServiceReference(IProvisioningAgentProvider.SERVICE_NAME);
+ if (ref == null)
+ return null;
+ IProvisioningAgentProvider agentProvider = (IProvisioningAgentProvider) getContext().getService(ref);
+ getContext().ungetService(ref);
+ return agentProvider;
+ }
}
diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java
index 674b1f2..417291d 100644
--- a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java
+++ b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/AutomaticUpdateScheduler.java
@@ -14,10 +14,12 @@ package org.eclipse.equinox.internal.p2.ui.sdk.scheduler;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.ULocale;
+import java.io.File;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
+import org.eclipse.equinox.internal.p2.engine.EngineActivator;
import org.eclipse.equinox.internal.p2.garbagecollector.GarbageCollector;
import org.eclipse.equinox.internal.p2.metadata.query.UpdateQuery;
import org.eclipse.equinox.internal.p2.ui.sdk.scheduler.migration.ImportFromInstallationWizard_c;
@@ -32,6 +34,7 @@ import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.osgi.service.datalocation.Location;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.*;
@@ -45,6 +48,7 @@ import org.eclipse.ui.statushandlers.StatusManager;
public class AutomaticUpdateScheduler implements IStartup {
private static final String ECLIPSE_P2_SKIP_MIGRATION_WIZARD = "eclipse.p2.skipMigrationWizard"; //$NON-NLS-1$
+ private static final String ECLIPSE_P2_SKIP_MOVED_INSTALL_DETECTION = "eclipse.p2.skipMovedInstallDetection"; //$NON-NLS-1$
// values are to be picked up from the arrays DAYS and HOURS
public static final String P_DAY = "day"; //$NON-NLS-1$
@@ -108,19 +112,71 @@ public class AutomaticUpdateScheduler implements IStartup {
if (skipWizard)
return false;
- if (!baseChangedSinceLastPresentationOfWizard(agent, registry, currentProfile))
- return false;
+ IProfile previousProfile = null;
+ if (!skipFirstTimeMigration() && !configurationSpecifiedManually() && isFirstTimeRunningThisSharedInstance(agent, registry, currentProfile)) {
+ File searchRoot = getSearchLocation();
+ if (searchRoot == null)
+ return false;
+ previousProfile = new PreviousConfigurationFinder(getConfigurationLocation().getParentFile()).findPreviousInstalls(searchRoot, getInstallFolder());
+ if (previousProfile == null)
+ return false;
+
+ //At this point we consider that the migration is done since we will present something to the user.
+ registry.setProfileStateProperty(currentProfile.getProfileId(), registry.listProfileTimestamps(currentProfile.getProfileId())[0], "INITIAL", "DONE");
+ }
- final IProfile previousProfile = findMostRecentReset(registry, currentProfile);
+ if (previousProfile == null && baseChangedSinceLastPresentationOfWizard(agent, registry, currentProfile))
+ previousProfile = findMostRecentReset(registry, currentProfile);
- if (previousProfile != null) {
- if (needsMigration(previousProfile, currentProfile)) {
- openMigrationWizard(previousProfile);
- }
+ if (previousProfile == null)
+ return false;
+
+ if (needsMigration(previousProfile, currentProfile)) {
+ openMigrationWizard(previousProfile);
}
return true;
}
+ private File getInstallFolder() {
+ Location configurationLocation = (Location) ServiceHelper.getService(EngineActivator.getContext(), Location.class.getName(), Location.INSTALL_FILTER);
+ return new File(configurationLocation.getURL().getPath());
+
+ }
+
+ //The search location is two level up from teh configuration location.
+ private File getSearchLocation() {
+ File parent = getConfigurationLocation().getParentFile();
+ if (parent == null)
+ return null;
+ return parent.getParentFile();
+ }
+
+ private File getConfigurationLocation() {
+ Location configurationLocation = (Location) ServiceHelper.getService(EngineActivator.getContext(), Location.class.getName(), Location.CONFIGURATION_FILTER);
+ File configurationFolder = new File(configurationLocation.getURL().getPath());
+ return configurationFolder;
+ }
+
+ //Check if the user has explicitly specified -configuration on the command line
+ private boolean configurationSpecifiedManually() {
+ String commandLine = System.getProperty("eclipse.commands"); //$NON-NLS-1$
+ if (commandLine == null)
+ return false;
+ return commandLine.contains("-configuration\n"); //$NON-NLS-1$
+ }
+
+ private boolean skipFirstTimeMigration() {
+ return Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty(ECLIPSE_P2_SKIP_MOVED_INSTALL_DETECTION));
+ }
+
+ private boolean isFirstTimeRunningThisSharedInstance(IProvisioningAgent agent, IProfileRegistry registry, IProfile currentProfile) {
+ long[] history = registry.listProfileTimestamps(currentProfile.getProfileId());
+ boolean isInitial = IProfile.STATE_SHARED_INSTALL_VALUE_INITIAL.equals(registry.getProfileStateProperties(currentProfile.getProfileId(), history[0]).get(IProfile.STATE_PROP_SHARED_INSTALL));
+ if (isInitial)
+ return false;
+ return "DONE".equals(registry.getProfileStateProperties(currentProfile.getProfileId(), history[0]).get("INITIAL"));
+ }
+
/**
* @param previousProfile is the profile used previous to the current one
* @param currentProfile is the current profile used by eclipse.
diff --git a/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/PreviousConfigurationFinder.java b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/PreviousConfigurationFinder.java
new file mode 100644
index 0000000..9aa6f23
--- /dev/null
+++ b/bundles/org.eclipse.equinox.p2.ui.sdk.scheduler/src/org/eclipse/equinox/internal/p2/ui/sdk/scheduler/PreviousConfigurationFinder.java
@@ -0,0 +1,306 @@
+package org.eclipse.equinox.internal.p2.ui.sdk.scheduler;
+
+import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.eclipse.core.runtime.URIUtil;
+import org.eclipse.equinox.p2.core.IProvisioningAgent;
+import org.eclipse.equinox.p2.core.ProvisionException;
+import org.eclipse.equinox.p2.engine.IProfile;
+import org.eclipse.equinox.p2.engine.IProfileRegistry;
+
+public class PreviousConfigurationFinder {
+
+ private static final Pattern path = Pattern.compile("(.+)_(.*)_(\\d+)_.*"); //$NON-NLS-1$
+
+ static class Identifier {
+ private static final String DELIM = ". _-"; //$NON-NLS-1$
+ private int major, minor, service;
+
+ Identifier(int major, int minor, int service) {
+ super();
+ this.major = major;
+ this.minor = minor;
+ this.service = service;
+ }
+
+ /**
+ * @throws NumberFormatException if cannot parse the major and minor version components
+ */
+ Identifier(String versionString) {
+ super();
+ StringTokenizer tokenizer = new StringTokenizer(versionString, DELIM);
+
+ // major
+ if (tokenizer.hasMoreTokens())
+ major = Integer.parseInt(tokenizer.nextToken());
+
+ // minor
+ if (tokenizer.hasMoreTokens())
+ minor = Integer.parseInt(tokenizer.nextToken());
+
+ try {
+ // service
+ if (tokenizer.hasMoreTokens())
+ service = Integer.parseInt(tokenizer.nextToken());
+ } catch (NumberFormatException nfe) {
+ // ignore the service qualifier in that case and default to 0
+ // this will allow us to tolerate other non-conventional version numbers
+ }
+ }
+
+ /**
+ * Returns true if this id is considered to be greater than or equal to the given baseline.
+ * e.g.
+ * 1.2.9 >= 1.3.1 -> false
+ * 1.3.0 >= 1.3.1 -> false
+ * 1.3.1 >= 1.3.1 -> true
+ * 1.3.2 >= 1.3.1 -> true
+ * 2.0.0 >= 1.3.1 -> true
+ */
+ boolean isGreaterEqualTo(Identifier minimum) {
+ if (major < minimum.major)
+ return false;
+ if (major > minimum.major)
+ return true;
+ // major numbers are equivalent so check minor
+ if (minor < minimum.minor)
+ return false;
+ if (minor > minimum.minor)
+ return true;
+ // minor numbers are equivalent so check service
+ return service >= minimum.service;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Identifier)
+ return false;
+ Identifier o = (Identifier) other;
+ if (major == o.major && minor == o.minor && service == o.service)
+ return true;
+ return false;
+ }
+ }
+
+ static class ConfigurationData {
+ String productId;
+ Identifier version;
+ String installPathHashcode;
+ File config;
+
+ public ConfigurationData(String productId, Identifier version, String installPathHashcode, File config) {
+ this.productId = productId;
+ this.version = version;
+ this.installPathHashcode = installPathHashcode;
+ this.config = config;
+ }
+
+ public String getProductId() {
+ return productId;
+ }
+
+ public Identifier getVersion() {
+ return version;
+ }
+
+ public String getInstallPathHashcode() {
+ return installPathHashcode;
+ }
+
+ public File getConfig() {
+ return config;
+ }
+ }
+
+ private File currentConfig;
+
+ public PreviousConfigurationFinder(File currentConfiguration) {
+ currentConfig = currentConfiguration;
+ }
+
+ private ConfigurationData extractConfigurationData(File candidate) {
+ Matcher m = path.matcher(candidate.getName());
+ if (!m.matches())
+ return null;
+ return new ConfigurationData(m.group(1), new Identifier(m.group(2)), m.group(3), candidate.getAbsoluteFile());
+ }
+
+ public IProfile findPreviousInstalls(File searchRoot, File installFolder) {
+ List<ConfigurationData> potentialConfigurations = readPreviousConfigurations(searchRoot);
+ Object[] productInfo = loadEclipseProductFile(installFolder);
+ ConfigurationData match = findMostRelevantConfiguration(potentialConfigurations, getInstallDirHash(installFolder), productInfo);
+ if (match == null)
+ match = findMostRelevantConfiguration(potentialConfigurations, productInfo);
+ if (match == null)
+ return null;
+ return fromConfigurationToProfile(match.getConfig());
+ }
+
+ private IProfile fromConfigurationToProfile(File configurationFolder) {
+ //TODO dispose the agent
+ String toBeImportedProfileId = null;
+ File config = new File(configurationFolder, "configuration/config.ini"); //$NON-NLS-1$
+ URI configArea = config.getParentFile().toURI();
+ InputStream is = null;
+ // default area
+ File p2DataArea = new File(configurationFolder, "p2"); //$NON-NLS-1$
+ try {
+ Properties props = new Properties();
+ is = new FileInputStream(config);
+ props.load(is);
+ toBeImportedProfileId = props.getProperty("eclipse.p2.profile"); //$NON-NLS-1$
+ String url = props.getProperty("eclipse.p2.data.area"); //$NON-NLS-1$
+ if (url != null) {
+ final String CONFIG_DIR = "@config.dir/"; //$NON-NLS-1$
+ final String FILE_PROTOCOL = "file:"; //$NON-NLS-1$
+ if (url.startsWith(CONFIG_DIR))
+ url = FILE_PROTOCOL + url.substring(CONFIG_DIR.length());
+ p2DataArea = new File(URIUtil.makeAbsolute(URIUtil.fromString(new File(url.substring(FILE_PROTOCOL.length())).isAbsolute() ? url : url.substring(FILE_PROTOCOL.length())), configArea));
+ }
+ } catch (IOException ioe) {
+ //ignore
+ } catch (URISyntaxException e) {
+ return null;
+ } finally {
+ try {
+ is.close();
+ } catch (IOException ioe) {
+ //ignore
+ }
+ is = null;
+ }
+ if (p2DataArea.exists()) {
+ IProvisioningAgent agent = null;
+ try {
+ agent = AutomaticUpdatePlugin.getDefault().getAgentProvider().createAgent(p2DataArea.toURI());
+ } catch (ProvisionException e) {
+ //Can't happen
+ }
+ IProfileRegistry registry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME);
+ if (toBeImportedProfileId != null)
+ return registry.getProfile(toBeImportedProfileId);
+
+ //TODO we may need to set the SELF profile on the registry to load the repos
+ IProfile[] allProfiles = registry.getProfiles();
+ if (allProfiles.length == 1)
+ return allProfiles[0];
+
+ // IMetadataRepositoryManager metadataRepoMgr = (IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME);
+ // URI[] metadataRepos = metadataRepoMgr.getKnownRepositories(IRepositoryManager.REPOSITORIES_NON_SYSTEM);
+ //TODO deal with the repos
+ }
+ return null;
+ }
+
+ private ConfigurationData findMostRelevantConfiguration(List<ConfigurationData> configurations, String installDirHash, Object[] productInfo) {
+ ConfigurationData bestMatch = null;
+ int numberOfcriteriaMet = 0;
+ for (ConfigurationData candidate : configurations) {
+ int criteriaMet = 0;
+ if (!candidate.getInstallPathHashcode().equals(installDirHash))
+ continue;
+ criteriaMet++;
+ if (!candidate.getProductId().equals(productInfo[0]))
+ continue;
+ criteriaMet++;
+ if (!candidate.getVersion().equals(productInfo[1]))
+ continue; //This is most likely ourselves
+ criteriaMet++;
+ if (criteriaMet > numberOfcriteriaMet) {
+ bestMatch = candidate;
+ numberOfcriteriaMet = criteriaMet;
+ } else if (criteriaMet == numberOfcriteriaMet) {
+ if (bestMatch.getConfig().lastModified() < candidate.getConfig().lastModified())
+ bestMatch = candidate;
+ }
+ }
+ return bestMatch;
+ }
+
+ //Out of a set of configuration, find the one with the most similar product info.
+ //TODO do we look for the higer or lower versions?
+ private ConfigurationData findMostRelevantConfiguration(List<ConfigurationData> configurations, Object[] productInfo) {
+ ConfigurationData bestMatch = null;
+ int numberOfcriteriaMet = 0;
+ for (ConfigurationData candidate : configurations) {
+ int criteriaMet = 0;
+ criteriaMet++;
+ if (!candidate.getProductId().equals(productInfo[0]))
+ continue;
+ criteriaMet++;
+ if (candidate.getVersion().equals(productInfo[1]))
+ continue; //This is most likely ourselves
+ else if (bestMatch != null && (candidate.getVersion().equals(bestMatch.getVersion())))
+ criteriaMet++;
+ if (criteriaMet > numberOfcriteriaMet) {
+ bestMatch = candidate;
+ numberOfcriteriaMet = criteriaMet;
+ } else if (criteriaMet == numberOfcriteriaMet) {
+ if (bestMatch.getConfig().lastModified() < candidate.getConfig().lastModified())
+ bestMatch = candidate;
+ }
+ }
+ return bestMatch;
+ }
+
+ //Load the .eclipseproduct file in the base of the installation. This logic is very similar to the one found in the launcher
+ private Object[] loadEclipseProductFile(File installDir) {
+ final String ECLIPSE = "eclipse"; //$NON-NLS-1$
+ final String PRODUCT_SITE_MARKER = ".eclipseproduct"; //$NON-NLS-1$
+ final String PRODUCT_SITE_ID = "id"; //$NON-NLS-1$
+ final String PRODUCT_SITE_VERSION = "version"; //$NON-NLS-1$
+
+ File eclipseProduct = new File(installDir, PRODUCT_SITE_MARKER);
+ String appId = null;
+ Identifier appVersion = null;
+ if (eclipseProduct.exists()) {
+ Properties props = new Properties();
+ try {
+ props.load(new FileInputStream(eclipseProduct));
+ appId = props.getProperty(PRODUCT_SITE_ID);
+ if (appId == null || appId.trim().length() == 0)
+ appId = ECLIPSE;
+ String version = props.getProperty(PRODUCT_SITE_VERSION);
+ if (version == null || version.trim().length() == 0)
+ appVersion = new Identifier(0, 0, 0);
+ else
+ appVersion = new Identifier(version);
+
+ } catch (IOException e) {
+ return new String[0];
+ }
+ } else {
+ return new String[0];
+ }
+ return new Object[] {appId, appVersion};
+ }
+
+ //Iterate through a folder to look for potential configuration folders and reify them.
+ private List<ConfigurationData> readPreviousConfigurations(File configurationFolder) {
+ File[] candidates = configurationFolder.listFiles();
+ List<ConfigurationData> configurations = new ArrayList<ConfigurationData>(candidates.length);
+ for (File candidate : candidates) {
+ if (!candidate.isDirectory())
+ continue;
+ if (candidate.equals(currentConfig))
+ continue;
+ ConfigurationData tmp = extractConfigurationData(candidate);
+ if (tmp != null)
+ configurations.add(tmp);
+ }
+ return configurations;
+ }
+
+ //Simplified code computing the hashCode of the install location. The real runtime code is in the launcher
+ private String getInstallDirHash(File installFolder) {
+ try {
+ return Integer.toString(installFolder.getCanonicalPath().hashCode());
+ } catch (IOException e) {
+ return ""; //$NON-NLS-1$
+ }
+ }
+}