summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2023-01-27 09:59:10 +0200
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2023-01-27 10:38:55 +0000
commitf5c48c86d3670240fc5c36c2f406196fc23527d5 (patch)
tree1823d302c330bf513908fdf68005d03ce5848f82
parent476b6d6fffaf6841adaf68889e8b8ddae17dd382 (diff)
parent50575212455fbd3109adbe92d8509fca3c51850a (diff)
Merge remote-tracking branch 'origin/4.5'
-rw-r--r--Changelog3
-rw-r--r--doc/installerfw.qdoc8
-rw-r--r--doc/scripting-api/packagemanagercore.qdoc14
-rw-r--r--src/libs/installer/component.cpp11
-rw-r--r--src/libs/installer/component.h3
-rw-r--r--src/libs/installer/componentmodel.cpp10
-rw-r--r--src/libs/installer/componentselectionpage_p.cpp21
-rw-r--r--src/libs/installer/componentselectionpage_p.h4
-rw-r--r--src/libs/installer/packagemanagercore.cpp144
-rw-r--r--src/libs/installer/packagemanagercore.h11
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp49
-rw-r--r--src/libs/installer/packagemanagercore_p.h4
-rw-r--r--src/libs/installer/packagemanagergui.cpp20
-rw-r--r--src/libs/installer/uninstallercalculator.cpp52
-rw-r--r--src/libs/installer/uninstallercalculator.h8
-rw-r--r--src/libs/kdtools/updateoperation.cpp2
-rw-r--r--tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp4
-rw-r--r--tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp3
18 files changed, 233 insertions, 138 deletions
diff --git a/Changelog b/Changelog
index f6aa2711d..e59ffd0de 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,6 @@
+4.5.2
+- Fix freezing UI while searching components (QTIFW-2886)
+
4.5.1
- Make Settings operation to support _OLD and placeholders (QTIFW-2882)
- ExtractOp: fix leftover empty directories when 'targetDir' arg is used (QTIFW-2764)
diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc
index 476234f80..a0fb9d848 100644
--- a/doc/installerfw.qdoc
+++ b/doc/installerfw.qdoc
@@ -907,8 +907,12 @@
The component is installed if and only if
all of the specified dependencies are fulfilled.
If a component has an automatic dependency on other components,
- the check box will not be visible next to the component in the component tree.
- The selection will be performed automatically.
+ the check box will not be visible next to the component in the component tree,
+ but this does not change the visibility of the check box in the updater view
+ where the end user may still manually select the component for update.
+
+ When running an installer or a maintenance tool in package manager
+ mode, the selection will be performed automatically.
If the component was not installed before, it will
be selected for installation only when all components
from this list are also selected for installation.
diff --git a/doc/scripting-api/packagemanagercore.qdoc b/doc/scripting-api/packagemanagercore.qdoc
index b14fd957f..ac6830d33 100644
--- a/doc/scripting-api/packagemanagercore.qdoc
+++ b/doc/scripting-api/packagemanagercore.qdoc
@@ -325,15 +325,25 @@
*/
/*!
+ \qmlmethod boolean installer::recalculateAllComponents()
+
+ Recalculates all components to install and uninstall. Returns \c true
+ on success, \c false otherwise.
+*/
+
+/*!
\qmlmethod void installer::componentsToInstallNeedsRecalculation()
+ \deprecated [4.5] Use recalculateAllComponents() instead.
Ensures that component dependencies are re-calculated.
*/
/*!
\qmlmethod void installer::clearComponentsToInstallCalculated()
-
- Forces a recalculation of components to install.
+ \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.
*/
/*!
diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp
index ccf9dc8bb..32f3fefc6 100644
--- a/src/libs/installer/component.cpp
+++ b/src/libs/installer/component.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.
@@ -1367,6 +1367,15 @@ bool Component::forcedInstallation() const
}
/*!
+ Returns whether this component is essential. Essential components
+ are always installed, and updated before other components.
+*/
+bool Component::isEssential() const
+{
+ return d->m_vars.value(scEssential, scFalse).toLower() == scTrue;
+}
+
+/*!
Sets the validator callback name to \a name.
*/
void Component::setValidatorCallbackName(const QString &name)
diff --git a/src/libs/installer/component.h b/src/libs/installer/component.h
index 0d8bf85ab..8f17b2d98 100644
--- a/src/libs/installer/component.h
+++ b/src/libs/installer/component.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.
@@ -209,6 +209,7 @@ public:
bool isVirtual() const;
bool isSelected() const;
bool forcedInstallation() const;
+ bool isEssential() const;
void setValidatorCallbackName(const QString &name);
diff --git a/src/libs/installer/componentmodel.cpp b/src/libs/installer/componentmodel.cpp
index 873175937..dbb80f2f6 100644
--- a/src/libs/installer/componentmodel.cpp
+++ b/src/libs/installer/componentmodel.cpp
@@ -216,7 +216,10 @@ QVariant ComponentModel::data(const QModelIndex &index, int role) const
return component->data(Qt::UserRole + index.column());
}
if (role == Qt::CheckStateRole) {
- if (!component->isCheckable() || !component->autoDependencies().isEmpty() || component->isUnstable())
+ if (!component->isCheckable() || component->isUnstable())
+ return QVariant();
+
+ if (!m_core->isUpdater() && !component->autoDependencies().isEmpty())
return QVariant();
}
if (role == ComponentModelHelper::ExpandedByDefault) {
@@ -564,9 +567,12 @@ QSet<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &compone
checkable = false;
}
- if ((!node->isCheckable() && checkable) || !node->isEnabled() || !node->autoDependencies().isEmpty() || node->isUnstable())
+ if ((!node->isCheckable() && checkable) || !node->isEnabled() || node->isUnstable())
continue;
+ if (!m_core->isUpdater() && !node->autoDependencies().isEmpty())
+ continue;
+
Qt::CheckState newState = state;
const Qt::CheckState recentState = node->checkState();
if (node->isTristate())
diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp
index 83bcaae14..84a8915a0 100644
--- a/src/libs/installer/componentselectionpage_p.cpp
+++ b/src/libs/installer/componentselectionpage_p.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.
@@ -72,6 +72,7 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
, m_categoryWidget(Q_NULLPTR)
, m_categoryLayoutVisible(false)
, m_proxyModel(new ComponentSortFilterProxyModel(q))
+ , m_componentsResolved(false)
, m_headerStretchLastSection(false)
{
m_treeView->setObjectName(QLatin1String("ComponentsTreeView"));
@@ -390,6 +391,15 @@ void ComponentSelectionPagePrivate::expandSearchResults()
restoreHeaderResizeModes();
}
+/*!
+ Returns \c true if the components to install and uninstall are calculated
+ successfully, \c false otherwise.
+*/
+bool ComponentSelectionPagePrivate::componentsResolved() const
+{
+ return m_componentsResolved;
+}
+
void ComponentSelectionPagePrivate::currentSelectedChanged(const QModelIndex &current)
{
if (!current.isValid())
@@ -547,6 +557,15 @@ void ComponentSelectionPagePrivate::onModelStateChanged(QInstaller::ComponentMod
m_checkDefault->setEnabled(false);
return;
}
+
+ m_componentsResolved = m_core->recalculateAllComponents();
+ if (!m_componentsResolved) {
+ const QString error = !m_core->componentsToInstallError().isEmpty()
+ ? m_core->componentsToInstallError() : m_core->componentsToUninstallError();
+ MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
+ QLatin1String("CalculateComponentsError"), tr("Error"), error);
+ }
+
q->setModified(state.testFlag(ComponentModel::DefaultChecked) == false);
// If all components in the checked list are only checkable when run without forced
// installation, set ComponentModel::AllUnchecked as well, as we cannot uncheck anything.
diff --git a/src/libs/installer/componentselectionpage_p.h b/src/libs/installer/componentselectionpage_p.h
index 7c2f6a38e..f06d376f4 100644
--- a/src/libs/installer/componentselectionpage_p.h
+++ b/src/libs/installer/componentselectionpage_p.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.
@@ -74,6 +74,7 @@ public:
void updateTreeView();
void expandDefault();
void expandSearchResults();
+ bool componentsResolved() const;
public slots:
void currentSelectedChanged(const QModelIndex &current);
@@ -118,6 +119,7 @@ private:
QStackedLayout *m_stackedLayout;
ComponentSortFilterProxyModel *m_proxyModel;
QLineEdit *m_searchLineEdit;
+ bool m_componentsResolved;
bool m_headerStretchLastSection;
QHash<int, QHeaderView::ResizeMode> m_headerResizeModes;
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index 8c70bdae6..2f69c20c8 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.
@@ -531,7 +531,6 @@ void PackageManagerCore::reset()
d->m_status = PackageManagerCore::Unfinished;
d->m_installerBaseBinaryUnreplaced.clear();
d->m_coreCheckedHash.clear();
- d->m_componentsToInstallCalculated = false;
}
/*!
@@ -613,32 +612,45 @@ template bool PackageManagerCore::loadComponentScripts<QList<Component *>>(const
template bool PackageManagerCore::loadComponentScripts<QHash<QString, Component *>>(const QHash<QString, Component *> &, const bool);
/*!
+ \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;
}
/*!
@@ -2169,8 +2181,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.
@@ -2181,16 +2194,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;
}
/*!
@@ -2202,25 +2214,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();
@@ -2253,28 +2270,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;
}
/*!
@@ -2298,6 +2331,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
@@ -4336,7 +4377,7 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const
if (d->statusCanceledOrFailed())
return false;
- if (!component->isUnstable() && component->autoDependencies().isEmpty())
+ if (!component->isUnstable())
component->setCheckState(Qt::Checked);
}
@@ -4348,7 +4389,7 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const
foreach (QInstaller::Component *component, d->m_updaterComponentsDeps) {
if (d->statusCanceledOrFailed())
return false;
- if (component->isInstalled() && !component->autoDependencies().isEmpty()) {
+ if (component->isInstalled()) {
// since we do not put them into the model, which would force a update of e.g. tri state
// components, we have to check all installed components ourselves
if (!component->isUnstable())
@@ -4527,8 +4568,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;
}
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index 936a377ab..c63447543 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.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.
@@ -240,12 +240,15 @@ public:
Q_INVOKABLE bool calculateComponentsToInstall() const;
QList<Component*> orderedComponentsToInstall() const;
- bool calculateComponents(QString *displayString);
+
+ Q_INVOKABLE bool recalculateAllComponents();
+ QString componentResolveReasons() const;
Q_INVOKABLE bool calculateComponentsToUninstall() const;
QList<Component*> componentsToUninstall() const;
QString componentsToInstallError() const;
+ QString componentsToUninstallError() const;
QString installReason(Component *component) const;
QString uninstallReason(Component *component) const;
@@ -363,8 +366,8 @@ public Q_SLOTS:
void languageChanged();
void setCompleteUninstallation(bool complete);
void cancelMetaInfoJob();
- void componentsToInstallNeedsRecalculation();
- void clearComponentsToInstallCalculated();
+ void componentsToInstallNeedsRecalculation(); // TODO: deprecated, remove
+ void clearComponentsToInstallCalculated() {} // TODO: deprecated, remove
Q_SIGNALS:
void aboutCalculateComponentsToInstall() const;
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 52d66ff6b..7313a2761 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.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.
@@ -170,7 +170,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
, m_updateSourcesAdded(false)
, m_magicBinaryMarker(0) // initialize with pseudo marker
, m_magicMarkerSupplement(BinaryContent::Default)
- , m_componentsToInstallCalculated(false)
, m_componentScriptEngine(nullptr)
, m_controlScriptEngine(nullptr)
, m_installerCalculator(nullptr)
@@ -209,7 +208,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_updateSourcesAdded(false)
, m_magicBinaryMarker(magicInstallerMaker)
, m_magicMarkerSupplement(BinaryContent::Default)
- , m_componentsToInstallCalculated(false)
, m_componentScriptEngine(nullptr)
, m_controlScriptEngine(nullptr)
, m_installerCalculator(nullptr)
@@ -496,7 +494,6 @@ void PackageManagerCorePrivate::clearAllComponentLists()
m_deletedReplacedComponents.clear();
m_componentsToReplaceAllMode.clear();
- m_componentsToInstallCalculated = false;
m_foundEssentialUpdate = false;
qDeleteAll(toDelete);
@@ -524,7 +521,6 @@ void PackageManagerCorePrivate::clearUpdaterComponentLists()
m_updaterDependencyReplacements.clear();
m_componentsToReplaceUpdaterMode.clear();
- m_componentsToInstallCalculated = false;
m_foundEssentialUpdate = false;
qDeleteAll(usedComponents);
@@ -590,7 +586,6 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> &params
{
m_coreCheckedHash.clear();
m_data = PackageManagerCoreData(params, isInstaller());
- m_componentsToInstallCalculated = false;
#ifdef Q_OS_LINUX
if (m_launchedAsRoot && isInstaller())
@@ -2921,7 +2916,6 @@ void PackageManagerCorePrivate::restoreCheckState()
}
m_coreCheckedHash.clear();
- m_componentsToInstallCalculated = false;
}
void PackageManagerCorePrivate::storeCheckState()
@@ -3062,20 +3056,19 @@ QStringList PackageManagerCorePrivate::runningInstallerProcesses(const QStringLi
bool PackageManagerCorePrivate::calculateComponentsAndRun()
{
- QString htmlOutput;
- bool componentsOk = m_core->calculateComponents(&htmlOutput);
-
- try {
- loadComponentScripts(installerCalculator()->orderedComponentsToInstall(), true);
- } catch (const Error &error) {
- qCWarning(QInstaller::lcInstallerInstallLog) << error.message();
- return false;
- }
+ bool componentsOk = m_core->recalculateAllComponents();
if (statusCanceledOrFailed()) {
qCDebug(QInstaller::lcInstallerInstallLog) << "Installation canceled.";
} else if (componentsOk && acceptLicenseAgreements()) {
- qCDebug(QInstaller::lcInstallerInstallLog).noquote() << htmlToString(htmlOutput);
+ try {
+ loadComponentScripts(installerCalculator()->orderedComponentsToInstall(), true);
+ } catch (const Error &error) {
+ qCWarning(QInstaller::lcInstallerInstallLog) << error.message();
+ return false;
+ }
+ qCDebug(QInstaller::lcInstallerInstallLog).noquote()
+ << htmlToString(m_core->componentResolveReasons());
QString spaceInfo;
const bool spaceOk = m_core->checkAvailableSpace(spaceInfo);
@@ -3092,28 +3085,6 @@ bool PackageManagerCorePrivate::calculateComponentsAndRun()
return false;
}
-void PackageManagerCorePrivate::calculateUninstallComponents()
-{
- clearUninstallerCalculator();
- const QList<Component *> componentsToInstallList = installerCalculator()->orderedComponentsToInstall();
-
- QList<Component *> selectedComponentsToUninstall;
- foreach (Component* component, m_core->components(PackageManagerCore::ComponentType::Replacements)) {
- // Uninstall the component if replacement is selected for install or update
- QPair<Component*, Component*> comp = componentsToReplace().value(component->name());
- if (comp.first && m_installerCalculator->orderedComponentsToInstall().contains(comp.first)) {
- uninstallerCalculator()->insertUninstallReason(component,
- UninstallerCalculator::Replaced, comp.first->name());
- selectedComponentsToUninstall.append(comp.second);
- }
- }
- foreach (Component *component, m_core->components(PackageManagerCore::ComponentType::AllNoReplacements)) {
- if (component->uninstallationRequested() && !componentsToInstallList.contains(component))
- selectedComponentsToUninstall.append(component);
- }
- uninstallerCalculator()->appendComponentsToUninstall(selectedComponentsToUninstall);
-}
-
bool PackageManagerCorePrivate::acceptLicenseAgreements() const
{
// Always skip for uninstaller
diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h
index 8d6ba0c89..f6e2b34dd 100644
--- a/src/libs/installer/packagemanagercore_p.h
+++ b/src/libs/installer/packagemanagercore_p.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.
@@ -267,7 +267,6 @@ private:
void findExecutablesRecursive(const QString &path, const QStringList &excludeFiles, QStringList *result);
QStringList runningInstallerProcesses(const QStringList &exludeFiles);
bool calculateComponentsAndRun();
- void calculateUninstallComponents();
bool acceptLicenseAgreements() const;
bool askUserAcceptLicense(const QString &name, const QString &content) const;
bool askUserConfirmCommand() const;
@@ -292,7 +291,6 @@ private:
qint64 m_magicBinaryMarker;
int m_magicMarkerSupplement;
- bool m_componentsToInstallCalculated;
bool m_foundEssentialUpdate;
mutable ScriptEngine *m_componentScriptEngine;
diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp
index 9db6e6eeb..b91526663 100644
--- a/src/libs/installer/packagemanagergui.cpp
+++ b/src/libs/installer/packagemanagergui.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.
@@ -1439,7 +1439,6 @@ int PackageManagerPage::nextId() const
if (core->isUninstaller())
return nextNextId; // forcibly hide the license page if we run as uninstaller
- core->calculateComponentsToInstall();
foreach (Component* component, core->orderedComponentsToInstall()) {
if (core->isMaintainer() && component->isInstalled())
continue; // package manager or updater, hide as long as the component is installed
@@ -1950,9 +1949,6 @@ void IntroductionPage::entering()
*/
void IntroductionPage::leaving()
{
- // force a recalculation of components to install to keep the state correct
- if (!packageManagerCore()->isUninstaller())
- packageManagerCore()->componentsToInstallNeedsRecalculation();
m_progressBar->setValue(0);
m_progressBar->setRange(0, 0);
setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::CancelButton));
@@ -2082,7 +2078,6 @@ void LicenseAgreementPage::entering()
m_textBrowser->setHtml(QString());
m_licenseListWidget->setVisible(false);
- packageManagerCore()->calculateComponentsToInstall();
foreach (QInstaller::Component *component, packageManagerCore()->orderedComponentsToInstall())
packageManagerCore()->addLicenseItem(component->licenses());
@@ -2213,8 +2208,7 @@ void ComponentSelectionPage::entering()
d->updateTreeView();
// check component model state so we can enable needed component selection buttons
- if (core->isUpdater())
- d->onModelStateChanged(d->m_currentModel->checkedState());
+ d->onModelStateChanged(d->m_currentModel->checkedState());
setModified(isComplete());
if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly()
@@ -2339,7 +2333,7 @@ bool ComponentSelectionPage::addVirtualComponentToUninstall(const QString &name)
name, allComponents);
if (component && component->isInstalled() && component->isVirtual()) {
component->setCheckState(Qt::Unchecked);
- core->componentsToInstallNeedsRecalculation();
+ core->recalculateAllComponents();
qCDebug(QInstaller::lcDeveloperBuild) << "Virtual component " << name << " was selected for uninstall by script.";
return true;
}
@@ -2356,6 +2350,9 @@ void ComponentSelectionPage::setModified(bool modified)
*/
bool ComponentSelectionPage::isComplete() const
{
+ if (!d->componentsResolved())
+ return false;
+
if (packageManagerCore()->isInstaller() || packageManagerCore()->isUpdater())
return d->m_currentModel->checked().count();
@@ -2713,8 +2710,9 @@ void ReadyForInstallationPage::entering()
.arg(productName()));
}
- QString htmlOutput;
- bool componentsOk = packageManagerCore()->calculateComponents(&htmlOutput);
+ bool componentsOk = packageManagerCore()->recalculateAllComponents();
+ const QString htmlOutput = packageManagerCore()->componentResolveReasons();
+
qCDebug(QInstaller::lcInstallerInstallLog).noquote() << htmlToString(htmlOutput);
m_taskDetailsBrowser->setHtml(htmlOutput);
m_taskDetailsBrowser->setVisible(!componentsOk || LoggingHandler::instance().isVerbose());
diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp
index 2f029630f..214e1124a 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.
@@ -30,6 +30,7 @@
#include "component.h"
#include "packagemanagercore.h"
+#include "globals.h"
namespace QInstaller {
@@ -55,35 +56,60 @@ QSet<Component *> UninstallerCalculator::componentsToUninstall() const
return m_componentsToUninstall;
}
-void UninstallerCalculator::appendComponentToUninstall(Component *component)
+QString UninstallerCalculator::componentsToUninstallError() const
+{
+ return m_componentsToUninstallError;
+}
+
+bool UninstallerCalculator::appendComponentToUninstall(Component *component)
{
if (!component)
- return;
+ return true;
if (!component->isInstalled())
- return;
+ return true;
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)
+ if (!depComponent || !depComponent->isInstalled())
+ continue;
+
+ if (m_componentsToUninstall.contains(depComponent)
+ || m_core->orderedComponentsToInstall().contains(depComponent)) {
+ // Component is already selected for uninstall or update
continue;
- if (depComponent->isInstalled() && !m_componentsToUninstall.contains(depComponent)
- && !m_core->orderedComponentsToInstall().contains(depComponent)) {
- appendComponentToUninstall(depComponent);
- insertUninstallReason(depComponent, UninstallerCalculator::Dependent, component->name());
}
+
+ 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(), uninstallReason(component));
+
+ qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
+ m_componentsToUninstallError.append(errorMessage);
+ return false;
+ }
+ // Resolve also all cascading dependencies
+ if (!appendComponentToUninstall(depComponent))
+ return false;
+
+ insertUninstallReason(depComponent, UninstallerCalculator::Dependent, component->name());
}
}
m_componentsToUninstall.insert(component);
+ return true;
}
-void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components)
+bool UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components)
{
- foreach (Component *component, components)
- appendComponentToUninstall(component);
+ foreach (Component *component, components) {
+ if (!appendComponentToUninstall(component))
+ return false;
+ }
QList<Component*> autoDependOnList;
// All regular dependees are resolved. Now we are looking for auto depend on components.
@@ -109,6 +135,8 @@ void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*>
appendComponentsToUninstall(autoDependOnList);
else
appendVirtualComponentsToUninstall();
+
+ return true;
}
void UninstallerCalculator::insertUninstallReason(Component *component, const UninstallReasonType uninstallReason,
diff --git a/src/libs/installer/uninstallercalculator.h b/src/libs/installer/uninstallercalculator.h
index 74207e005..6bdd342d2 100644
--- a/src/libs/installer/uninstallercalculator.h
+++ b/src/libs/installer/uninstallercalculator.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.
@@ -59,8 +59,9 @@ public:
const QStringList &localVirtualComponents);
QSet<Component*> componentsToUninstall() const;
+ QString componentsToUninstallError() const;
- void appendComponentsToUninstall(const QList<Component*> &components);
+ bool appendComponentsToUninstall(const QList<Component*> &components);
void insertUninstallReason(Component *component,
const UninstallReasonType uninstallReason,
const QString &referencedComponentName = QString());
@@ -70,8 +71,9 @@ public:
private:
QString uninstallReasonReferencedComponent(Component *component) const;
bool isRequiredVirtualPackage(Component *component);
- void appendComponentToUninstall(Component *component);
+ bool appendComponentToUninstall(Component *component);
void appendVirtualComponentsToUninstall();
+ QString m_componentsToUninstallError;
QSet<Component *> m_componentsToUninstall;
PackageManagerCore *m_core;
diff --git a/src/libs/kdtools/updateoperation.cpp b/src/libs/kdtools/updateoperation.cpp
index 9d1bd8230..6a7e62f2b 100644
--- a/src/libs/kdtools/updateoperation.cpp
+++ b/src/libs/kdtools/updateoperation.cpp
@@ -348,6 +348,8 @@ bool UpdateOperation::variableReplacement(QString *variableValue)
key.prepend(QLatin1String("@"));
key.append(QLatin1String("@"));
*variableValue = m_core->replaceVariables(key);
+ qCDebug(QInstaller::lcInstallerInstallLog) << "Running above operation with replaced value: " << valueNormalized
+ << "has been replaced with" << *variableValue;
variableValueChanged = true;
}
}
diff --git a/tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp b/tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp
index b52e0e9f6..9fbc12c41 100644
--- a/tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp
+++ b/tests/auto/installer/brokeninstaller/tst_brokeninstaller.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.
@@ -145,7 +145,7 @@ private slots:
Component *componentDependingOnMissingDependency = core.componentByName("componentd");
componentDependingOnMissingDependency->addDependency("componentmissingdependency");
- core.componentsToInstallNeedsRecalculation();
+ core.recalculateAllComponents();
model->reset(components);
testModelState(model, m_checkedComponentsWithMissingDependency, m_partiallyCheckedComponentsWithBrokenScript, m_uncheckedComponentsWithMissingDependency);
diff --git a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
index 44dc65960..cc2e069ea 100644
--- a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
+++ b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -260,7 +260,6 @@ private slots:
root->setInstalled();
child1->setInstalled();
child2->setUninstalled();
- core.componentsToInstallNeedsRecalculation();
core.calculateComponentsToInstall();
QCOMPARE(core.requiredDiskSpace(), 250ULL);
}