diff options
-rw-r--r-- | src/libs/installer/installer.pro | 6 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 7 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 127 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.h | 9 | ||||
-rw-r--r-- | src/libs/installer/uninstallercalculator.cpp | 158 | ||||
-rw-r--r-- | src/libs/installer/uninstallercalculator.h | 75 | ||||
-rw-r--r-- | tests/auto/installer/solver/tst_solver.cpp | 52 |
7 files changed, 323 insertions, 111 deletions
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro index 290f78d37..448b4acc4 100644 --- a/src/libs/installer/installer.pro +++ b/src/libs/installer/installer.pro @@ -121,7 +121,8 @@ HEADERS += packagemanagercore.h \ fileio.h \ binarycontent.h \ binarylayout.h \ - installercalculator.h + installercalculator.h \ + uninstallercalculator.h SOURCES += packagemanagercore.cpp \ packagemanagercore_p.cpp \ @@ -191,7 +192,8 @@ SOURCES += packagemanagercore.cpp \ fileio.cpp \ binarycontent.cpp \ binarylayout.cpp \ - installercalculator.cpp + installercalculator.cpp \ + uninstallercalculator.cpp RESOURCES += resources/patch_file_lists.qrc \ resources/installer.qrc diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index a9e7f7216..93a97ccc6 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -57,6 +57,7 @@ #include "settings.h" #include "utils.h" #include "installercalculator.h" +#include "uninstallercalculator.h" #include <productkeycheck.h> @@ -1269,9 +1270,9 @@ bool PackageManagerCore::calculateComponentsToUninstall() const componentsToUninstall.append(component); } - d->m_componentsToUninstall.clear(); + d->clearUninstallerCalculator(); d->storeCheckState(); - result = d->appendComponentsToUninstall(componentsToUninstall); + result = d->uninstallerCalculator()->appendComponentsToUninstall(componentsToUninstall); } emit finishedCalculateComponentsToUninstall(); return result; @@ -1282,7 +1283,7 @@ bool PackageManagerCore::calculateComponentsToUninstall() const */ QList<Component *> PackageManagerCore::componentsToUninstall() const { - return d->m_componentsToUninstall.toList(); + return d->uninstallerCalculator()->componentsToUninstall().toList(); } QString PackageManagerCore::componentsToInstallError() const diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index ca9aca625..5b31255e5 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -50,7 +50,6 @@ #include "errors.h" #include "fileio.h" #include "remotefileengine.h" -#include "globals.h" #include "graph.h" #include "messageboxhandler.h" #include "packagemanagercore.h" @@ -60,6 +59,7 @@ #include "qsettingswrapper.h" #include "remoteclient.h" #include "installercalculator.h" +#include "uninstallercalculator.h" #include "kdselfrestarter.h" #include "kdupdaterfiledownloaderfactory.h" @@ -198,6 +198,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core) , m_componentScriptEngine(0) , m_controlScriptEngine(0) , m_installerCalculator(0) + , m_uninstallerCalculator(0) , m_proxyFactory(0) , m_defaultModel(0) , m_updaterModel(0) @@ -226,6 +227,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q , m_componentScriptEngine(0) , m_controlScriptEngine(0) , m_installerCalculator(0) + , m_uninstallerCalculator(0) , m_proxyFactory(0) , m_defaultModel(0) , m_updaterModel(0) @@ -269,6 +271,7 @@ PackageManagerCorePrivate::~PackageManagerCorePrivate() clearAllComponentLists(); clearUpdaterComponentLists(); clearInstallerCalculator(); + clearUninstallerCalculator(); qDeleteAll(m_ownedOperations); qDeleteAll(m_performedOperationsOld); @@ -497,6 +500,30 @@ InstallerCalculator *PackageManagerCorePrivate::installerCalculator() const return m_installerCalculator; } +void PackageManagerCorePrivate::clearUninstallerCalculator() +{ + delete m_uninstallerCalculator; + m_uninstallerCalculator = 0; +} + +UninstallerCalculator *PackageManagerCorePrivate::uninstallerCalculator() const +{ + if (!m_uninstallerCalculator) { + PackageManagerCorePrivate *const pmcp = const_cast<PackageManagerCorePrivate *> (this); + + QList<Component*> installedComponents; + foreach (const QString &name, pmcp->localInstalledPackages().keys()) { + if (Component *component = m_core->componentByName(name)) { + if (!component->uninstallationRequested()) + installedComponents.append(component); + } + } + + pmcp->m_uninstallerCalculator = new UninstallerCalculator(installedComponents); + } + return m_uninstallerCalculator; +} + void PackageManagerCorePrivate::initialize(const QHash<QString, QString> ¶ms) { m_coreCheckedHash.clear(); @@ -2178,104 +2205,6 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe return m_updateSourcesAdded; } -bool PackageManagerCorePrivate::appendComponentToUninstall(Component *component) -{ - // remove all already resolved dependees - QSet<Component *> dependees = m_core->dependees(component).toSet().subtract(m_componentsToUninstall); - if (dependees.isEmpty()) { - component->setCheckState(Qt::Unchecked); - m_componentsToUninstall.insert(component); - return true; - } - - QSet<Component *> dependeesToResolve; - foreach (Component *dependee, dependees) { - if (dependee->isInstalled()) { - // keep them as already resolved - dependee->setCheckState(Qt::Unchecked); - m_componentsToUninstall.insert(dependee); - // gather possible dependees, keep them to resolve it later - dependeesToResolve.unite(m_core->dependees(dependee).toSet()); - } - } - - bool allResolved = true; - foreach (Component *dependee, dependeesToResolve) - allResolved &= appendComponentToUninstall(dependee); - - return allResolved; -} - -bool PackageManagerCorePrivate::appendComponentsToUninstall(const QList<Component*> &components) -{ - if (components.isEmpty()) { - qDebug() << "components list is empty in" << Q_FUNC_INFO; - return true; - } - - bool allResolved = true; - foreach (Component *component, components) { - if (component->isInstalled()) { - component->setCheckState(Qt::Unchecked); - m_componentsToUninstall.insert(component); - allResolved &= appendComponentToUninstall(component); - } - } - - QSet<Component*> installedComponents; - foreach (const QString &name, localInstalledPackages().keys()) { - if (Component *component = m_core->componentByName(name)) { - if (!component->uninstallationRequested()) - installedComponents.insert(component); - } - } - - QList<Component*> autoDependOnList; - if (allResolved) { - // All regular dependees are resolved. Now we are looking for auto depend on components. - foreach (Component *component, installedComponents) { - // If a components is installed and not yet scheduled for un-installation, check for auto depend. - if (component->isInstalled() && !m_componentsToUninstall.contains(component)) { - QStringList autoDependencies = component->autoDependencies(); - if (autoDependencies.isEmpty()) - continue; - - // This code needs to be enabled once the scripts use isInstalled, installationRequested and - // uninstallationRequested... - if (autoDependencies.first().compare(QLatin1String("script"), Qt::CaseInsensitive) == 0) { - //QScriptValue valueFromScript; - //try { - // valueFromScript = callScriptMethod(QLatin1String("isAutoDependOn")); - //} catch (const Error &error) { - // // keep the component, should do no harm - // continue; - //} - - //if (valueFromScript.isValid() && !valueFromScript.toBool()) - // autoDependOnList.append(component); - continue; - } - - foreach (Component *c, installedComponents) { - const QString replaces = c->value(scReplaces); - const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(), - QString::SkipEmptyParts) << c->name(); - foreach (const QString &possibleName, possibleNames) - autoDependencies.removeAll(possibleName); - } - - // A component requested auto installation, keep it to resolve their dependencies as well. - if (!autoDependencies.isEmpty()) - autoDependOnList.append(component); - } - } - } - - if (!autoDependOnList.isEmpty()) - return appendComponentsToUninstall(autoDependOnList); - return allResolved; -} - void PackageManagerCorePrivate::restoreCheckState() { if (m_coreCheckedHash.isEmpty()) diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index 06ccaf50d..cf686f0e0 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -70,6 +70,7 @@ class ScriptEngine; class ComponentModel; class TempDirDeleter; class InstallerCalculator; +class UninstallerCalculator; /* The default configuration interface implementation does call QSettings to save files for later deletion, @@ -149,6 +150,9 @@ public: void clearInstallerCalculator(); InstallerCalculator *installerCalculator() const; + void clearUninstallerCalculator(); + UninstallerCalculator *uninstallerCalculator() const; + bool runInstaller(); bool isInstaller() const; @@ -191,9 +195,6 @@ public: void installComponent(Component *component, double progressOperationSize, bool adminRightsGained = false); - bool appendComponentToUninstall(Component *component); - bool appendComponentsToUninstall(const QList<Component*> &components); - signals: void installationStarted(); void installationFinished(); @@ -273,8 +274,8 @@ private: QHash<QString, QPair<Component*, Component*> > m_componentsToReplaceUpdaterMode; InstallerCalculator *m_installerCalculator; + UninstallerCalculator *m_uninstallerCalculator; - QSet<Component*> m_componentsToUninstall; FileDownloaderProxyFactory *m_proxyFactory; ComponentModel *m_defaultModel; diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp new file mode 100644 index 000000000..0266bbb06 --- /dev/null +++ b/src/libs/installer/uninstallercalculator.cpp @@ -0,0 +1,158 @@ +/************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#include "uninstallercalculator.h" + +#include "component.h" +#include "packagemanagercore.h" +#include "globals.h" + +#include <QDebug> + +namespace QInstaller { + +UninstallerCalculator::UninstallerCalculator(const QList<Component *> &installedComponents) + : m_installedComponents(installedComponents) +{ +} + +QSet<Component *> UninstallerCalculator::componentsToUninstall() const +{ + return m_componentsToUninstall; +} + +bool UninstallerCalculator::appendComponentToUninstall(Component *component) +{ + if (!component) + return false; + + PackageManagerCore *core = component->packageManagerCore(); + // remove all already resolved dependees + QSet<Component *> dependees = core->dependees(component).toSet() + .subtract(m_componentsToUninstall); + if (dependees.isEmpty()) { + component->setCheckState(Qt::Unchecked); + m_componentsToUninstall.insert(component); + return true; + } + + QSet<Component *> dependeesToResolve; + foreach (Component *dependee, dependees) { + if (dependee->isInstalled()) { + // keep them as already resolved + dependee->setCheckState(Qt::Unchecked); + m_componentsToUninstall.insert(dependee); + // gather possible dependees, keep them to resolve it later + dependeesToResolve.unite(core->dependees(dependee).toSet()); + } + } + + bool allResolved = true; + foreach (Component *dependee, dependeesToResolve) + allResolved &= appendComponentToUninstall(dependee); + + return allResolved; +} + +bool UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components) +{ + if (components.isEmpty()) { + qDebug() << "components list is empty in" << Q_FUNC_INFO; + return true; + } + + bool allResolved = true; + foreach (Component *component, components) { + if (component->isInstalled()) { + component->setCheckState(Qt::Unchecked); + m_componentsToUninstall.insert(component); + allResolved &= appendComponentToUninstall(component); + } + } + + QList<Component*> autoDependOnList; + if (allResolved) { + // All regular dependees are resolved. Now we are looking for auto depend on components. + foreach (Component *component, m_installedComponents) { + // If a components is installed and not yet scheduled for un-installation, check for auto depend. + if (component->isInstalled() && !m_componentsToUninstall.contains(component)) { + QStringList autoDependencies = component->autoDependencies(); + if (autoDependencies.isEmpty()) + continue; + + // This code needs to be enabled once the scripts use isInstalled, installationRequested and + // uninstallationRequested... + if (autoDependencies.first().compare(QLatin1String("script"), Qt::CaseInsensitive) == 0) { + //QScriptValue valueFromScript; + //try { + // valueFromScript = callScriptMethod(QLatin1String("isAutoDependOn")); + //} catch (const Error &error) { + // // keep the component, should do no harm + // continue; + //} + + //if (valueFromScript.isValid() && !valueFromScript.toBool()) + // autoDependOnList.append(component); + continue; + } + + foreach (Component *c, m_installedComponents) { + const QString replaces = c->value(scReplaces); + const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(), + QString::SkipEmptyParts) << c->name(); + foreach (const QString &possibleName, possibleNames) + autoDependencies.removeAll(possibleName); + } + + // A component requested auto installation, keep it to resolve their dependencies as well. + if (!autoDependencies.isEmpty()) + autoDependOnList.append(component); + } + } + } + + if (!autoDependOnList.isEmpty()) + return appendComponentsToUninstall(autoDependOnList); + return allResolved; +} + + +} // namespace QInstaller diff --git a/src/libs/installer/uninstallercalculator.h b/src/libs/installer/uninstallercalculator.h new file mode 100644 index 000000000..e5da7898e --- /dev/null +++ b/src/libs/installer/uninstallercalculator.h @@ -0,0 +1,75 @@ +/************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ +#ifndef UNINSTALLERCALCULATOR_H +#define UNINSTALLERCALCULATOR_H + +#include "installer_global.h" + +#include <QHash> +#include <QList> +#include <QSet> +#include <QString> + +namespace QInstaller { + +class Component; + +class INSTALLER_EXPORT UninstallerCalculator +{ +public: + UninstallerCalculator(const QList<Component *> &installedComponents); + + QSet<Component*> componentsToUninstall() const; + + bool appendComponentsToUninstall(const QList<Component*> &components); + +private: + + bool appendComponentToUninstall(Component *component); + + QList<Component *> m_installedComponents; + QSet<Component *> m_componentsToUninstall; +}; + +} + + +#endif // UNINSTALLERCALCULATOR_H diff --git a/tests/auto/installer/solver/tst_solver.cpp b/tests/auto/installer/solver/tst_solver.cpp index 3c1530a1c..b2a932419 100644 --- a/tests/auto/installer/solver/tst_solver.cpp +++ b/tests/auto/installer/solver/tst_solver.cpp @@ -42,6 +42,7 @@ #include <component.h> #include <graph.h> #include <installercalculator.h> +#include <uninstallercalculator.h> #include <packagemanagercore.h> #include <QTest> @@ -149,7 +150,7 @@ private slots: qPrintable(cycle.first.data())); } - void resolve_data() + void resolveInstaller_data() { QTest::addColumn<PackageManagerCore *>("core"); QTest::addColumn<QList<Component *> >("selectedComponents"); @@ -168,7 +169,7 @@ private slots: core->appendRootComponent(componentA); core->appendRootComponent(componentB); - QTest::newRow("Simple resolved") << core + QTest::newRow("Installer resolved") << core << (QList<Component *>() << componentB) << (QList<Component *>() << componentAB << componentB) << (QList<int>() @@ -176,7 +177,7 @@ private slots: << InstallerCalculator::Resolved); } - void resolve() + void resolveInstaller() { QFETCH(PackageManagerCore *, core); QFETCH(QList<Component *> , selectedComponents); @@ -194,6 +195,51 @@ private slots: } delete core; } + + void resolveUninstaller_data() + { + QTest::addColumn<PackageManagerCore *>("core"); + QTest::addColumn<QList<Component *> >("selectedToUninstall"); + QTest::addColumn<QList<Component *> >("installedComponents"); + QTest::addColumn<QSet<Component *> >("expectedResult"); + + PackageManagerCore *core = new PackageManagerCore(); + core->setPackageManager(); + NamedComponent *componentA = new NamedComponent(core, QLatin1String("A")); + NamedComponent *componentAA = new NamedComponent(core, QLatin1String("A.A")); + NamedComponent *componentAB = new NamedComponent(core, QLatin1String("A.B")); + componentA->appendComponent(componentAA); + componentA->appendComponent(componentAB); + NamedComponent *componentB = new NamedComponent(core, QLatin1String("B")); + componentB->addDependency(QLatin1String("A.B")); + core->appendRootComponent(componentA); + core->appendRootComponent(componentB); + + componentA->setInstalled(); + componentB->setInstalled(); + componentAB->setInstalled(); + + QTest::newRow("Uninstaller resolved") << core + << (QList<Component *>() << componentAB) + << (QList<Component *>() << componentA << componentB << componentAB) + << (QSet<Component *>() << componentAB << componentB); + } + + void resolveUninstaller() + { + QFETCH(PackageManagerCore *, core); + QFETCH(QList<Component *> , selectedToUninstall); + QFETCH(QList<Component *> , installedComponents); + QFETCH(QSet<Component *> , expectedResult); + + UninstallerCalculator calc(installedComponents); + calc.appendComponentsToUninstall(selectedToUninstall); + QSet<Component *> result = calc.componentsToUninstall(); + + QCOMPARE(result.count(), expectedResult.count()); + QCOMPARE(result, expectedResult); + delete core; + } }; QTEST_MAIN(tst_Solver) |