diff options
Diffstat (limited to 'src/libs/installer/uninstallercalculator.cpp')
-rw-r--r-- | src/libs/installer/uninstallercalculator.cpp | 207 |
1 files changed, 92 insertions, 115 deletions
diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp index c717f6550..de753f71a 100644 --- a/src/libs/installer/uninstallercalculator.cpp +++ b/src/libs/installer/uninstallercalculator.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2022 The Qt Company Ltd. +** Copyright (C) 2023 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -32,8 +32,6 @@ #include "packagemanagercore.h" #include "globals.h" -#include <QDebug> - namespace QInstaller { /*! @@ -42,57 +40,73 @@ namespace QInstaller { \internal */ -UninstallerCalculator::UninstallerCalculator(const QList<Component *> &installedComponents - , PackageManagerCore *core +UninstallerCalculator::UninstallerCalculator(PackageManagerCore *core , const AutoDependencyHash &autoDependencyComponentHash - , const DependencyHash &dependencyComponentHash + , const LocalDependencyHash &localDependencyComponentHash , const QStringList &localVirtualComponents) - : m_installedComponents(installedComponents) - , m_core(core) + : CalculatorBase(core) , m_autoDependencyComponentHash(autoDependencyComponentHash) - , m_dependencyComponentHash(dependencyComponentHash) + , m_localDependencyComponentHash(localDependencyComponentHash) , m_localVirtualComponents(localVirtualComponents) { } -QSet<Component *> UninstallerCalculator::componentsToUninstall() const +UninstallerCalculator::~UninstallerCalculator() { - return m_componentsToUninstall; } -void UninstallerCalculator::appendComponentToUninstall(Component *component, const bool reverse) +bool UninstallerCalculator::solveComponent(Component *component, const QString &version) { + Q_UNUSED(version) + if (!component) - return; + return true; if (!component->isInstalled()) - return; + return true; - if (m_dependencyComponentHash.contains(component->name())) { - const QStringList &dependencies = PackageManagerCore::parseNames(m_dependencyComponentHash.value(component->name())); + if (m_localDependencyComponentHash.contains(component->name())) { + const QStringList &dependencies = PackageManagerCore::parseNames(m_localDependencyComponentHash.value(component->name())); for (const QString &dependencyComponent : dependencies) { Component *depComponent = m_core->componentByName(dependencyComponent); - if (depComponent && depComponent->isInstalled() && !m_componentsToUninstall.contains(depComponent)) { - appendComponentToUninstall(depComponent, reverse); - insertUninstallReason(depComponent, UninstallerCalculator::Dependent, component->name()); - } else if (reverse) { - appendComponentToUninstall(depComponent, true); - } + if (!depComponent || !depComponent->isInstalled()) + continue; + + if (m_resolvedComponents.contains(depComponent) + || m_core->orderedComponentsToInstall().contains(depComponent)) { + // Component is already selected for uninstall or update + continue; + } + + if (depComponent->isEssential() || depComponent->forcedInstallation()) { + const QString errorMessage = QCoreApplication::translate("InstallerCalculator", + "Impossible dependency resolution detected. Forced install component \"%1\" would be uninstalled " + "because its dependency \"%2\" is marked for uninstallation with reason: \"%3\".") + .arg(depComponent->name(), component->name(), resolutionText(component)); + + qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage; + m_errorString.append(errorMessage); + return false; + } + // Resolve also all cascading dependencies + if (!solveComponent(depComponent)) + return false; + + insertResolution(depComponent, Resolution::Dependent, component->name()); } } - if (reverse) { - m_componentsToUninstall.remove(component); - } else { - m_componentsToUninstall.insert(component); - } + + m_resolvedComponents.append(component); + return true; } -void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components, const bool reverse) +bool UninstallerCalculator::solve(const QList<Component*> &components) { - if (components.isEmpty()) - return; - foreach (Component *component, components) - appendComponentToUninstall(component, reverse); + foreach (Component *component, components) { + if (!solveComponent(component)) + return false; + } + QList<Component*> autoDependOnList; // All regular dependees are resolved. Now we are looking for auto depend on components. for (Component *component : components) { @@ -104,120 +118,83 @@ void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> Component *autoDepComponent = m_core->componentByName(autoDependencyComponent); if (autoDepComponent && autoDepComponent->isInstalled()) { // A component requested auto uninstallation, keep it to resolve their dependencies as well. - if (reverse) { - autoDependOnList.append(autoDepComponent); - } else if (!m_componentsToUninstall.contains(autoDepComponent)) { - insertUninstallReason(autoDepComponent, UninstallerCalculator::AutoDependent, component->name()); + if (!m_resolvedComponents.contains(autoDepComponent)) { + insertResolution(autoDepComponent, Resolution::Automatic, component->name()); autoDepComponent->setInstallAction(ComponentModelHelper::AutodependUninstallation); autoDependOnList.append(autoDepComponent); } } } } + if (!autoDependOnList.isEmpty()) - appendComponentsToUninstall(autoDependOnList, reverse); + solve(autoDependOnList); else - appendVirtualComponentsToUninstall(reverse); -} + appendVirtualComponentsToUninstall(); -void UninstallerCalculator::removeComponentsFromUnInstall(const QList<Component*> &components) -{ - appendComponentsToUninstall(components, true); -} - -void UninstallerCalculator::insertUninstallReason(Component *component, const UninstallReasonType uninstallReason, - const QString &referencedComponentName) -{ - // keep the first reason - if (m_toUninstallComponentIdReasonHash.contains(component->name())) - return; - m_toUninstallComponentIdReasonHash.insert(component->name(), - qMakePair(uninstallReason, referencedComponentName)); + return true; } -QString UninstallerCalculator::uninstallReason(Component *component) const +QString UninstallerCalculator::resolutionText(Component *component) const { - UninstallerCalculator::UninstallReasonType reason = uninstallReasonType(component); + Resolution reason = resolutionType(component); switch (reason) { - case Selected: + case Resolution::Selected: return QCoreApplication::translate("UninstallerCalculator", "Deselected Components:"); - case Replaced: + case Resolution::Replaced: return QCoreApplication::translate("UninstallerCalculator", "Components replaced " - "by \"%1\":").arg(uninstallReasonReferencedComponent(component)); - case VirtualDependent: + "by \"%1\":").arg(referencedComponent(component)); + case Resolution::VirtualDependent: return QCoreApplication::translate("UninstallerCalculator", "Removing virtual components without existing dependencies:"); - case Dependent: + case Resolution::Dependent: return QCoreApplication::translate("UninstallerCalculator", "Components " - "dependency \"%1\" removed:").arg(uninstallReasonReferencedComponent(component)); - case AutoDependent: + "dependency \"%1\" removed:").arg(referencedComponent(component)); + case Resolution::Automatic: return QCoreApplication::translate("UninstallerCalculator", "Components " - "autodependency \"%1\" removed:").arg(uninstallReasonReferencedComponent(component)); + "autodependency \"%1\" removed:").arg(referencedComponent(component)); + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid uninstall resolution detected!"); } return QString(); } -UninstallerCalculator::UninstallReasonType UninstallerCalculator::uninstallReasonType(Component *c) const -{ - return m_toUninstallComponentIdReasonHash.value(c->name()).first; -} - -QString UninstallerCalculator::uninstallReasonReferencedComponent(Component *component) const -{ - return m_toUninstallComponentIdReasonHash.value(component->name()).second; -} - -void UninstallerCalculator::appendVirtualComponentsToUninstall(const bool reverse) +void UninstallerCalculator::appendVirtualComponentsToUninstall() { QList<Component*> unneededVirtualList; - // Check for virtual components without dependees - if (reverse) { - for (Component *reverseFromUninstall : qAsConst(m_virtualComponentsForReverse)) { - if (m_componentsToUninstall.contains(reverseFromUninstall)) { - bool required = false; - // Check if installed or about to be updated -packages are dependant on the package - const QList<Component*> installDependants = m_core->installDependants(reverseFromUninstall); - for (Component *dependant : installDependants) { - if (dependant->isInstalled() && !m_componentsToUninstall.contains(dependant)) { - required = true; - break; - } - } - if (required) { - unneededVirtualList.append(reverseFromUninstall); - } - } - } - } else { - for (const QString &componentName : qAsConst(m_localVirtualComponents)) { - Component *virtualComponent = m_core->componentByName(componentName); - if (virtualComponent->isInstalled() && !m_componentsToUninstall.contains(virtualComponent)) { - // Components with auto dependencies were handled in the previous step - if (!virtualComponent->autoDependencies().isEmpty() || virtualComponent->forcedInstallation()) - continue; - - bool required = false; - // Check if installed or about to be updated -packages are dependant on the package - const QList<Component*> installDependants = m_core->installDependants(virtualComponent); - for (Component *dependant : installDependants) { - if (dependant->isInstalled() && !m_componentsToUninstall.contains(dependant)) { - required = true; - break; - } - } - if (!required) { - unneededVirtualList.append(virtualComponent); - m_virtualComponentsForReverse.append(virtualComponent); - insertUninstallReason(virtualComponent, UninstallerCalculator::VirtualDependent); - } - } + for (const QString &componentName : qAsConst(m_localVirtualComponents)) { + Component *virtualComponent = m_core->componentByName(componentName, m_core->components(PackageManagerCore::ComponentType::All)); + if (!virtualComponent) + continue; + + if (virtualComponent->isInstalled() && !m_resolvedComponents.contains(virtualComponent)) { + // Components with auto dependencies were handled in the previous step + if (!virtualComponent->autoDependencies().isEmpty() || virtualComponent->forcedInstallation()) + continue; + + if (!isRequiredVirtualPackage(virtualComponent)) { + unneededVirtualList.append(virtualComponent); + insertResolution(virtualComponent, Resolution::VirtualDependent); + } } } if (!unneededVirtualList.isEmpty()) - appendComponentsToUninstall(unneededVirtualList, reverse); + solve(unneededVirtualList); +} + +bool UninstallerCalculator::isRequiredVirtualPackage(Component *component) +{ + const QStringList localInstallDependents = m_core->localDependenciesToComponent(component); + for (const QString &dependent : localInstallDependents) { + Component *comp = m_core->componentByName(dependent); + if (!m_resolvedComponents.contains(comp)) { + return true; + } + } + return m_core->isDependencyForRequestedComponent(component); } } // namespace QInstaller |