From 21de5f081ab3b18625febcd8ac181f6a122c4c7f Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Tue, 3 May 2022 11:59:21 +0300 Subject: Do not install new dependencies for installed components If component is updated to repository, and new dependencies are added, the dependencies should be installed only when fresh install to component is made or the component is updated. This change adds a new LocalDependencies value to component. It keeps track of the dependencies the local installed packages has. Fixes also a bug in uninstallecalculator, where we should also read the dependencies from local installed packages instead of newly introduced repositories. Task-number: QTIFW-2624 Change-Id: I0557e5adf1e87c0a1238cc455cfb2c90f6b05c87 Reviewed-by: Arttu Tarkiainen --- src/libs/installer/component.cpp | 35 +++++++++- src/libs/installer/component.h | 4 +- src/libs/installer/constants.h | 1 + src/libs/installer/installercalculator.cpp | 4 +- src/libs/installer/packagemanagercore.cpp | 2 + src/libs/installer/packagemanagercore_p.cpp | 10 +-- src/libs/installer/packagemanagercore_p.h | 2 +- src/libs/installer/qinstallerglobal.h | 2 +- src/libs/installer/uninstallercalculator.cpp | 8 +-- src/libs/installer/uninstallercalculator.h | 4 +- .../installPackagesDependencyChanged/Updates.xml | 72 +++++++++++++++++++++ .../componentA/2.0.0content.7z | Bin 0 -> 259 bytes .../componentB/1.0.0content.7z | Bin 0 -> 241 bytes .../componentC/1.0.0content.7z | Bin 0 -> 241 bytes .../componentD/1.0.0content.7z | Bin 0 -> 241 bytes .../componentF/1.0.0content.7z | Bin 0 -> 241 bytes .../componentH/1.0.0content.7z | Bin 0 -> 209 bytes tests/auto/installer/cliinterface/settings.qrc | 7 ++ .../installer/cliinterface/tst_cliinterface.cpp | 39 +++++++++++ tests/auto/installer/solver/tst_solver.cpp | 4 +- 20 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/Updates.xml create mode 100644 tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentA/2.0.0content.7z create mode 100644 tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentB/1.0.0content.7z create mode 100644 tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentC/1.0.0content.7z create mode 100644 tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentD/1.0.0content.7z create mode 100644 tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentF/1.0.0content.7z create mode 100644 tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentH/1.0.0content.7z diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp index 702dd2763..c703bfdcd 100644 --- a/src/libs/installer/component.cpp +++ b/src/libs/installer/component.cpp @@ -308,6 +308,10 @@ void Component::loadDataFromPackage(const KDUpdater::LocalPackage &package) setValue(scTreeName, package.treeName.first); d->m_treeNameMoveChildren = package.treeName.second; + + // scDependencies might be updated from repository later, + // keep the local dependencies as well. + setValue(scLocalDependencies, value(scDependencies)); } /*! @@ -1354,11 +1358,22 @@ void Component::addDependency(const QString &newDependency) setValue(scDependencies, oldDependencies + QLatin1String(", ") + newDependency); } +/*! + Returns a list of dependencies defined in the the repository or in the package.xml. +*/ QStringList Component::dependencies() const { return d->m_vars.value(scDependencies).split(QInstaller::commaRegExp(), Qt::SkipEmptyParts); } +/*! + Returns a list of installed components dependencies defined in the components.xml. +*/ +QStringList Component::localDependencies() const +{ + return d->m_vars.value(scLocalDependencies).split(QInstaller::commaRegExp(), Qt::SkipEmptyParts); +} + /*! Adds the component specified by \a newDependOn to the automatic depend-on list. Alternatively, multiple components can be specified by separating each with @@ -1382,6 +1397,24 @@ QStringList Component::autoDependencies() const return d->m_vars.value(scAutoDependOn).split(QInstaller::commaRegExp(), Qt::SkipEmptyParts); } +/*! + Returns a list of dependencies that the component currently has. The + dependencies can vary when component is already installed with different + dependency list than what is introduced in the repository. If component is + not installed, or update is requested to an installed component, + current dependencies are read from repository so that correct dependencies + are calculated for the component when it is installed or updated. +*/ +QStringList Component::currentDependencies() const +{ + QStringList dependenciesList; + if (isInstalled() && !updateRequested()) + dependenciesList = localDependencies(); + else + dependenciesList = dependencies(); + return dependenciesList; +} + /*! \sa {component::setInstalled}{component.setInstalled} */ @@ -1519,7 +1552,7 @@ bool Component::isUpdateAvailable() const \sa {component::updateRequested}{component.updateRequested} */ -bool Component::updateRequested() +bool Component::updateRequested() const { return d->m_updateIsAvailable && isSelected() && !isUnstable(); } diff --git a/src/libs/installer/component.h b/src/libs/installer/component.h index dbf604a56..e5f1b38da 100644 --- a/src/libs/installer/component.h +++ b/src/libs/installer/component.h @@ -170,8 +170,10 @@ public: Q_INVOKABLE void addDependency(const QString &newDependency); QStringList dependencies() const; + QStringList localDependencies() const; Q_INVOKABLE void addAutoDependOn(const QString &newDependOn); QStringList autoDependencies() const; + QStringList currentDependencies() const; void languageChanged(); QString localTempPath() const; @@ -195,7 +197,7 @@ public: Q_INVOKABLE void setUpdateAvailable(bool isUpdateAvailable); Q_INVOKABLE bool isUpdateAvailable() const; - Q_INVOKABLE bool updateRequested(); + Q_INVOKABLE bool updateRequested() const; Q_INVOKABLE bool componentChangeRequested(); Q_INVOKABLE bool isForcedUpdate(); diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h index af518a0f6..7fa54c4ec 100644 --- a/src/libs/installer/constants.h +++ b/src/libs/installer/constants.h @@ -59,6 +59,7 @@ static const QLatin1String scDisplayName("DisplayName"); static const QLatin1String scTreeName("TreeName"); static const QLatin1String scAutoTreeName("AutoTreeName"); static const QLatin1String scDependencies("Dependencies"); +static const QLatin1String scLocalDependencies("LocalDependencies"); static const QLatin1String scAutoDependOn("AutoDependOn"); static const QLatin1String scNewComponent("NewComponent"); static const QLatin1String scRepositories("Repositories"); diff --git a/src/libs/installer/installercalculator.cpp b/src/libs/installer/installercalculator.cpp index 21e82fc9a..2ef5d3b74 100644 --- a/src/libs/installer/installercalculator.cpp +++ b/src/libs/installer/installercalculator.cpp @@ -109,7 +109,7 @@ bool InstallerCalculator::appendComponentsToInstall(const QList &co } } - if (component->dependencies().isEmpty()) + if (component->currentDependencies().isEmpty()) realAppendToInstallComponents(component, QString(), revertFromInstall); else notAppendedComponents.append(component); @@ -177,7 +177,7 @@ void InstallerCalculator::realAppendToInstallComponents(Component *component, co bool InstallerCalculator::appendComponentToInstall(Component *component, const QString &version, bool revertFromInstall) { - const QStringList dependenciesList = component->dependencies(); + const QStringList dependenciesList = component->currentDependencies(); QSet allDependencies(dependenciesList.begin(), dependenciesList.end()); QString requiredDependencyVersion = version; foreach (const QString &dependencyComponentName, allDependencies) { diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 8ebaefd62..543852e20 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -3922,6 +3922,8 @@ bool PackageManagerCore::updateComponentData(struct Data &data, Component *compo // a possible component to replace that might be installed (to mark the replacement as installed). component->setInstalled(); component->setValue(scInstalledVersion, data.installedPackages->value(name).version); + component->setValue(scLocalDependencies, data.installedPackages->value(name). + dependencies.join(QLatin1String(","))); return true; } diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 85e902ac3..e279a8027 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -463,7 +463,7 @@ void PackageManagerCorePrivate::cleanUpComponentEnvironment() { m_componentReplaces.clear(); m_autoDependencyComponentHash.clear(); - m_dependencyComponentHash.clear(); + m_localDependencyComponentHash.clear(); m_localVirtualComponents.clear(); // clean up registered (downloaded) data if (m_core->isMaintainer()) @@ -596,7 +596,7 @@ UninstallerCalculator *PackageManagerCorePrivate::uninstallerCalculator() const } pmcp->m_uninstallerCalculator = new UninstallerCalculator(installedComponents, m_core, - pmcp->m_autoDependencyComponentHash, pmcp->m_dependencyComponentHash, pmcp->m_localVirtualComponents); + pmcp->m_autoDependencyComponentHash, pmcp->m_localDependencyComponentHash, pmcp->m_localVirtualComponents); } return m_uninstallerCalculator; } @@ -3164,11 +3164,11 @@ void PackageManagerCorePrivate::createDependencyHashes(const Component* componen m_autoDependencyComponentHash.insert(autodepend, value); } - for (const QString &depend : component->dependencies()) { - QStringList value = m_dependencyComponentHash.value(depend); + for (const QString &depend : component->localDependencies()) { + QStringList value = m_localDependencyComponentHash.value(depend); if (!value.contains(component->name())) value.append(component->name()); - m_dependencyComponentHash.insert(depend, value); + m_localDependencyComponentHash.insert(depend, value); } } diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index 3a859f63d..8a5b805d8 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -311,7 +311,7 @@ private: QHash m_coreCheckedHash; QList m_deletedReplacedComponents; AutoDependencyHash m_autoDependencyComponentHash; - DependencyHash m_dependencyComponentHash; + LocalDependencyHash m_localDependencyComponentHash; QStringList m_localVirtualComponents; diff --git a/src/libs/installer/qinstallerglobal.h b/src/libs/installer/qinstallerglobal.h index 5bc87e21d..88f255af6 100644 --- a/src/libs/installer/qinstallerglobal.h +++ b/src/libs/installer/qinstallerglobal.h @@ -58,7 +58,7 @@ typedef QList PackagesList; typedef QMap LocalPackagesMap; typedef QHash AutoDependencyHash; -typedef QHash DependencyHash; +typedef QHash LocalDependencyHash; } // namespace QInstaller diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp index c717f6550..af03df8c5 100644 --- a/src/libs/installer/uninstallercalculator.cpp +++ b/src/libs/installer/uninstallercalculator.cpp @@ -45,12 +45,12 @@ namespace QInstaller { UninstallerCalculator::UninstallerCalculator(const QList &installedComponents , PackageManagerCore *core , const AutoDependencyHash &autoDependencyComponentHash - , const DependencyHash &dependencyComponentHash + , const LocalDependencyHash &localDependencyComponentHash , const QStringList &localVirtualComponents) : m_installedComponents(installedComponents) , m_core(core) , m_autoDependencyComponentHash(autoDependencyComponentHash) - , m_dependencyComponentHash(dependencyComponentHash) + , m_localDependencyComponentHash(localDependencyComponentHash) , m_localVirtualComponents(localVirtualComponents) { } @@ -68,8 +68,8 @@ void UninstallerCalculator::appendComponentToUninstall(Component *component, con if (!component->isInstalled()) return; - if (m_dependencyComponentHash.contains(component->name())) { - const QStringList &dependencies = PackageManagerCore::parseNames(m_dependencyComponentHash.value(component->name())); + 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 && depComponent->isInstalled() && !m_componentsToUninstall.contains(depComponent)) { diff --git a/src/libs/installer/uninstallercalculator.h b/src/libs/installer/uninstallercalculator.h index a458daa80..76e32c6a6 100644 --- a/src/libs/installer/uninstallercalculator.h +++ b/src/libs/installer/uninstallercalculator.h @@ -55,7 +55,7 @@ public: UninstallerCalculator(const QList &installedComponents, PackageManagerCore *core, const AutoDependencyHash &autoDependencyComponentHash, - const DependencyHash &dependencyComponentHash, + const LocalDependencyHash &localDependencyComponentHash, const QStringList &localVirtualComponents); QSet componentsToUninstall() const; @@ -78,7 +78,7 @@ private: PackageManagerCore *m_core; QHash > m_toUninstallComponentIdReasonHash; AutoDependencyHash m_autoDependencyComponentHash; - DependencyHash m_dependencyComponentHash; + LocalDependencyHash m_localDependencyComponentHash; QStringList m_localVirtualComponents; QList m_virtualComponentsForReverse; }; diff --git a/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/Updates.xml b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/Updates.xml new file mode 100644 index 000000000..72931954a --- /dev/null +++ b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/Updates.xml @@ -0,0 +1,72 @@ + + {AnyApplication} + 1.0.0 + false + + componentA + Component A + New dependency added + 2.0.0 + 2014-08-25 + 100 + + content.7z + 92b02a74d0886bc1569ff8b3a7edd1f9d828e56c + componentF + + + componentB + Component B + This component does not depend on any other component. + 1.0.0 + 2014-08-25 + 90 + + content.7z + aedfaef53cdc0f52353a8680009be405fa767811 + + + componentC + Component C. Dependencies removed + This component dependencies on Component A and Component B are removed in update. + + 1.0.0 + 2014-08-25 + 80 + + content.7z + 20b9463a5e06f373182b3c7c4cf879806d429409 + + + componentD + Component D (auto depends on A and B) + This component has an automatic dependency on Component A and Component B. If both A and B are marked for installation, this component is also installed. + componentA, componentB + 1.0.0 + 2014-08-25 + 70 + + content.7z + 99cf24c71559c75dfae9933826ed16051fca6ea1 + + + componentF + Component F + This component contains 2 subcomponents. + 1.0.0 + 2014-08-25 + 40 + + content.7z + e6443a8b5a5651f63c0604cae6d32431ca617f1a + + + componentH + This component does not depend on any other component. + 1.0.0 + 2014-08-25 + 50 + content.7z + false + + diff --git a/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentA/2.0.0content.7z b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentA/2.0.0content.7z new file mode 100644 index 000000000..4ddbe565b Binary files /dev/null and b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentA/2.0.0content.7z differ diff --git a/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentB/1.0.0content.7z b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentB/1.0.0content.7z new file mode 100644 index 000000000..f84ffcdc5 Binary files /dev/null and b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentB/1.0.0content.7z differ diff --git a/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentC/1.0.0content.7z b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentC/1.0.0content.7z new file mode 100644 index 000000000..9ad11e06f Binary files /dev/null and b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentC/1.0.0content.7z differ diff --git a/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentD/1.0.0content.7z b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentD/1.0.0content.7z new file mode 100644 index 000000000..0c8c52e31 Binary files /dev/null and b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentD/1.0.0content.7z differ diff --git a/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentF/1.0.0content.7z b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentF/1.0.0content.7z new file mode 100644 index 000000000..4a04b1394 Binary files /dev/null and b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentF/1.0.0content.7z differ diff --git a/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentH/1.0.0content.7z b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentH/1.0.0content.7z new file mode 100644 index 000000000..e1449ad29 Binary files /dev/null and b/tests/auto/installer/cliinterface/data/installPackagesDependencyChanged/componentH/1.0.0content.7z differ diff --git a/tests/auto/installer/cliinterface/settings.qrc b/tests/auto/installer/cliinterface/settings.qrc index 6b46aaffd..824517e1e 100644 --- a/tests/auto/installer/cliinterface/settings.qrc +++ b/tests/auto/installer/cliinterface/settings.qrc @@ -21,6 +21,13 @@ data/installPackagesRepository/componentF.subcomponent1.subsubcomponent2/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2.subsubcomponent1/1.0.0content.7z data/installPackagesRepository/componentF.subcomponent2.subsubcomponent2/1.0.0content.7z + data/installPackagesDependencyChanged/Updates.xml + data/installPackagesDependencyChanged/componentA/2.0.0content.7z + data/installPackagesDependencyChanged/componentB/1.0.0content.7z + data/installPackagesDependencyChanged/componentC/1.0.0content.7z + data/installPackagesDependencyChanged/componentD/1.0.0content.7z + data/installPackagesDependencyChanged/componentF/1.0.0content.7z + data/installPackagesDependencyChanged/componentH/1.0.0content.7z data/filequeryrepository/Updates.xml data/filequeryrepository/A/1.0.2-1meta.7z data/componentsFromInstallPackagesRepository.xml diff --git a/tests/auto/installer/cliinterface/tst_cliinterface.cpp b/tests/auto/installer/cliinterface/tst_cliinterface.cpp index c43eca381..8f1784543 100644 --- a/tests/auto/installer/cliinterface/tst_cliinterface.cpp +++ b/tests/auto/installer/cliinterface/tst_cliinterface.cpp @@ -413,6 +413,45 @@ private slots: << "installcontentA.txt" << "installcontentE.txt" << "installcontentG.txt"); } + void testInstallPackagesWithChangedRepository() + { + QScopedPointer core(PackageManager::getPackageManagerWithInit + (m_installDir, ":///data/installPackagesRepository")); + core->setNoDefaultInstallation(true); + QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() + << QLatin1String("componentC"))); + + QCOMPARE(PackageManagerCore::Success, core->status()); + VerifyInstaller::verifyInstallerResources(m_installDir, "componentA", "1.0.0content.txt"); //Dependency to componentC + VerifyInstaller::verifyInstallerResources(m_installDir, "componentB", "1.0.0content.txt"); //Dependency to componentC + VerifyInstaller::verifyInstallerResources(m_installDir, "componentC", "1.0.0content.txt"); //Selected + VerifyInstaller::verifyInstallerResources(m_installDir, "componentD", "1.0.0content.txt"); //Autodepend on componentA,componentB + VerifyInstaller::verifyInstallerResources(m_installDir, "componentE", "1.0.0content.txt"); //AutodependOn componentC + VerifyInstaller::verifyInstallerResources(m_installDir, "componentI", "1.0.0content.txt"); //Virtual dependency to componentC + VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" + << "installcontent.txt" << "installcontentA.txt" << "installcontentB.txt" + << "installcontentC.txt" << "installcontentD.txt" << "installcontentE.txt" + << "installcontentI.txt"); + + core->reset(); + core->cancelMetaInfoJob(); //Call cancel to reset metadata so that update repositories are fetched + + QSet repoList; + Repository repo = Repository::fromUserInput(":///data/installPackagesDependencyChanged"); + repoList.insert(repo); + core->settings().setDefaultRepositories(repoList); + + QCOMPARE(PackageManagerCore::Success, core->installSelectedComponentsSilently(QStringList() + << QLatin1String("componentH"))); + // New dependency is added in repository from componentA to componentF, check that it is not installed + VerifyInstaller::verifyInstallerResourcesDeletion(m_installDir, "componentF"); + VerifyInstaller::verifyFileExistence(m_installDir, QStringList() << "components.xml" + << "installcontent.txt" << "installcontentA.txt" << "installcontentB.txt" + << "installcontentC.txt" << "installcontentD.txt" << "installcontentE.txt" + << "installcontentI.txt" << "installcontentH.txt"); + core->setNoDefaultInstallation(false); + } + void testUnInstallDefaultPackagesSilently() { QScopedPointer core(PackageManager::getPackageManagerWithInit diff --git a/tests/auto/installer/solver/tst_solver.cpp b/tests/auto/installer/solver/tst_solver.cpp index 45fadc4e6..8b5d1fdcf 100644 --- a/tests/auto/installer/solver/tst_solver.cpp +++ b/tests/auto/installer/solver/tst_solver.cpp @@ -252,7 +252,7 @@ private slots: QTest::addColumn >("installedComponents"); QTest::addColumn >("expectedResult"); QTest::addColumn("uninstallReasons"); - QTest::addColumn("dependencyHash"); + QTest::addColumn("dependencyHash"); UninstallReasonList uninstallReasonList; PackageManagerCore *core = new PackageManagerCore(); @@ -317,7 +317,7 @@ private slots: QFETCH(QList , installedComponents); QFETCH(QSet , expectedResult); QFETCH(UninstallReasonList, uninstallReasons); - QFETCH(DependencyHash, dependencyHash); + QFETCH(LocalDependencyHash, dependencyHash); UninstallerCalculator calc(installedComponents, core, QHash(), dependencyHash, QStringList()); calc.appendComponentsToUninstall(selectedToUninstall); -- cgit v1.2.3