blob: 7e18f4bac2a2ce0fbbfa2c4d90604ae70120e36b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2015 Ericsson AB 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:
* Ericsson AB - initial API and implementation
* Ericsson AB (Pascal Rapicault)
* Ericsson AB (Hamdan Msheik)
* Red Hat Inc. - Bug 460967
******************************************************************************/
package org.eclipse.equinox.internal.p2.ui.sdk.scheduler.migration;
import java.io.File;
import java.net.URI;
import java.util.*;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper;
import org.eclipse.equinox.internal.p2.engine.EngineActivator;
import org.eclipse.equinox.internal.p2.metadata.query.UpdateQuery;
import org.eclipse.equinox.internal.p2.ui.sdk.scheduler.*;
import org.eclipse.equinox.p2.core.IAgentLocation;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery;
import org.eclipse.equinox.p2.engine.query.UserVisibleRootQuery;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.IRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.equinox.p2.ui.ProvisioningUI;
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.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
public class MigrationSupport {
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$
//The return value indicates if the migration dialog has been shown or not. It does not indicate whether the migration has completed.
public boolean performMigration(IProvisioningAgent agent, IProfileRegistry registry, IProfile currentProfile) {
boolean skipWizard = Boolean.TRUE.toString().equalsIgnoreCase(System.getProperty(ECLIPSE_P2_SKIP_MIGRATION_WIZARD));
if (skipWizard)
return false;
IProfile previousProfile = null;
URI[] reposToMigrate = null;
if (!skipFirstTimeMigration() && !configurationSpecifiedManually() && isFirstTimeRunningThisSharedInstance(agent, registry, currentProfile)) {
File searchRoot = getSearchLocation();
if (searchRoot == null)
return false;
IProvisioningAgent otherConfigAgent = new PreviousConfigurationFinder(getConfigurationLocation().getParentFile()).findPreviousInstalls(searchRoot, getInstallFolder());
if (otherConfigAgent == null) {
return false;
}
previousProfile = ((IProfileRegistry) otherConfigAgent.getService(IProfileRegistry.SERVICE_NAME)).getProfile(IProfileRegistry.SELF);
if (previousProfile == null)
return false;
reposToMigrate = ((IMetadataRepositoryManager) otherConfigAgent.getService(IMetadataRepositoryManager.SERVICE_NAME)).getKnownRepositories(IRepositoryManager.REPOSITORIES_NON_SYSTEM);
reposToMigrate = copyOf(reposToMigrate, reposToMigrate.length + 1);
reposToMigrate[reposToMigrate.length - 1] = getURIForProfile(otherConfigAgent, previousProfile);
}
if (previousProfile == null && baseChangedSinceLastPresentationOfWizard(agent, registry, currentProfile))
previousProfile = findMostRecentReset(registry, currentProfile);
if (previousProfile == null)
return false;
Collection<IInstallableUnit> unitsToMigrate = findUnitstoMigrate(previousProfile, currentProfile);
if (!unitsToMigrate.isEmpty()) {
openMigrationWizard(previousProfile, unitsToMigrate, reposToMigrate);
} else {
//There is nothing to migrate, so we mark the migration complete
rememberMigrationCompleted();
}
return true;
}
private static URI[] copyOf(URI[] original, int newLength) {
URI[] copy = new URI[newLength];
int copyCount = Math.min(original.length, newLength);
System.arraycopy(original, 0, copy, 0, copyCount);
return copy;
}
private URI getURIForProfile(IProvisioningAgent agent, IProfile profile) {
IAgentLocation agentLocation = (IAgentLocation) agent.getService(IAgentLocation.SERVICE_NAME);
return URIUtil.append(agentLocation.getRootLocation(), "org.eclipse.equinox.p2.engine/profileRegistry/" + profile.getProfileId() + ".profile"); //$NON-NLS-1$ //$NON-NLS-2$
}
private File getInstallFolder() {
Location configurationLocation = ServiceHelper.getService(EngineActivator.getContext(), Location.class, Location.INSTALL_FILTER);
return new File(configurationLocation.getURL().getPath());
}
//The search location is two level up from the configuration location.
private File getSearchLocation() {
File parent = getConfigurationLocation().getParentFile();
if (parent == null)
return null;
return parent.getParentFile();
}
private File getConfigurationLocation() {
Location configurationLocation = ServiceHelper.getService(EngineActivator.getContext(), Location.class, 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) {
if (getLastMigration() >= history[0])
return false;
//This detect the case where the user has not done any migration.
Map<String, String> sharedRelatedValues = registry.getProfileStateProperties(currentProfile.getProfileId(), IProfile.STATE_PROP_SHARED_INSTALL);
if (sharedRelatedValues.containsValue(IProfile.STATE_SHARED_INSTALL_VALUE_NEW))
return false;
return true;
}
return false;
}
/**
* @param previousProfile is the profile used previous to the current one
* @param currentProfile is the current profile used by eclipse.
* @return true if set difference between previousProfile units and currentProfile units not empty, otherwise false
*/
protected Collection<IInstallableUnit> findUnitstoMigrate(IProfile previousProfile, IProfile currentProfile) {
//First, try the case of inclusion
Set<IInstallableUnit> previousProfileUnits = getUserRoots(previousProfile);
Set<IInstallableUnit> currentProfileUnits = currentProfile.available(new UserVisibleRootQuery(), null).toSet();
previousProfileUnits.removeAll(currentProfileUnits);
//For the IUs left in the previous profile, look for those that could be in the base but not as roots
Iterator<IInstallableUnit> previousProfileIterator = previousProfileUnits.iterator();
while (previousProfileIterator.hasNext()) {
if (!currentProfile.available(QueryUtil.createIUQuery(previousProfileIterator.next()), null).isEmpty())
previousProfileIterator.remove();
}
//For the IUs left in the previous profile, look for those that could be available in the root but as higher versions (they could be root or not)
previousProfileIterator = previousProfileUnits.iterator();
while (previousProfileIterator.hasNext()) {
if (!currentProfile.available(new UpdateQuery(previousProfileIterator.next()), null).isEmpty())
previousProfileIterator.remove();
}
return previousProfileUnits;
}
private Set<IInstallableUnit> getUserRoots(IProfile previousProfile) {
IQueryResult<IInstallableUnit> allRoots = previousProfile.query(new UserVisibleRootQuery(), null);
Set<IInstallableUnit> rootsFromTheBase = previousProfile.query(new IUProfilePropertyQuery("org.eclipse.equinox.p2.base", "true"), null).toUnmodifiableSet();
Set<IInstallableUnit> userRoots = allRoots.toSet();
userRoots.removeAll(rootsFromTheBase);
return userRoots;
}
protected void openMigrationWizard(final IProfile inputProfile, final Collection<IInstallableUnit> unitsToMigrate, final URI[] reposToMigrate) {
Display d = Display.getDefault();
d.asyncExec(new Runnable() {
public void run() {
WizardDialog migrateWizard = new MigrationWizardDialog(getWorkbenchWindowShell(), new MigrationWizard(inputProfile, unitsToMigrate, reposToMigrate, reposToMigrate != null));
migrateWizard.create();
migrateWizard.open();
}
});
}
private boolean baseChangedSinceLastPresentationOfWizard(IProvisioningAgent agent, IProfileRegistry registry, IProfile profile) {
long lastProfileMigrated = getLastMigration();
long lastResetTimestamp = findMostRecentResetTimestamp(registry, profile);
return lastProfileMigrated <= lastResetTimestamp;
}
//The timestamp from which we migrated or -1
private long findMostRecentResetTimestamp(IProfileRegistry registry, IProfile profile) {
long[] history = registry.listProfileTimestamps(profile.getProfileId());
int index = history.length - 1;
boolean found = false;
while (!(found = IProfile.STATE_SHARED_INSTALL_VALUE_BEFOREFLUSH.equals(registry.getProfileStateProperties(profile.getProfileId(), history[index]).get(IProfile.STATE_PROP_SHARED_INSTALL))) && index > 0) {
index--;
}
if (!found)
return -1;
return history[index];
}
private IProfile findMostRecentReset(IProfileRegistry registry, IProfile profile) {
long ts = findMostRecentResetTimestamp(registry, profile);
if (ts == -1)
return null;
return registry.getProfile(profile.getProfileId(), ts);
}
Shell getWorkbenchWindowShell() {
IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
return activeWindow != null ? activeWindow.getShell() : null;
}
public void rememberMigrationCompleted() {
IProfileRegistry registry = (IProfileRegistry) ProvisioningUI.getDefaultUI().getSession().getProvisioningAgent().getService(IProfileRegistry.SERVICE_NAME);
long[] history = registry.listProfileTimestamps(ProvisioningUI.getDefaultUI().getProfileId());
AutomaticUpdatePlugin.getDefault().getPreferenceStore().setValue(AutomaticUpdateScheduler.MIGRATION_DIALOG_SHOWN, history[history.length - 1]);
AutomaticUpdatePlugin.getDefault().savePreferences();
}
//Get the timestamp that we migrated from. O if we have not migrated.
public long getLastMigration() {
return AutomaticUpdatePlugin.getDefault().getPreferenceStore().getLong(AutomaticUpdateScheduler.MIGRATION_DIALOG_SHOWN);
}
}