summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/uninstallercalculator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/installer/uninstallercalculator.cpp')
-rw-r--r--src/libs/installer/uninstallercalculator.cpp207
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