blob: 3b2d72a1c24be2ee3cece402c0a90b22975a6a58 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2010 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
* Sonatype, Inc. - ongoing development
******************************************************************************/
package org.eclipse.equinox.internal.p2.operations;
import java.util.Collection;
import java.util.Map.Entry;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.provisional.p2.director.*;
import org.eclipse.equinox.p2.engine.IProvisioningPlan;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.osgi.util.NLS;
/**
* 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.NOTHING_TO_UPDATE :
return new Status(IStatus.INFO, Activator.ID, statusCode, Messages.PlanAnalyzer_NoUpdates, null);
case IStatusCodes.PROFILE_CHANGE_ALTERED :
return new MultiStatus(Activator.ID, statusCode, Messages.PlanAnalyzer_RequestAltered, null);
case IStatusCodes.ALTERED_IMPLIED_UPDATE :
return new Status(IStatus.INFO, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_ImpliedUpdate, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_IGNORED_IMPLIED_UPDATE :
return new Status(IStatus.WARNING, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_LockedImpliedUpdate0, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_IGNORED_IMPLIED_DOWNGRADE :
return new Status(IStatus.WARNING, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_IgnoringImpliedDowngrade, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_IGNORED_ALREADY_INSTALLED :
return new Status(IStatus.WARNING, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_AlreadyInstalled, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_PARTIAL_INSTALL :
return new Status(IStatus.INFO, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_PartialInstall, getIUString(affectedIU)), null);
case IStatusCodes.ALTERED_PARTIAL_UNINSTALL :
return new Status(IStatus.INFO, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_PartialUninstall, getIUString(affectedIU)), null);
case IStatusCodes.UNEXPECTED_NOTHING_TO_DO :
return new Status(IStatus.ERROR, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_NothingToDo, getIUString(affectedIU)), null);
case IStatusCodes.OPERATION_ALREADY_IN_PROGRESS :
return new Status(IStatus.ERROR, Activator.ID, statusCode, Messages.PlanAnalyzer_AnotherOperationInProgress, null);
default :
return new Status(IStatus.ERROR, Activator.ID, statusCode, NLS.bind(Messages.PlanAnalyzer_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, IProvisioningPlan 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 (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.
PlannerStatus plannerStatus = plan.getStatus() instanceof PlannerStatus ? (PlannerStatus) plan.getStatus() : null;
// If there is no additional plannerStatus details just return the report
if (plannerStatus == null)
return report;
if (plan.getStatus().getSeverity() != IStatus.ERROR) {
Collection<IInstallableUnit> iusAdded = originalRequest.getAdditions();
for (IInstallableUnit added : iusAdded) {
RequestStatus rs = plannerStatus.getRequestChanges().get(added);
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, Activator.ID, IStatusCodes.ALTERED_IGNORED_INSTALL_REQUEST, NLS.bind(Messages.PlanAnalyzer_IgnoringInstall, getIUString(added)), null);
report.addStatus(added, fail);
report.addSummaryStatus(fail);
}
}
Collection<IInstallableUnit> iusRemoved = originalRequest.getRemovals();
for (IInstallableUnit removed : iusRemoved) {
RequestStatus rs = plannerStatus.getRequestChanges().get(removed);
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, Activator.ID, IStatusCodes.ALTERED_PARTIAL_UNINSTALL, NLS.bind(Messages.PlanAnalyzer_PartialUninstall, getIUString(removed)), null);
report.addStatus(removed, fail);
report.addSummaryStatus(fail);
}
}
}
// Now process the side effects
if (plannerStatus.getRequestSideEffects() != null) {
for (Entry<IInstallableUnit, RequestStatus> entry : plannerStatus.getRequestSideEffects().entrySet()) {
IInstallableUnit iu = entry.getKey();
RequestStatus rs = entry.getValue();
if (rs.getInitialRequestType() == RequestStatus.ADDED) {
report.addStatus(iu, new Status(rs.getSeverity(), Activator.ID, IStatusCodes.ALTERED_SIDE_EFFECT_INSTALL, NLS.bind(Messages.PlanAnalyzer_SideEffectInstall, getIUString(iu)), null));
} else {
report.addStatus(iu, new Status(rs.getSeverity(), Activator.ID, IStatusCodes.ALTERED_SIDE_EFFECT_REMOVE, NLS.bind(Messages.PlanAnalyzer_SideEffectUninstall, getIUString(iu)), null));
}
}
}
return report;
}
private static String getIUString(IInstallableUnit iu) {
if (iu == null)
return Messages.PlanAnalyzer_Items;
// Get the iu name in the default locale
String name = iu.getProperty(IInstallableUnit.PROP_NAME, null);
if (name != null)
return name;
return iu.getId();
}
private static boolean nothingToDo(ProfileChangeRequest request) {
return request.getAdditions().size() == 0 && request.getRemovals().size() == 0 && request.getInstallableUnitProfilePropertiesToAdd().size() == 0 && request.getInstallableUnitProfilePropertiesToRemove().size() == 0;
}
}