diff options
author | kh1 <karsten.heimrich@digia.com> | 2014-10-01 22:37:09 +0200 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@digia.com> | 2014-10-06 16:08:23 +0200 |
commit | f288f29e92102f7779101a59515f86bce64a3713 (patch) | |
tree | f44ad581f551f272fb03610c401bddc73b9f10d3 /src/libs | |
parent | 8941d7affa7dddf6780e79172bcb3c0d67fca128 (diff) |
Move InstallerCalculator into its own header
Make it public, so that it can be used outside (e.g. in tests)
Change-Id: I2a307dcd6f2eb017f9ac26de06d77deb0d668fbe
Reviewed-by: Jarek Kobus <jaroslaw.kobus@digia.com>
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/installer/installer.pro | 6 | ||||
-rw-r--r-- | src/libs/installer/installercalculator.cpp | 219 | ||||
-rw-r--r-- | src/libs/installer/installercalculator.h | 98 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 1 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 168 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.h | 40 |
6 files changed, 323 insertions, 209 deletions
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro index 97fa4904a..290f78d37 100644 --- a/src/libs/installer/installer.pro +++ b/src/libs/installer/installer.pro @@ -120,7 +120,8 @@ HEADERS += packagemanagercore.h \ remoteserverconnection_p.h \ fileio.h \ binarycontent.h \ - binarylayout.h + binarylayout.h \ + installercalculator.h SOURCES += packagemanagercore.cpp \ packagemanagercore_p.cpp \ @@ -189,7 +190,8 @@ SOURCES += packagemanagercore.cpp \ remoteserverconnection.cpp \ fileio.cpp \ binarycontent.cpp \ - binarylayout.cpp + binarylayout.cpp \ + installercalculator.cpp RESOURCES += resources/patch_file_lists.qrc \ resources/installer.qrc diff --git a/src/libs/installer/installercalculator.cpp b/src/libs/installer/installercalculator.cpp new file mode 100644 index 000000000..2fe3c9915 --- /dev/null +++ b/src/libs/installer/installercalculator.cpp @@ -0,0 +1,219 @@ +/************************************************************************** +** +** 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 "installercalculator.h" + +#include "component.h" +#include "packagemanagercore.h" + +#include <QDebug> + +namespace QInstaller { + +InstallerCalculator::InstallerCalculator(const QList<Component *> &allComponents) + : m_allComponents(allComponents) +{ +} + +void InstallerCalculator::insertInstallReason(Component *component, + InstallReasonType installReason, const QString &referencedComponentName) +{ + // keep the first reason + if (m_toInstallComponentIdReasonHash.contains(component->name())) + return; + m_toInstallComponentIdReasonHash.insert(component->name(), + qMakePair(installReason, referencedComponentName)); +} + +InstallerCalculator::InstallReasonType InstallerCalculator::installReasonType(Component *c) const +{ + return m_toInstallComponentIdReasonHash.value(c->name(), + qMakePair(InstallerCalculator::Selected, QString())).first; +} + +QString InstallerCalculator::installReasonReferencedComponent(Component *component) const +{ + return m_toInstallComponentIdReasonHash.value(component->name(), + qMakePair(InstallerCalculator::Selected, QString())).second; +} + +QString InstallerCalculator::installReason(Component *component) const +{ + InstallerCalculator::InstallReasonType reason = installReasonType(component); + switch (reason) { + case Automatic: + return QCoreApplication::translate("InstallerCalculator", + "Components added as automatic dependencies:"); + case Dependent: + return QCoreApplication::translate("InstallerCalculator", "Components added as " + "dependency for '%1':").arg(installReasonReferencedComponent(component)); + case Resolved: + return QCoreApplication::translate("InstallerCalculator", + "Components that have resolved dependencies:"); + case Selected: + return QCoreApplication::translate("InstallerCalculator", + "Selected components without dependencies:"); + } + return QString(); +} + +QList<Component*> InstallerCalculator::orderedComponentsToInstall() const +{ + return m_orderedComponentsToInstall; +} + +QString InstallerCalculator::componentsToInstallError() const +{ + return m_componentsToInstallError; +} + +void InstallerCalculator::realAppendToInstallComponents(Component *component) +{ + if (!component->isInstalled() || component->updateRequested()) { + // remove the checkState method if we don't use selected in scripts + component->setCheckState(Qt::Checked); + + m_orderedComponentsToInstall.append(component); + m_toInstallComponentIds.insert(component->name()); + } +} + +QString InstallerCalculator::recursionError(Component *component) +{ + return QCoreApplication::translate("InstallerCalculator", "Recursion detected, component '%1' " + "already added with reason: '%2'").arg(component->name(), installReason(component)); +} + +bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &components) +{ + if (components.isEmpty()) + return true; + + QList<Component*> notAppendedComponents; // for example components with unresolved dependencies + foreach (Component *component, components){ + if (m_toInstallComponentIds.contains(component->name())) { + const QString errorMessage = recursionError(component); + qWarning() << errorMessage; + m_componentsToInstallError.append(errorMessage); + Q_ASSERT_X(!m_toInstallComponentIds.contains(component->name()), Q_FUNC_INFO, + qPrintable(errorMessage)); + return false; + } + + if (component->dependencies().isEmpty()) + realAppendToInstallComponents(component); + else + notAppendedComponents.append(component); + } + + foreach (Component *component, notAppendedComponents) { + if (!appendComponentToInstall(component)) + return false; + } + + QList<Component *> foundAutoDependOnList; + // All regular dependencies are resolved. Now we are looking for auto depend on components. + foreach (Component *component, m_allComponents) { + // If a components is already installed or is scheduled for installation, no need to check + // for auto depend installation. + if ((!component->isInstalled() || component->updateRequested()) + && !m_toInstallComponentIds.contains(component->name())) { + // If we figure out a component requests auto installation, keep it to resolve + // their dependencies as well. + if (component->isAutoDependOn(m_toInstallComponentIds)) { + foundAutoDependOnList.append(component); + insertInstallReason(component, InstallerCalculator::Automatic); + } + } + } + + if (!foundAutoDependOnList.isEmpty()) + return appendComponentsToInstall(foundAutoDependOnList); + return true; +} + +bool InstallerCalculator::appendComponentToInstall(Component *component) +{ + QSet<QString> allDependencies = component->dependencies().toSet(); + + foreach (const QString &dependencyComponentName, allDependencies) { + // PackageManagerCore::componentByName returns 0 if dependencyComponentName contains a + // version which is not available + Component *dependencyComponent = + PackageManagerCore::componentByName(dependencyComponentName, m_allComponents); + if (!dependencyComponent) { + const QString errorMessage = QCoreApplication::translate("InstallerCalculator", + "Cannot find missing dependency '%1' for '%2'.").arg(dependencyComponentName, + component->name()); + qWarning() << errorMessage; + m_componentsToInstallError.append(errorMessage); + return false; + } + + if ((!dependencyComponent->isInstalled() || dependencyComponent->updateRequested()) + && !m_toInstallComponentIds.contains(dependencyComponent->name())) { + if (m_visitedComponents.value(component).contains(dependencyComponent)) { + const QString errorMessage = recursionError(component); + qWarning() << errorMessage; + m_componentsToInstallError = errorMessage; + Q_ASSERT_X(!m_visitedComponents.value(component).contains(dependencyComponent), + Q_FUNC_INFO, qPrintable(errorMessage)); + return false; + } + m_visitedComponents[component].insert(dependencyComponent); + + // add needed dependency components to the next run + insertInstallReason(dependencyComponent, InstallerCalculator::Dependent, + component->name()); + + if (!appendComponentToInstall(dependencyComponent)) + return false; + } + } + + if (!m_toInstallComponentIds.contains(component->name())) { + realAppendToInstallComponents(component); + insertInstallReason(component, InstallerCalculator::Resolved); + } + return true; +} + +} // namespace QInstaller diff --git a/src/libs/installer/installercalculator.h b/src/libs/installer/installercalculator.h new file mode 100644 index 000000000..1552f94cc --- /dev/null +++ b/src/libs/installer/installercalculator.h @@ -0,0 +1,98 @@ +/************************************************************************** +** +** 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 INSTALLERCALCULATOR_H +#define INSTALLERCALCULATOR_H + +#include "installer_global.h" + +#include <QHash> +#include <QList> +#include <QSet> +#include <QString> + +namespace QInstaller { + +class Component; + +class INSTALLER_EXPORT InstallerCalculator +{ +public: + InstallerCalculator(const QList<Component *> &allComponents); + + enum InstallReasonType + { + Automatic, // "Component(s) added as automatic dependencies" + Dependent, // "Added as dependency for %1." + Resolved, // "Component(s) that have resolved Dependencies" + Selected // "Selected Component(s) without Dependencies" + }; + + InstallReasonType installReasonType(Component *component) const; + QString installReasonReferencedComponent(Component *component) const; + QString installReason(Component *component) const; + QList<Component*> orderedComponentsToInstall() const; + QString componentsToInstallError() const; + + bool appendComponentsToInstall(const QList<Component*> &components); + +private: + void insertInstallReason(Component *component, + InstallReasonType installReasonType, + const QString &referencedComponentName = QString()); + void realAppendToInstallComponents(Component *component); + bool appendComponentToInstall(Component *components); + QString recursionError(Component *component); + + QList<Component*> m_allComponents; + QHash<Component*, QSet<Component*> > m_visitedComponents; + QSet<QString> m_toInstallComponentIds; //for faster lookups + QString m_componentsToInstallError; + //calculate installation order variables + QList<Component*> m_orderedComponentsToInstall; + //we can't use this reason hash as component id hash, because some reasons are ready before + //the component is added + QHash<QString, QPair<InstallReasonType, QString> > m_toInstallComponentIdReasonHash; +}; + +} + + +#endif // INSTALLERCALCULATOR_H diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index efaa05ab5..79cb80261 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -56,6 +56,7 @@ #include "remoteclient.h" #include "settings.h" #include "utils.h" +#include "installercalculator.h" #include <productkeycheck.h> diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 6e24ce110..ca9aca625 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -59,6 +59,7 @@ #include "protocol.h" #include "qsettingswrapper.h" #include "remoteclient.h" +#include "installercalculator.h" #include "kdselfrestarter.h" #include "kdupdaterfiledownloaderfactory.h" @@ -182,174 +183,7 @@ static void deferredRename(const QString &oldName, const QString &newName, bool #endif } -InstallerCalculator::InstallerCalculator(const QList<Component *> &allComponents) - : m_allComponents(allComponents) -{ -} - -void InstallerCalculator::insertInstallReason(Component *component, - InstallReasonType installReason, const QString &referencedComponentName) -{ - // keep the first reason - if (m_toInstallComponentIdReasonHash.contains(component->name())) - return; - m_toInstallComponentIdReasonHash.insert(component->name(), - qMakePair(installReason, referencedComponentName)); -} - -InstallerCalculator::InstallReasonType InstallerCalculator::installReasonType(Component *component) const -{ - return m_toInstallComponentIdReasonHash.value(component->name(), - qMakePair(InstallerCalculator::Selected, QString())).first; -} - -QString InstallerCalculator::installReasonReferencedComponent(Component *component) const -{ - return m_toInstallComponentIdReasonHash.value(component->name(), - qMakePair(InstallerCalculator::Selected, QString())).second; -} - -QString InstallerCalculator::installReason(Component *component) const -{ - InstallerCalculator::InstallReasonType reason = installReasonType(component); - switch (reason) { - case Automatic: - return QCoreApplication::translate("InstallerCalculator", - "Components added as automatic dependencies:"); - case Dependent: - return QCoreApplication::translate("InstallerCalculator", "Components added as " - "dependency for '%1':").arg(installReasonReferencedComponent(component)); - case Resolved: - return QCoreApplication::translate("InstallerCalculator", - "Components that have resolved dependencies:"); - case Selected: - return QCoreApplication::translate("InstallerCalculator", - "Selected components without dependencies:"); - } - return QString(); -} - -QList<Component*> InstallerCalculator::orderedComponentsToInstall() const -{ - return m_orderedComponentsToInstall; -} - -QString InstallerCalculator::componentsToInstallError() const -{ - return m_componentsToInstallError; -} - -void InstallerCalculator::realAppendToInstallComponents(Component *component) -{ - if (!component->isInstalled() || component->updateRequested()) { - // remove the checkState method if we don't use selected in scripts - component->setCheckState(Qt::Checked); - - m_orderedComponentsToInstall.append(component); - m_toInstallComponentIds.insert(component->name()); - } -} - -QString InstallerCalculator::recursionError(Component *component) -{ - return QCoreApplication::translate("InstallerCalculator", "Recursion detected, component '%1' " - "already added with reason: '%2'").arg(component->name(), installReason(component)); -} - -bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &components) -{ - if (components.isEmpty()) { - return true; - } - - QList<Component*> notAppendedComponents; // for example components with unresolved dependencies - foreach (Component *component, components){ - if (m_toInstallComponentIds.contains(component->name())) { - const QString errorMessage = recursionError(component); - qWarning() << errorMessage; - m_componentsToInstallError.append(errorMessage); - Q_ASSERT_X(!m_toInstallComponentIds.contains(component->name()), Q_FUNC_INFO, - qPrintable(errorMessage)); - return false; - } - - if (component->dependencies().isEmpty()) - realAppendToInstallComponents(component); - else - notAppendedComponents.append(component); - } - foreach (Component *component, notAppendedComponents) { - if (!appendComponentToInstall(component)) - return false; - } - - QList<Component *> foundAutoDependOnList; - // All regular dependencies are resolved. Now we are looking for auto depend on components. - foreach (Component *component, m_allComponents) { - // If a components is already installed or is scheduled for installation, no need to check - // for auto depend installation. - if ((!component->isInstalled() || component->updateRequested()) - && !m_toInstallComponentIds.contains(component->name())) { - // If we figure out a component requests auto installation, keep it to resolve - // their dependencies as well. - if (component->isAutoDependOn(m_toInstallComponentIds)) { - foundAutoDependOnList.append(component); - insertInstallReason(component, InstallerCalculator::Automatic); - } - } - } - - if (!foundAutoDependOnList.isEmpty()) - return appendComponentsToInstall(foundAutoDependOnList); - return true; -} - -bool InstallerCalculator::appendComponentToInstall(Component *component) -{ - QSet<QString> allDependencies = component->dependencies().toSet(); - - foreach (const QString &dependencyComponentName, allDependencies) { - // PackageManagerCore::componentByName returns 0 if dependencyComponentName contains a - // version which is not available - Component *dependencyComponent = - PackageManagerCore::componentByName(dependencyComponentName, m_allComponents); - if (!dependencyComponent) { - const QString errorMessage = QCoreApplication::translate("InstallerCalculator", - "Cannot find missing dependency '%1' for '%2'.").arg(dependencyComponentName, - component->name()); - qWarning() << errorMessage; - m_componentsToInstallError.append(errorMessage); - return false; - } - - if ((!dependencyComponent->isInstalled() || dependencyComponent->updateRequested()) - && !m_toInstallComponentIds.contains(dependencyComponent->name())) { - if (m_visitedComponents.value(component).contains(dependencyComponent)) { - const QString errorMessage = recursionError(component); - qWarning() << errorMessage; - m_componentsToInstallError = errorMessage; - Q_ASSERT_X(!m_visitedComponents.value(component).contains(dependencyComponent), - Q_FUNC_INFO, qPrintable(errorMessage)); - return false; - } - m_visitedComponents[component].insert(dependencyComponent); - - // add needed dependency components to the next run - insertInstallReason(dependencyComponent, InstallerCalculator::Dependent, - component->name()); - - if (!appendComponentToInstall(dependencyComponent)) - return false; - } - } - - if (!m_toInstallComponentIds.contains(component->name())) { - realAppendToInstallComponents(component); - insertInstallReason(component, InstallerCalculator::Resolved); - } - return true; -} // -- PackageManagerCorePrivate diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index 6ae1632ae..06ccaf50d 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -92,46 +92,6 @@ public: } }; -class InstallerCalculator -{ -public: - InstallerCalculator(const QList<Component *> &allComponents); - - enum InstallReasonType - { - Automatic, // "Component(s) added as automatic dependencies" - Dependent, // "Added as dependency for %1." - Resolved, // "Component(s) that have resolved Dependencies" - Selected // "Selected Component(s) without Dependencies" - }; - - InstallReasonType installReasonType(Component *component) const; - QString installReasonReferencedComponent(Component *component) const; - QString installReason(Component *component) const; - QList<Component*> orderedComponentsToInstall() const; - QString componentsToInstallError() const; - - bool appendComponentsToInstall(const QList<Component*> &components); - -private: - void insertInstallReason(Component *component, - InstallReasonType installReasonType, - const QString &referencedComponentName = QString()); - void realAppendToInstallComponents(Component *component); - bool appendComponentToInstall(Component *components); - QString recursionError(Component *component); - - QList<Component*> m_allComponents; - QHash<Component*, QSet<Component*> > m_visitedComponents; - QSet<QString> m_toInstallComponentIds; //for faster lookups - QString m_componentsToInstallError; - //calculate installation order variables - QList<Component*> m_orderedComponentsToInstall; - //we can't use this reason hash as component id hash, because some reasons are ready before - //the component is added - QHash<QString, QPair<InstallReasonType, QString> > m_toInstallComponentIdReasonHash; -}; - class PackageManagerCorePrivate : public QObject { Q_OBJECT |