blob: a4fed80a42cf9c20bf7da5eb7d11918428b8178c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.equinox.internal.p2.ui;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.provisional.p2.director.*;
import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.internal.provisional.p2.ui.*;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
/**
* This class analyzes a profile change request and the resultant provisioning plan,
* and reports problems in a way that can be communicated to a user.
*
* @since 3.5
*/
public class PlanAnalyzer {
public static IStatus getStatus(int statusCode, IInstallableUnit affectedIU) {
switch (statusCode) {
case IStatusCodes.PROFILE_CHANGE_ALTERED :
return new MultiStatus(ProvUIActivator.PLUGIN_ID, statusCode, ProvUIMessages.PlanStatusHelper_RequestAltered, null);
case IStatusCodes.ALTERED_IMPLIED_UPDATE :
return new Status(IStatus.INFO, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanStatusHelper_ImpliedUpdate, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_IGNORED_IMPLIED_UPDATE :
return new Status(IStatus.WARNING, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanAnalyzer_LockedImpliedUpdate0, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_IGNORED_IMPLIED_DOWNGRADE :
return new Status(IStatus.WARNING, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanStatusHelper_IgnoringImpliedDowngrade, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_IGNORED_ALREADY_INSTALLED :
return new Status(IStatus.WARNING, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanStatusHelper_AlreadyInstalled, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_PARTIAL_INSTALL :
return new Status(IStatus.INFO, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanAnalyzer_PartialInstall, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_PARTIAL_UNINSTALL :
return new Status(IStatus.INFO, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanAnalyzer_PartialUninstall, getIUString(affectedIU)), null);
case IStatusCodes.UNEXPECTED_NOTHING_TO_DO :
return new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanStatusHelper_NothingToDo, getIUString(affectedIU)), null);
case IStatusCodes.NOTHING_TO_UPDATE :
return new Status(IStatus.INFO, ProvUIActivator.PLUGIN_ID, statusCode, ProvUIMessages.UpdateOperation_NothingToUpdate, null);
case IStatusCodes.OPERATION_ALREADY_IN_PROGRESS :
return new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, statusCode, ProvUIMessages.PlanStatusHelper_AnotherOperationInProgress, null);
default :
return new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, statusCode, NLS.bind(ProvUIMessages.PlanStatusHelper_UnexpectedError, new Integer(statusCode), getIUString(affectedIU)), null);
}
}
public static MultiStatus getProfileChangeAlteredStatus() {
return (MultiStatus) getStatus(IStatusCodes.PROFILE_CHANGE_ALTERED, null);
}
public static ResolutionResult computeResolutionResult(ProfileChangeRequest originalRequest, ProvisioningPlan plan, MultiStatus originalStatus) {
Assert.isNotNull(originalRequest);
Assert.isNotNull(plan);
Assert.isNotNull(originalStatus);
ResolutionResult report = new ResolutionResult();
// If the plan was canceled, no further analysis is needed
if (plan.getStatus().getSeverity() == IStatus.CANCEL) {
report.addSummaryStatus(plan.getStatus());
return report;
}
// If the plan requires install handler support, we want to open the old update UI and
// cancel this operation
if (UpdateManagerCompatibility.requiresInstallHandlerSupport(plan)) {
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
public void run() {
Shell shell = ProvUI.getDefaultParentShell();
MessageDialog dialog = new MessageDialog(shell, ProvUIMessages.PlanStatusHelper_UpdateManagerPromptTitle, null, ProvUIMessages.PlanStatusHelper_PromptForUpdateManagerUI, MessageDialog.WARNING, new String[] {ProvUIMessages.PlanStatusHelper_Launch, IDialogConstants.CANCEL_LABEL}, 0);
if (dialog.open() == 0)
BusyIndicator.showWhile(shell.getDisplay(), new Runnable() {
public void run() {
UpdateManagerCompatibility.openInstaller();
}
});
}
});
report.addSummaryStatus(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, ProvUIMessages.PlanStatusHelper_RequiresUpdateManager));
}
if (nothingToDo(originalRequest)) {
report.addSummaryStatus(getStatus(IStatusCodes.UNEXPECTED_NOTHING_TO_DO, null));
IStatus[] details = originalStatus.getChildren();
for (int i = 0; i < details.length; i++)
report.addSummaryStatus(details[i]);
return report;
}
// If there was already some status supplied before resolution, this should get included
// with the report. For example, this might contain information about the profile request
// being altered before resolution began.
if (originalStatus != null && originalStatus.getChildren().length > 0) {
report.addSummaryStatus(originalStatus);
}
// If the overall plan had a non-OK status, capture that in the report.
if (!plan.getStatus().isOK())
report.addSummaryStatus(plan.getStatus());
// Now we compare what was requested with what is going to happen.
// In the long run, when a RequestStatus can provide actual explanation/status
// about failures, we might want to add this information to the overall status.
// As it stands now, if the provisioning plan is in error, that info is more detailed
// than the request status. So we will only add request status info to the overall
// status when the overall status is not in error.
if (plan.getStatus().getSeverity() != IStatus.ERROR) {
IInstallableUnit[] iusAdded = originalRequest.getAddedInstallableUnits();
for (int i = 0; i < iusAdded.length; i++) {
RequestStatus rs = plan.getRequestStatus(iusAdded[i]);
if (rs.getSeverity() == IStatus.ERROR) {
// This is a serious error so it must also appear in the overall status
IStatus fail = new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, IStatusCodes.ALTERED_IGNORED_INSTALL_REQUEST, NLS.bind(ProvUIMessages.PlanAnalyzer_IgnoringInstall, getIUString(iusAdded[i])), null);
report.addStatus(iusAdded[i], fail);
report.addSummaryStatus(fail);
}
}
IInstallableUnit[] iusRemoved = originalRequest.getRemovedInstallableUnits();
for (int i = 0; i < iusRemoved.length; i++) {
RequestStatus rs = plan.getRequestStatus(iusRemoved[i]);
if (rs.getSeverity() == IStatus.ERROR) {
// TODO see https://bugs.eclipse.org/bugs/show_bug.cgi?id=255984
// We are making assumptions here about why the planner chose to ignore an uninstall.
// Assume it could not be uninstalled because of some other dependency, yet the planner did not view
// this as an error. So we inform the user that we can only uninstall parts of it. The root property will be
// removed per the original change request.
IStatus fail = new Status(IStatus.INFO, ProvUIActivator.PLUGIN_ID, IStatusCodes.ALTERED_PARTIAL_UNINSTALL, NLS.bind(ProvUIMessages.PlanAnalyzer_PartialUninstall, getIUString(iusRemoved[i])), null);
report.addStatus(iusRemoved[i], fail);
report.addSummaryStatus(fail);
}
}
}
// Now process the side effects
Map sideEffects = plan.getSideEffectChanges();
Iterator iusWithSideEffects = sideEffects.keySet().iterator();
while (iusWithSideEffects.hasNext()) {
IInstallableUnit iu = (IInstallableUnit) iusWithSideEffects.next();
RequestStatus rs = (RequestStatus) sideEffects.get(iu);
if (rs.getInitialRequestType() == RequestStatus.ADDED) {
report.addStatus(iu, new Status(rs.getSeverity(), ProvUIActivator.PLUGIN_ID, IStatusCodes.ALTERED_SIDE_EFFECT_INSTALL, NLS.bind(ProvUIMessages.PlanAnalyzer_SideEffectInstall, getIUString(iu)), null));
} else {
report.addStatus(iu, new Status(rs.getSeverity(), ProvUIActivator.PLUGIN_ID, IStatusCodes.ALTERED_SIDE_EFFECT_REMOVE, NLS.bind(ProvUIMessages.PlanAnalyzer_SideEffectUninstall, getIUString(iu)), null));
}
}
return report;
}
private static String getIUString(IInstallableUnit iu) {
if (iu == null)
return ProvUIMessages.PlanStatusHelper_Items;
// Get the iu name in the default locale
String name = IUPropertyUtils.getIUProperty(iu, IInstallableUnit.PROP_NAME);
if (name != null)
return name;
return iu.getId();
}
private static boolean nothingToDo(ProfileChangeRequest request) {
return request.getAddedInstallableUnits().length == 0 && request.getRemovedInstallableUnits().length == 0 && request.getInstallableUnitProfilePropertiesToAdd().size() == 0 && request.getInstallableUnitProfilePropertiesToRemove().size() == 0;
}
}