summaryrefslogtreecommitdiffstats
path: root/src/libs
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 /src/libs
parent476b6d6fffaf6841adaf68889e8b8ddae17dd382 (diff)
parent50575212455fbd3109adbe92d8509fca3c51850a (diff)
Merge remote-tracking branch 'origin/4.5'
Diffstat (limited to 'src/libs')
-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
13 files changed, 209 insertions, 130 deletions
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;
}
}