diff options
author | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2023-01-27 09:59:10 +0200 |
---|---|---|
committer | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2023-01-27 10:38:55 +0000 |
commit | f5c48c86d3670240fc5c36c2f406196fc23527d5 (patch) | |
tree | 1823d302c330bf513908fdf68005d03ce5848f82 /src/libs | |
parent | 476b6d6fffaf6841adaf68889e8b8ddae17dd382 (diff) | |
parent | 50575212455fbd3109adbe92d8509fca3c51850a (diff) |
Merge remote-tracking branch 'origin/4.5'
Change-Id: I07baba6a0e64b6022e6a933708e199551be7dd2f
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/installer/component.cpp | 11 | ||||
-rw-r--r-- | src/libs/installer/component.h | 3 | ||||
-rw-r--r-- | src/libs/installer/componentmodel.cpp | 10 | ||||
-rw-r--r-- | src/libs/installer/componentselectionpage_p.cpp | 21 | ||||
-rw-r--r-- | src/libs/installer/componentselectionpage_p.h | 4 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 144 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.h | 11 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 49 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.h | 4 | ||||
-rw-r--r-- | src/libs/installer/packagemanagergui.cpp | 20 | ||||
-rw-r--r-- | src/libs/installer/uninstallercalculator.cpp | 52 | ||||
-rw-r--r-- | src/libs/installer/uninstallercalculator.h | 8 | ||||
-rw-r--r-- | src/libs/kdtools/updateoperation.cpp | 2 |
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 ¤t) { 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 ¤t); @@ -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> ¶ms { 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; } } |