summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/packagemanagercore.cpp
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2023-01-10 14:17:21 +0200
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2023-01-26 15:25:41 +0200
commit50575212455fbd3109adbe92d8509fca3c51850a (patch)
treec098c162795ec071653ffe082dda782b61edb813 /src/libs/installer/packagemanagercore.cpp
parentf5750078a7a75e7ad7b0260b54236ee87f3900f9 (diff)
Support detecting invalid dependency resolutions on component selection
IFW could already previously detect circular and missing dependencies by running a precheck calculation when building the component tree. However, there can be also cases of where the user selection results in unsolvable changes to components. One such case was the erroneous possibility to uninstall a component marked with ForcedInstallation, if any of its dependencies was checkable and the user unselected it for uninstallation. Add support for reacting to such errors in the component tree view, displaying a message box about the invalid dependency resolvation error, and blocking further navigation until the component selection passes the dependency calculations. Also attempt some refactoring the related code to simplify the different call sequences resulting in recalculation of the components. Change-Id: I9dc78f858bd4be7932f89f8e14bbfd97fbd3a0f6 Reviewed-by: Katja Marttila <katja.marttila@qt.io>
Diffstat (limited to 'src/libs/installer/packagemanagercore.cpp')
-rw-r--r--src/libs/installer/packagemanagercore.cpp140
1 files changed, 90 insertions, 50 deletions
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index c0902569d..db6c692e2 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.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.
@@ -532,7 +532,6 @@ void PackageManagerCore::reset()
d->m_status = PackageManagerCore::Unfinished;
d->m_installerBaseBinaryUnreplaced.clear();
d->m_coreCheckedHash.clear();
- d->m_componentsToInstallCalculated = false;
}
/*!
@@ -602,32 +601,45 @@ bool PackageManagerCore::clearLocalCache(QString *error)
}
/*!
+ \deprecated [4.5] Use recalculateAllComponents() instead.
+
\sa {installer::componentsToInstallNeedsRecalculation}{installer.componentsToInstallNeedsRecalculation}
*/
void PackageManagerCore::componentsToInstallNeedsRecalculation()
{
- d->clearInstallerCalculator();
+ recalculateAllComponents();
+}
- QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation();
+/*!
+ \fn QInstaller::PackageManagerCore::clearComponentsToInstallCalculated()
- d->m_componentsToInstallCalculated =
- d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall);
+ \deprecated [4.5] Installer framework recalculates components each time the calculation
+ of components to install is requested, so there is no need to call this anymore, and the
+ method does nothing. On previous versions calling this forced a recalculation of
+ components to install.
- d->calculateUninstallComponents();
- d->updateComponentCheckedState();
+ \sa {installer::clearComponentsToInstallCalculated}{installer.clearComponentsToInstallCalculated}
+ */
+/*!
+ Recalculates all components to install and uninstall. Returns \c true
+ on success, \c false otherwise. Detailed error messages can be retrieved
+ with {installer::componentsToInstallError} and {installer::componentsToUninstallError}.
+ */
+bool PackageManagerCore::recalculateAllComponents()
+{
+ if (!calculateComponentsToInstall())
+ return false;
+ if (!isInstaller() && !calculateComponentsToUninstall())
+ return false;
+
+ // update install actions
+ d->updateComponentCheckedState();
// update all nodes uncompressed size
foreach (Component *const component, components(ComponentType::Root))
component->updateUncompressedSize(); // this is a recursive call
-}
-/*!
- Forces a recalculation of components to install.
- \sa {installer::clearComponentsToInstallCalculated}{installer.clearComponentsToInstallCalculated}
- */
-void PackageManagerCore::clearComponentsToInstallCalculated()
-{
- d->m_componentsToInstallCalculated = false;
+ return true;
}
/*!
@@ -2154,8 +2166,9 @@ QList<Component *> PackageManagerCore::componentsMarkedForInstallation() const
}
/*!
- Determines which components to install based on the current run mode and returns an
- ordered list of components to install. Also auto installed dependencies are resolved.
+ Determines which components to install based on the current run mode, including dependencies
+ and automatic dependencies. Returns \c true on success, \c false otherwise.
+
The aboutCalculateComponentsToInstall() signal is emitted
before the calculation starts, the finishedCalculateComponentsToInstall()
signal once all calculations are done.
@@ -2166,16 +2179,15 @@ QList<Component *> PackageManagerCore::componentsMarkedForInstallation() const
bool PackageManagerCore::calculateComponentsToInstall() const
{
emit aboutCalculateComponentsToInstall();
- if (!d->m_componentsToInstallCalculated) {
- d->clearInstallerCalculator();
- QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation();
- d->storeCheckState();
- d->m_componentsToInstallCalculated =
- d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall);
- }
+ d->clearInstallerCalculator();
+ const QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation();
+
+ const bool componentsToInstallCalculated =
+ d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall);
+
emit finishedCalculateComponentsToInstall();
- return d->m_componentsToInstallCalculated;
+ return componentsToInstallCalculated;
}
/*!
@@ -2187,25 +2199,30 @@ QList<Component*> PackageManagerCore::orderedComponentsToInstall() const
}
/*!
- Calculates components to install and uninstall. In case of an error, returns \c false
- and and sets the \a displayString for error detail.
+ Returns a HTML-formatted description of the reasons each component is about
+ to be installed or uninstalled, or a description of the error occurred while
+ calculating components to install and uninstall.
*/
-
-bool PackageManagerCore::calculateComponents(QString *displayString)
+QString PackageManagerCore::componentResolveReasons() const
{
QString htmlOutput;
- if (!calculateComponentsToInstall()) {
+ if (!componentsToInstallError().isEmpty()) {
htmlOutput.append(QString::fromLatin1("<h2><font color=\"red\">%1</font></h2><ul>")
- .arg(tr("Cannot resolve all dependencies.")));
+ .arg(tr("Cannot resolve all dependencies.")));
//if we have a missing dependency or a recursion we can display it
- if (!componentsToInstallError().isEmpty()) {
- htmlOutput.append(QString::fromLatin1("<li> %1 </li>").arg(
- componentsToInstallError()));
- }
+ htmlOutput.append(QString::fromLatin1("<li> %1 </li>").arg(
+ componentsToInstallError()));
htmlOutput.append(QLatin1String("</ul>"));
- if (displayString)
- *displayString = htmlOutput;
- return false;
+ return htmlOutput;
+ }
+
+ if (!componentsToUninstallError().isEmpty()) {
+ htmlOutput.append(QString::fromLatin1("<h2><font color=\"red\">%1</font></h2><ul>")
+ .arg(tr("Cannot resolve components to uninstall.")));
+ htmlOutput.append(QString::fromLatin1("<li> %1 </li>").arg(
+ componentsToUninstallError()));
+ htmlOutput.append(QLatin1String("</ul>"));
+ return htmlOutput;
}
QList<Component*> componentsToRemove = componentsToUninstall();
@@ -2238,28 +2255,44 @@ bool PackageManagerCore::calculateComponents(QString *displayString)
}
htmlOutput.append(QString::fromLatin1("<li> %1 </li>").arg(component->name()));
}
- if (displayString)
- *displayString = htmlOutput;
- return true;
+ return htmlOutput;
}
/*!
- Calculates a list of components to uninstall based on the current run mode.
+ Calculates a list of components to uninstall.
+
The aboutCalculateComponentsToUninstall() signal is emitted
before the calculation starts, the finishedCalculateComponentsToUninstall() signal once all
- calculations are done. Always returns \c true.
+ calculations are done. Returns \c true on success, \c false otherwise.
\sa {installer::calculateComponentsToUninstall}{installer.calculateComponentsToUninstall}
*/
bool PackageManagerCore::calculateComponentsToUninstall() const
{
emit aboutCalculateComponentsToUninstall();
- if (!isUpdater()) {
- d->calculateUninstallComponents();
- d->storeCheckState();
+
+ d->clearUninstallerCalculator();
+ const QList<Component *> componentsToInstallList = d->installerCalculator()->orderedComponentsToInstall();
+
+ 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());
+ selectedComponentsToUninstall.append(comp.second);
+ }
+ }
+ foreach (Component *component, components(PackageManagerCore::ComponentType::AllNoReplacements)) {
+ if (component->uninstallationRequested() && !componentsToInstallList.contains(component))
+ selectedComponentsToUninstall.append(component);
}
+ const bool componentsToUninstallCalculated =
+ d->uninstallerCalculator()->appendComponentsToUninstall(selectedComponentsToUninstall);
+
emit finishedCalculateComponentsToUninstall();
- return true;
+ return componentsToUninstallCalculated;
}
/*!
@@ -2283,6 +2316,14 @@ QString PackageManagerCore::componentsToInstallError() const
}
/*!
+ Returns errors found in the components that are marked for uninstallation.
+*/
+QString PackageManagerCore::componentsToUninstallError() const
+{
+ return d->uninstallerCalculator()->componentsToUninstallError();
+}
+
+/*!
Returns the reason why \a component needs to be installed:
\list
@@ -4516,8 +4557,7 @@ ComponentModel *PackageManagerCore::componentModel(PackageManagerCore *core, con
ComponentModel::tr("Release Date"));
model->setHeaderData(ComponentModelHelper::UncompressedSizeColumn, Qt::Horizontal,
ComponentModel::tr("Size"));
- connect(model, &ComponentModel::checkStateChanged,
- this, &PackageManagerCore::componentsToInstallNeedsRecalculation);
+
return model;
}