summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2023-01-10 16:16:41 +0200
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2023-02-08 16:37:22 +0200
commit399c010235bdb9079005930e125f301f53153808 (patch)
treeaeb0bea9d6530930ccf60a6e26bab3652e8a5647
parent3ef3edd5206552dd037774594901780a4c817687 (diff)
Add common base class for the installer calculator classes
As the classes already share similar features and public API, it would make sense to inherit a common abstract class to define the interface. Change-Id: I7ed278b1b049b7ec12c4401e55fdf39306b0ab85 Reviewed-by: Katja Marttila <katja.marttila@qt.io>
-rw-r--r--src/libs/installer/calculatorbase.cpp76
-rw-r--r--src/libs/installer/calculatorbase.h84
-rw-r--r--src/libs/installer/installer.pro2
-rw-r--r--src/libs/installer/installercalculator.cpp84
-rw-r--r--src/libs/installer/installercalculator.h40
-rw-r--r--src/libs/installer/packagemanagercore.cpp24
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp14
-rw-r--r--src/libs/installer/uninstallercalculator.cpp85
-rw-r--r--src/libs/installer/uninstallercalculator.h36
-rw-r--r--tests/auto/installer/solver/tst_solver.cpp50
10 files changed, 286 insertions, 209 deletions
diff --git a/src/libs/installer/calculatorbase.cpp b/src/libs/installer/calculatorbase.cpp
new file mode 100644
index 000000000..4f1732677
--- /dev/null
+++ b/src/libs/installer/calculatorbase.cpp
@@ -0,0 +1,76 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "calculatorbase.h"
+
+#include "component.h"
+
+namespace QInstaller {
+
+CalculatorBase::CalculatorBase(PackageManagerCore *core)
+ : m_core(core)
+{
+}
+
+CalculatorBase::~CalculatorBase()
+{
+}
+
+void CalculatorBase::insertResolution(Component *component, const Resolution resolutionType
+ , const QString &referencedComponent)
+{
+ // Keep the first reason
+ if (m_componentNameResolutionHash.contains(component->name()))
+ return;
+
+ m_componentNameResolutionHash.insert(component->name(),
+ QPair<Resolution, QString>(resolutionType, referencedComponent));
+}
+
+QList<Component *> CalculatorBase::resolvedComponents() const
+{
+ return m_resolvedComponents;
+}
+
+CalculatorBase::Resolution CalculatorBase::resolutionType(Component *component) const
+{
+ return m_componentNameResolutionHash.value(component->name()).first;
+}
+
+QString CalculatorBase::error() const
+{
+ return m_errorString;
+}
+
+QString CalculatorBase::referencedComponent(Component *component) const
+{
+ return m_componentNameResolutionHash.value(component->name()).second;
+}
+
+} // namespace QInstaller
+
diff --git a/src/libs/installer/calculatorbase.h b/src/libs/installer/calculatorbase.h
new file mode 100644
index 000000000..baf51c5b4
--- /dev/null
+++ b/src/libs/installer/calculatorbase.h
@@ -0,0 +1,84 @@
+/**************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef CALCULATORBASE_H
+#define CALCULATORBASE_H
+
+#include "installer_global.h"
+
+#include <QList>
+#include <QString>
+#include <QMetaEnum>
+
+namespace QInstaller {
+
+class Component;
+class PackageManagerCore;
+
+class INSTALLER_EXPORT CalculatorBase
+{
+public:
+ enum class Resolution {
+ Selected = 0, // "Selected Component(s) without Dependencies" / "Deselected Component(s)"
+ Replaced, // "Component(s) replaced by other components"
+ VirtualDependent, // "No dependencies to virtual component"
+ Dependent, // "Added as dependency for %1." / "Removed as dependency component is removed"
+ Automatic, // "Component(s) added as automatic dependencies" / "Removed as autodependency component is removed"
+ Resolved // "Component(s) that have resolved Dependencies"
+ };
+
+ CalculatorBase(PackageManagerCore *core);
+ virtual ~CalculatorBase() = 0;
+
+ virtual bool solve(const QList<Component *> &components) = 0;
+ void insertResolution(Component *component, const Resolution resolutionType,
+ const QString &referencedComponent = QString());
+
+ QList<Component *> resolvedComponents() const;
+ virtual QString resolutionText(Component *component) const = 0;
+ Resolution resolutionType(Component *component) const;
+
+ QString error() const;
+
+protected:
+ virtual bool solveComponent(Component *component, const QString &version = QString()) = 0;
+ QString referencedComponent(Component *component) const;
+
+protected:
+ PackageManagerCore *m_core;
+ QString m_errorString;
+
+ QList<Component *> m_resolvedComponents;
+ QHash<QString, QPair<Resolution, QString> > m_componentNameResolutionHash;
+};
+
+} // namespace QInstaller
+
+Q_DECLARE_METATYPE(QInstaller::CalculatorBase::Resolution)
+
+#endif // CALCULATORBASE_H
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro
index 0de80b064..5a58968ee 100644
--- a/src/libs/installer/installer.pro
+++ b/src/libs/installer/installer.pro
@@ -46,6 +46,7 @@ greaterThan(QT_MAJOR_VERSION, 5):QT += core5compat
HEADERS += packagemanagercore.h \
aspectratiolabel.h \
+ calculatorbase.h \
componentsortfilterproxymodel.h \
concurrentoperationrunner.h \
genericdatacache.h \
@@ -149,6 +150,7 @@ SOURCES += packagemanagercore.cpp \
abstractarchive.cpp \
archivefactory.cpp \
aspectratiolabel.cpp \
+ calculatorbase.cpp \
concurrentoperationrunner.cpp \
directoryguard.cpp \
fileguard.cpp \
diff --git a/src/libs/installer/installercalculator.cpp b/src/libs/installer/installercalculator.cpp
index 77989e3f8..105e99fd8 100644
--- a/src/libs/installer/installercalculator.cpp
+++ b/src/libs/installer/installercalculator.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.
@@ -42,48 +42,38 @@ namespace QInstaller {
*/
InstallerCalculator::InstallerCalculator(PackageManagerCore *core, const AutoDependencyHash &autoDependencyComponentHash)
- : m_core(core)
+ : CalculatorBase(core)
, m_autoDependencyComponentHash(autoDependencyComponentHash)
{
}
-InstallerCalculator::InstallReasonType InstallerCalculator::installReasonType(const Component *c) const
+InstallerCalculator::~InstallerCalculator()
{
- return m_toInstallComponentIdReasonHash.value(c->name(),
- qMakePair(InstallerCalculator::Selected, QString())).first;
}
-QString InstallerCalculator::installReason(const Component *component) const
+QString InstallerCalculator::resolutionText(Component *component) const
{
- InstallerCalculator::InstallReasonType reason = installReasonType(component);
+ const Resolution reason = resolutionType(component);
switch (reason) {
- case Automatic:
+ case Resolution::Automatic:
return QCoreApplication::translate("InstallerCalculator",
"Components added as automatic dependencies:");
- case Dependent:
+ case Resolution::Dependent:
return QCoreApplication::translate("InstallerCalculator", "Components added as "
- "dependency for \"%1\":").arg(installReasonReferencedComponent(component));
- case Resolved:
+ "dependency for \"%1\":").arg(referencedComponent(component));
+ case Resolution::Resolved:
return QCoreApplication::translate("InstallerCalculator",
"Components that have resolved dependencies:");
- case Selected:
+ case Resolution::Selected:
return QCoreApplication::translate("InstallerCalculator",
"Selected components without dependencies:");
+ default:
+ Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid install resolution detected!");
}
return QString();
}
-QList<Component*> InstallerCalculator::orderedComponentsToInstall() const
-{
- return m_orderedComponentsToInstall;
-}
-
-QString InstallerCalculator::componentsToInstallError() const
-{
- return m_componentsToInstallError;
-}
-
-bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &components)
+bool InstallerCalculator::solve(const QList<Component *> &components)
{
if (components.isEmpty())
return true;
@@ -95,54 +85,38 @@ bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &co
if (m_toInstallComponentIds.contains(component->name())) {
const QString errorMessage = recursionError(component);
qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
- m_componentsToInstallError.append(errorMessage);
+ m_errorString.append(errorMessage);
Q_ASSERT_X(!m_toInstallComponentIds.contains(component->name()), Q_FUNC_INFO,
qPrintable(errorMessage));
return false;
}
if (component->currentDependencies().isEmpty())
- realAppendToInstallComponents(component);
+ addComponentForInstall(component);
else
notAppendedComponents.append(component);
}
for (Component *component : qAsConst(notAppendedComponents)) {
- if (!appendComponentToInstall(component))
+ if (!solveComponent(component))
return false;
}
// All regular dependencies are resolved. Now we are looking for auto depend on components.
QSet<Component *> foundAutoDependOnList = autodependencyComponents();
-
if (!foundAutoDependOnList.isEmpty())
- return appendComponentsToInstall(foundAutoDependOnList.values());
- return true;
-}
+ return solve(foundAutoDependOnList.values());
-QString InstallerCalculator::installReasonReferencedComponent(const Component *component) const
-{
- return m_toInstallComponentIdReasonHash.value(component->name(),
- qMakePair(InstallerCalculator::Selected, QString())).second;
-}
-
-void InstallerCalculator::insertInstallReason(Component *component,
- InstallReasonType installReason, const QString &referencedComponentName)
-{
- // keep the first reason
- if (m_toInstallComponentIdReasonHash.contains(component->name()))
- return;
- m_toInstallComponentIdReasonHash.insert(component->name(),
- qMakePair(installReason, referencedComponentName));
+ return true;
}
-void InstallerCalculator::realAppendToInstallComponents(Component *component, const QString &version)
+void InstallerCalculator::addComponentForInstall(Component *component, const QString &version)
{
if (!m_componentsForAutodepencencyCheck.contains(component))
m_componentsForAutodepencencyCheck.append(component);
if (!component->isInstalled(version) || (m_core->isUpdater() && component->isUpdateAvailable())) {
- m_orderedComponentsToInstall.append(component);
+ m_resolvedComponents.append(component);
m_toInstallComponentIds.insert(component->name());
}
}
@@ -150,10 +124,10 @@ void InstallerCalculator::realAppendToInstallComponents(Component *component, co
QString InstallerCalculator::recursionError(Component *component) const
{
return QCoreApplication::translate("InstallerCalculator", "Recursion detected, component \"%1\" "
- "already added with reason: \"%2\"").arg(component->name(), installReason(component));
+ "already added with reason: \"%2\"").arg(component->name(), resolutionText(component));
}
-bool InstallerCalculator::appendComponentToInstall(Component *component, const QString &version)
+bool InstallerCalculator::solveComponent(Component *component, const QString &version)
{
const QStringList dependenciesList = component->currentDependencies();
QString requiredDependencyVersion = version;
@@ -166,7 +140,7 @@ bool InstallerCalculator::appendComponentToInstall(Component *component, const Q
"Cannot find missing dependency \"%1\" for \"%2\".").arg(dependencyComponentName,
component->name());
qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
- m_componentsToInstallError.append(errorMessage);
+ m_errorString.append(errorMessage);
if (component->packageManagerCore()->settings().allowUnstableComponents()) {
component->setUnstable(Component::UnstableError::MissingDependency, errorMessage);
continue;
@@ -204,24 +178,24 @@ bool InstallerCalculator::appendComponentToInstall(Component *component, const Q
if (m_visitedComponents.value(component).contains(dependencyComponent)) {
const QString errorMessage = recursionError(component);
qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
- m_componentsToInstallError = errorMessage;
+ m_errorString = errorMessage;
Q_ASSERT_X(!m_visitedComponents.value(component).contains(dependencyComponent),
Q_FUNC_INFO, qPrintable(errorMessage));
return false;
}
m_visitedComponents[component].insert(dependencyComponent);
// add needed dependency components to the next run
- insertInstallReason(dependencyComponent, InstallerCalculator::Dependent,
+ insertResolution(dependencyComponent, Resolution::Dependent,
component->name());
- if (!appendComponentToInstall(dependencyComponent, requiredDependencyVersion))
+ if (!solveComponent(dependencyComponent, requiredDependencyVersion))
return false;
}
}
if (!m_toInstallComponentIds.contains(component->name())) {
- realAppendToInstallComponents(component, requiredDependencyVersion);
- insertInstallReason(component, InstallerCalculator::Resolved);
+ addComponentForInstall(component, requiredDependencyVersion);
+ insertResolution(component, Resolution::Resolved);
}
return true;
}
@@ -253,7 +227,7 @@ QSet<Component *> InstallerCalculator::autodependencyComponents()
// are other autodependencies as well
if (autoDependComponent->isAutoDependOn(m_toInstallComponentIds)) {
foundAutoDependOnList.insert(autoDependComponent);
- insertInstallReason(autoDependComponent, InstallerCalculator::Automatic);
+ insertResolution(autoDependComponent, Resolution::Automatic);
}
}
}
diff --git a/src/libs/installer/installercalculator.h b/src/libs/installer/installercalculator.h
index 422de439c..339dbeffd 100644
--- a/src/libs/installer/installercalculator.h
+++ b/src/libs/installer/installercalculator.h
@@ -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.
@@ -30,6 +30,7 @@
#include "installer_global.h"
#include "qinstallerglobal.h"
+#include "calculatorbase.h"
#include <QHash>
#include <QList>
@@ -41,51 +42,30 @@ namespace QInstaller {
class Component;
class PackageManagerCore;
-class INSTALLER_EXPORT InstallerCalculator
+class INSTALLER_EXPORT InstallerCalculator : public CalculatorBase
{
public:
InstallerCalculator(PackageManagerCore *core, const AutoDependencyHash &autoDependencyComponentHash);
+ ~InstallerCalculator();
- enum InstallReasonType
- {
- Selected, // "Selected Component(s) without Dependencies"
- Automatic, // "Component(s) added as automatic dependencies"
- Dependent, // "Added as dependency for %1."
- Resolved // "Component(s) that have resolved Dependencies"
- };
-
- InstallReasonType installReasonType(const Component *component) const;
- QString installReason(const Component *component) const;
- QList<Component*> orderedComponentsToInstall() const;
- QString componentsToInstallError() const;
- bool appendComponentsToInstall(const QList<Component*> &components);
+ bool solve(const QList<Component *> &components) override;
+ QString resolutionText(Component *component) const override;
private:
- QString installReasonReferencedComponent(const Component *component) const;
- void insertInstallReason(Component *component,
- InstallReasonType installReasonType,
- const QString &referencedComponentName = QString());
- void realAppendToInstallComponents(Component *component, const QString &version = QString());
- bool appendComponentToInstall(Component *components, const QString &version = QString());
+ bool solveComponent(Component *component, const QString &version = QString()) override;
+
+ void addComponentForInstall(Component *component, const QString &version = QString());
QSet<Component *> autodependencyComponents();
QString recursionError(Component *component) const;
private:
- PackageManagerCore *m_core;
QHash<Component*, QSet<Component*> > m_visitedComponents;
QList<const Component*> m_componentsForAutodepencencyCheck;
QSet<QString> m_toInstallComponentIds; //for faster lookups
- QString m_componentsToInstallError;
- //calculate installation order variables
- QList<Component*> m_orderedComponentsToInstall;
- //we can't use this reason hash as component id hash, because some reasons are ready before
- //the component is added
- QHash<QString, QPair<InstallReasonType, QString> > m_toInstallComponentIdReasonHash;
//Helper hash for quicker search for autodependency components
AutoDependencyHash m_autoDependencyComponentHash;
};
-}
-
+} // namespace QInstaller
#endif // INSTALLERCALCULATOR_H
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index d5758438d..ebefafab6 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -2199,7 +2199,7 @@ bool PackageManagerCore::calculateComponentsToInstall() const
const QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation();
const bool componentsToInstallCalculated =
- d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall);
+ d->installerCalculator()->solve(selectedComponentsToInstall);
emit finishedCalculateComponentsToInstall();
return componentsToInstallCalculated;
@@ -2210,7 +2210,7 @@ bool PackageManagerCore::calculateComponentsToInstall() const
*/
QList<Component*> PackageManagerCore::orderedComponentsToInstall() const
{
- return d->installerCalculator()->orderedComponentsToInstall();
+ return d->installerCalculator()->resolvedComponents();
}
/*!
@@ -2287,15 +2287,15 @@ bool PackageManagerCore::calculateComponentsToUninstall() const
emit aboutCalculateComponentsToUninstall();
d->clearUninstallerCalculator();
- const QList<Component *> componentsToInstallList = d->installerCalculator()->orderedComponentsToInstall();
+ const QList<Component *> componentsToInstallList = d->installerCalculator()->resolvedComponents();
QList<Component *> selectedComponentsToUninstall;
foreach (Component* component, components(PackageManagerCore::ComponentType::Replacements)) {
// Uninstall the component if replacement is selected for install or update
QPair<Component*, Component*> comp = d->componentsToReplace().value(component->name());
- if (comp.first && d->m_installerCalculator->orderedComponentsToInstall().contains(comp.first)) {
- d->uninstallerCalculator()->insertUninstallReason(component,
- UninstallerCalculator::Replaced, comp.first->name());
+ if (comp.first && d->m_installerCalculator->resolvedComponents().contains(comp.first)) {
+ d->uninstallerCalculator()->insertResolution(component,
+ CalculatorBase::Resolution::Replaced, comp.first->name());
selectedComponentsToUninstall.append(comp.second);
}
}
@@ -2304,7 +2304,7 @@ bool PackageManagerCore::calculateComponentsToUninstall() const
selectedComponentsToUninstall.append(component);
}
const bool componentsToUninstallCalculated =
- d->uninstallerCalculator()->appendComponentsToUninstall(selectedComponentsToUninstall);
+ d->uninstallerCalculator()->solve(selectedComponentsToUninstall);
emit finishedCalculateComponentsToUninstall();
return componentsToUninstallCalculated;
@@ -2319,7 +2319,7 @@ bool PackageManagerCore::calculateComponentsToUninstall() const
*/
QList<Component *> PackageManagerCore::componentsToUninstall() const
{
- return d->uninstallerCalculator()->componentsToUninstall().values();
+ return d->uninstallerCalculator()->resolvedComponents();
}
/*!
@@ -2327,7 +2327,7 @@ QList<Component *> PackageManagerCore::componentsToUninstall() const
*/
QString PackageManagerCore::componentsToInstallError() const
{
- return d->installerCalculator()->componentsToInstallError();
+ return d->installerCalculator()->error();
}
/*!
@@ -2335,7 +2335,7 @@ QString PackageManagerCore::componentsToInstallError() const
*/
QString PackageManagerCore::componentsToUninstallError() const
{
- return d->uninstallerCalculator()->componentsToUninstallError();
+ return d->uninstallerCalculator()->error();
}
/*!
@@ -2349,7 +2349,7 @@ QString PackageManagerCore::componentsToUninstallError() const
*/
QString PackageManagerCore::installReason(Component *component) const
{
- return d->installerCalculator()->installReason(component);
+ return d->installerCalculator()->resolutionText(component);
}
/*!
@@ -2365,7 +2365,7 @@ QString PackageManagerCore::installReason(Component *component) const
*/
QString PackageManagerCore::uninstallReason(Component *component) const
{
- return d->uninstallerCalculator()->uninstallReason(component);
+ return d->uninstallerCalculator()->resolutionText(component);
}
/*!
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 7313a2761..a4e5b185d 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -401,10 +401,10 @@ bool PackageManagerCorePrivate::buildComponentTree(QHash<QString, Component*> &c
component->setCheckState(Qt::Checked);
clearInstallerCalculator();
- if (installerCalculator()->appendComponentsToInstall(components.values()) == false) {
- setStatus(PackageManagerCore::Failure, installerCalculator()->componentsToInstallError());
+ if (installerCalculator()->solve(components.values()) == false) {
+ setStatus(PackageManagerCore::Failure, installerCalculator()->error());
MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), QLatin1String("Error"),
- tr("Unresolved dependencies"), installerCalculator()->componentsToInstallError());
+ tr("Unresolved dependencies"), installerCalculator()->error());
return false;
}
@@ -1932,7 +1932,7 @@ bool PackageManagerCorePrivate::runPackageUpdater()
// There is a replacement, but the replacement is not scheduled for update, keep it as well.
if (m_componentsToReplaceUpdaterMode.contains(name)
- && !m_installerCalculator->orderedComponentsToInstall().contains(m_componentsToReplaceUpdaterMode.value(name).first)) {
+ && !m_installerCalculator->resolvedComponents().contains(m_componentsToReplaceUpdaterMode.value(name).first)) {
nonRevertedOperations.append(operation);
continue;
}
@@ -2935,9 +2935,9 @@ void PackageManagerCorePrivate::updateComponentCheckedState()
? ComponentModelHelper::KeepInstalled
: ComponentModelHelper::KeepUninstalled);
}
- for (Component *component : uninstallerCalculator()->componentsToUninstall())
+ for (Component *component : uninstallerCalculator()->resolvedComponents())
component->setInstallAction(ComponentModelHelper::Uninstall);
- for (Component *component : installerCalculator()->orderedComponentsToInstall())
+ for (Component *component : installerCalculator()->resolvedComponents())
component->setInstallAction(ComponentModelHelper::Install);
}
@@ -3062,7 +3062,7 @@ bool PackageManagerCorePrivate::calculateComponentsAndRun()
qCDebug(QInstaller::lcInstallerInstallLog) << "Installation canceled.";
} else if (componentsOk && acceptLicenseAgreements()) {
try {
- loadComponentScripts(installerCalculator()->orderedComponentsToInstall(), true);
+ loadComponentScripts(installerCalculator()->resolvedComponents(), true);
} catch (const Error &error) {
qCWarning(QInstaller::lcInstallerInstallLog) << error.message();
return false;
diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp
index ebfc52efe..de753f71a 100644
--- a/src/libs/installer/uninstallercalculator.cpp
+++ b/src/libs/installer/uninstallercalculator.cpp
@@ -44,25 +44,21 @@ UninstallerCalculator::UninstallerCalculator(PackageManagerCore *core
, const AutoDependencyHash &autoDependencyComponentHash
, const LocalDependencyHash &localDependencyComponentHash
, const QStringList &localVirtualComponents)
- : m_core(core)
+ : CalculatorBase(core)
, m_autoDependencyComponentHash(autoDependencyComponentHash)
, m_localDependencyComponentHash(localDependencyComponentHash)
, m_localVirtualComponents(localVirtualComponents)
{
}
-QSet<Component *> UninstallerCalculator::componentsToUninstall() const
+UninstallerCalculator::~UninstallerCalculator()
{
- return m_componentsToUninstall;
}
-QString UninstallerCalculator::componentsToUninstallError() const
+bool UninstallerCalculator::solveComponent(Component *component, const QString &version)
{
- return m_componentsToUninstallError;
-}
+ Q_UNUSED(version)
-bool UninstallerCalculator::appendComponentToUninstall(Component *component)
-{
if (!component)
return true;
@@ -76,7 +72,7 @@ bool UninstallerCalculator::appendComponentToUninstall(Component *component)
if (!depComponent || !depComponent->isInstalled())
continue;
- if (m_componentsToUninstall.contains(depComponent)
+ if (m_resolvedComponents.contains(depComponent)
|| m_core->orderedComponentsToInstall().contains(depComponent)) {
// Component is already selected for uninstall or update
continue;
@@ -86,28 +82,28 @@ bool UninstallerCalculator::appendComponentToUninstall(Component *component)
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(), uninstallReason(component));
+ .arg(depComponent->name(), component->name(), resolutionText(component));
qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
- m_componentsToUninstallError.append(errorMessage);
+ m_errorString.append(errorMessage);
return false;
}
// Resolve also all cascading dependencies
- if (!appendComponentToUninstall(depComponent))
+ if (!solveComponent(depComponent))
return false;
- insertUninstallReason(depComponent, UninstallerCalculator::Dependent, component->name());
+ insertResolution(depComponent, Resolution::Dependent, component->name());
}
}
- m_componentsToUninstall.insert(component);
+ m_resolvedComponents.append(component);
return true;
}
-bool UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components)
+bool UninstallerCalculator::solve(const QList<Component*> &components)
{
foreach (Component *component, components) {
- if (!appendComponentToUninstall(component))
+ if (!solveComponent(component))
return false;
}
@@ -122,8 +118,8 @@ bool 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 (!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);
}
@@ -132,56 +128,38 @@ bool UninstallerCalculator::appendComponentsToUninstall(const QList<Component*>
}
if (!autoDependOnList.isEmpty())
- appendComponentsToUninstall(autoDependOnList);
+ solve(autoDependOnList);
else
appendVirtualComponentsToUninstall();
return 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));
-}
-
-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()
{
QList<Component*> unneededVirtualList;
@@ -191,20 +169,20 @@ void UninstallerCalculator::appendVirtualComponentsToUninstall()
if (!virtualComponent)
continue;
- if (virtualComponent->isInstalled() && !m_componentsToUninstall.contains(virtualComponent)) {
+ 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);
- insertUninstallReason(virtualComponent, UninstallerCalculator::VirtualDependent);
+ insertResolution(virtualComponent, Resolution::VirtualDependent);
}
}
}
if (!unneededVirtualList.isEmpty())
- appendComponentsToUninstall(unneededVirtualList);
+ solve(unneededVirtualList);
}
bool UninstallerCalculator::isRequiredVirtualPackage(Component *component)
@@ -212,10 +190,11 @@ 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_componentsToUninstall.contains(comp)) {
+ if (!m_resolvedComponents.contains(comp)) {
return true;
}
}
return m_core->isDependencyForRequestedComponent(component);
}
+
} // namespace QInstaller
diff --git a/src/libs/installer/uninstallercalculator.h b/src/libs/installer/uninstallercalculator.h
index b764042aa..24979a9bb 100644
--- a/src/libs/installer/uninstallercalculator.h
+++ b/src/libs/installer/uninstallercalculator.h
@@ -30,6 +30,7 @@
#include "installer_global.h"
#include "qinstallerglobal.h"
+#include "calculatorbase.h"
#include <QHash>
#include <QList>
@@ -41,49 +42,30 @@ namespace QInstaller {
class Component;
class PackageManagerCore;
-class INSTALLER_EXPORT UninstallerCalculator
+class INSTALLER_EXPORT UninstallerCalculator : public CalculatorBase
{
public:
- enum UninstallReasonType
- {
- Selected, // "Deselected Component(s)"
- Replaced, // "Component(s) replaced by other components"
- VirtualDependent, // "No dependencies to virtual component"
- Dependent, // "Removed as dependency component is removed"
- AutoDependent // "Removed as autodependency component is removed"
- };
-
UninstallerCalculator(PackageManagerCore *core,
const AutoDependencyHash &autoDependencyComponentHash,
const LocalDependencyHash &localDependencyComponentHash,
const QStringList &localVirtualComponents);
+ ~UninstallerCalculator();
- QSet<Component*> componentsToUninstall() const;
- QString componentsToUninstallError() const;
-
- bool appendComponentsToUninstall(const QList<Component*> &components);
- void insertUninstallReason(Component *component,
- const UninstallReasonType uninstallReason,
- const QString &referencedComponentName = QString());
- QString uninstallReason(Component *component) const;
- UninstallerCalculator::UninstallReasonType uninstallReasonType(Component *c) const;
+ bool solve(const QList<Component*> &components) override;
+ QString resolutionText(Component *component) const override;
private:
- QString uninstallReasonReferencedComponent(Component *component) const;
+ bool solveComponent(Component *component, const QString &version = QString()) override;
+
bool isRequiredVirtualPackage(Component *component);
- bool appendComponentToUninstall(Component *component);
void appendVirtualComponentsToUninstall();
- QString m_componentsToUninstallError;
- QSet<Component *> m_componentsToUninstall;
- PackageManagerCore *m_core;
- QHash<QString, QPair<UninstallReasonType, QString> > m_toUninstallComponentIdReasonHash;
+private:
AutoDependencyHash m_autoDependencyComponentHash;
LocalDependencyHash m_localDependencyComponentHash;
QStringList m_localVirtualComponents;
};
-}
-
+} // namespace QInstaller
#endif // UNINSTALLERCALCULATOR_H
diff --git a/tests/auto/installer/solver/tst_solver.cpp b/tests/auto/installer/solver/tst_solver.cpp
index ee05cc7f4..85fb387e2 100644
--- a/tests/auto/installer/solver/tst_solver.cpp
+++ b/tests/auto/installer/solver/tst_solver.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.
@@ -39,7 +39,7 @@
using namespace QInstaller;
typedef QMap<Component *, QStringList> ComponentToStringList;
-typedef QList<QPair<Component *, UninstallerCalculator::UninstallReasonType>> UninstallReasonList;
+typedef QList<QPair<Component *, CalculatorBase::Resolution>> UninstallReasonList;
Q_DECLARE_METATYPE(UninstallReasonList)
@@ -149,7 +149,7 @@ private slots:
QTest::addColumn<PackageManagerCore *>("core");
QTest::addColumn<QList<Component *> >("selectedComponents");
QTest::addColumn<QList<Component *> >("expectedResult");
- QTest::addColumn<QList<int> >("installReason");
+ QTest::addColumn<QList<CalculatorBase::Resolution> >("installReason");
QTest::addColumn<AutoDependencyHash >("autodependencyHash");
PackageManagerCore *core = new PackageManagerCore();
@@ -176,11 +176,11 @@ private slots:
QTest::newRow("Installer resolved") << core
<< (QList<Component *>() << componentB)
<< (QList<Component *>() << componentB_NewVersion << componentAB << componentB << componentB_Auto)
- << (QList<int>()
- << InstallerCalculator::Dependent
- << InstallerCalculator::Dependent
- << InstallerCalculator::Resolved
- << InstallerCalculator::Automatic)
+ << (QList<CalculatorBase::Resolution>()
+ << CalculatorBase::Resolution::Dependent
+ << CalculatorBase::Resolution::Dependent
+ << CalculatorBase::Resolution::Resolved
+ << CalculatorBase::Resolution::Automatic)
<< autodependencyHash;
}
@@ -189,17 +189,17 @@ private slots:
QFETCH(PackageManagerCore *, core);
QFETCH(QList<Component *> , selectedComponents);
QFETCH(QList<Component *> , expectedResult);
- QFETCH(QList<int>, installReason);
+ QFETCH(QList<CalculatorBase::Resolution>, installReason);
QFETCH(AutoDependencyHash, autodependencyHash);
InstallerCalculator calc(core, autodependencyHash);
- calc.appendComponentsToInstall(selectedComponents);
- QList<Component *> result = calc.orderedComponentsToInstall();
+ calc.solve(selectedComponents);
+ QList<Component *> result = calc.resolvedComponents();
QCOMPARE(result.count(), expectedResult.count());
for (int i = 0; i < result.count(); i++) {
QCOMPARE(result.at(i), expectedResult.at(i));
- QCOMPARE((int)calc.installReasonType(result.at(i)), installReason.at(i));
+ QCOMPARE(calc.resolutionType(result.at(i)), installReason.at(i));
}
delete core;
}
@@ -237,9 +237,9 @@ private slots:
InstallerCalculator calc(core, QHash<QString, QStringList>());
QTest::ignoreMessage(QtWarningMsg, "Cannot find missing dependency \"B->=2.0.0\" for \"A\".");
- calc.appendComponentsToInstall(selectedComponents);
+ calc.solve(selectedComponents);
- QList<Component *> result = calc.orderedComponentsToInstall();
+ QList<Component *> result = calc.resolvedComponents();
QCOMPARE(result.count(), expectedResult.count());
delete core;
}
@@ -248,7 +248,7 @@ private slots:
{
QTest::addColumn<PackageManagerCore *>("core");
QTest::addColumn<QList<Component *> >("selectedToUninstall");
- QTest::addColumn<QSet<Component *> >("expectedResult");
+ QTest::addColumn<QList<Component *> >("expectedResult");
QTest::addColumn<UninstallReasonList >("uninstallReasons");
QTest::addColumn<LocalDependencyHash >("dependencyHash");
@@ -272,11 +272,11 @@ private slots:
QHash<QString, QStringList> dependencyComponentHash;
dependencyComponentHash.insert(QLatin1String("A.B"), QStringList() << QLatin1String("B"));
- uninstallReasonList.append(qMakePair(componentAB, UninstallerCalculator::Selected));
- uninstallReasonList.append(qMakePair(componentB, UninstallerCalculator::Dependent));
+ uninstallReasonList.append(qMakePair(componentAB, CalculatorBase::Resolution::Selected));
+ uninstallReasonList.append(qMakePair(componentB, CalculatorBase::Resolution::Dependent));
QTest::newRow("Uninstaller resolved") << core
<< (QList<Component *>() << componentAB)
- << (QSet<Component *>() << componentAB << componentB)
+ << (QList<Component *>() << componentB << componentAB)
<< uninstallReasonList
<< dependencyComponentHash;
@@ -297,11 +297,11 @@ private slots:
dependencyComponentHash.insert(QLatin1String("A"), QStringList() << QLatin1String("B"));
- uninstallReasonList.append(qMakePair(compA, UninstallerCalculator::Selected));
- uninstallReasonList.append(qMakePair(compB, UninstallerCalculator::Dependent));
+ uninstallReasonList.append(qMakePair(compA, CalculatorBase::Resolution::Selected));
+ uninstallReasonList.append(qMakePair(compB, CalculatorBase::Resolution::Dependent));
QTest::newRow("Cascade dependencies") << core
<< (QList<Component *>() << compA)
- << (QSet<Component *>() << compA << compB)
+ << (QList<Component *>() << compB << compA)
<< (uninstallReasonList)
<< dependencyComponentHash;
}
@@ -310,15 +310,15 @@ private slots:
{
QFETCH(PackageManagerCore *, core);
QFETCH(QList<Component *> , selectedToUninstall);
- QFETCH(QSet<Component *> , expectedResult);
+ QFETCH(QList<Component *> , expectedResult);
QFETCH(UninstallReasonList, uninstallReasons);
QFETCH(LocalDependencyHash, dependencyHash);
UninstallerCalculator calc(core, QHash<QString, QStringList>(), dependencyHash, QStringList());
- calc.appendComponentsToUninstall(selectedToUninstall);
- QSet<Component *> result = calc.componentsToUninstall();
+ calc.solve(selectedToUninstall);
+ QList<Component *> result = calc.resolvedComponents();
for (auto pair : uninstallReasons) {
- UninstallerCalculator::UninstallReasonType type = calc.uninstallReasonType(pair.first);
+ CalculatorBase::Resolution type = calc.resolutionType(pair.first);
QCOMPARE(pair.second, type);
}
QCOMPARE(result.count(), expectedResult.count());