diff options
author | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2021-12-22 11:54:43 +0200 |
---|---|---|
committer | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2022-01-06 13:06:28 +0200 |
commit | c048aecb4858286a1516dba50317b4568f0d5c3d (patch) | |
tree | 9565c33387ca7cc6f665182ddbf22847288ffee0 | |
parent | 46ce6b3127061b4645ef91fe0a63119337da4848 (diff) |
Do not replace conflicting remote packages silently with locals
On (tree)name conflicts with other than the same component in local and
remote packages - instead of silently replacing the remote package with
local, do one of the following:
- Remote package A may have declared the same tree name as installed
local package B. Catch the case and re-register package A as an
unstable component with the original name, if possible.
- Remote package A may have declared a tree name that conflicts with
local package B's name. Do not register component A.
Change-Id: I16ac583ea10bf203d8b8d0b19e6890f03cf0067a
Reviewed-by: Katja Marttila <katja.marttila@qt.io>
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 43 | ||||
-rw-r--r-- | tests/auto/installer/treename/data/components.xml | 59 | ||||
-rw-r--r-- | tests/auto/installer/treename/settings.qrc | 2 | ||||
-rw-r--r-- | tests/auto/installer/treename/tst_treename.cpp | 59 |
4 files changed, 158 insertions, 5 deletions
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index bb2eca6e6..81c0bea3a 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -3909,14 +3909,47 @@ bool PackageManagerCore::fetchAllPackages(const PackagesList &remotes, const Loc } else if (remoteTreeNameComponents.contains(localComponent->name())) { const QString remoteTreeName = remoteTreeNameComponents.value(localComponent->name()); const QString localTreeName = localComponent->value(scTreeName); - if (remoteTreeName != localTreeName) + if (remoteTreeName != localTreeName) { delete allComponents.take(remoteTreeNameComponents.value(localComponent->name())); - else + } else { + // 3. Component has same treename in local and remote, don't add the component again. continue; - // 3. Component has same treename in local and remote, don't add the component again. - } else if (allComponents.contains(name)) { - continue; + } + // 4. Component does not have treename in local or remote, don't add the component again. + } else if (allComponents.contains(localComponent->name())) { + Component *const component = allComponents.value(localComponent->name()); + if (component->value(scTreeName).isEmpty() && localComponent->value(scTreeName).isEmpty()) + continue; + } + // 5. Remote has treename for a different component that is already reserved + // by this local component, Or, remote adds component without treename + // but it conflicts with a local treename. + if (allComponents.contains(name)) { + const QString key = remoteTreeNameComponents.key(name); + qCritical() << "Cannot register component" << (key.isEmpty() ? name : key) + << "with name" << name << "! Component with identifier" << name + << "already exists."; + + if (!key.isEmpty()) + allTreeNameComponents.remove(key); + + // Try to re-add the remote component as unstable + if (!key.isEmpty() && !allComponents.contains(key) && settings().allowUnstableComponents()) { + qCDebug(lcInstallerInstallLog) + << "Registering component with the original indetifier:" << key; + + Component *component = allComponents.take(name); + component->removeValue(scTreeName); + const QString errorString = QLatin1String("Tree name conflicts with an existing indentifier"); + d->m_pendingUnstableComponents.insert(component->name(), + QPair<Component::UnstableError, QString>(Component::InvalidTreeName, errorString)); + + allComponents.insert(key, component); + } else { + delete allComponents.take(name); + } } + const QString treeName = localComponent->value(scTreeName); if (!treeName.isEmpty()) allTreeNameComponents.insert(localComponent->name(), treeName); diff --git a/tests/auto/installer/treename/data/components.xml b/tests/auto/installer/treename/data/components.xml new file mode 100644 index 000000000..0cb0e9826 --- /dev/null +++ b/tests/auto/installer/treename/data/components.xml @@ -0,0 +1,59 @@ +<Packages> + <ApplicationName>Test Application</ApplicationName> + <ApplicationVersion>1.0.0</ApplicationVersion> + <Package> + <Name>ASub2ToRoot</Name> + <Title>Root component 1</Title> + <Description>A package without treename (remote treename conflicts with local name)</Description> + <TreeName></TreeName> + <Version>1.0.0-1</Version> + <LastUpdateDate></LastUpdateDate> + <InstallDate>2021-01-01</InstallDate> + <Size>0</Size> + <Checkable>true</Checkable> + </Package> + <Package> + <Name>B</Name> + <Title>Root component 2</Title> + <Description>A package with treename (remote treename conflicts with local treename)</Description> + <TreeName>BSub2ToRoot</TreeName> + <Version>1.0.0-1</Version> + <LastUpdateDate></LastUpdateDate> + <InstallDate>2021-01-01</InstallDate> + <Size>0</Size> + <Checkable>true</Checkable> + </Package> + <Package> + <Name>componentB.sub1.sub2</Name> + <Title>Sub component</Title> + <Description>A package with treename (remote has different treename)</Description> + <TreeName>componentC.sub2</TreeName> + <Version>1.0.0-1</Version> + <LastUpdateDate></LastUpdateDate> + <InstallDate>2021-01-01</InstallDate> + <Size>0</Size> + <Checkable>true</Checkable> + </Package> + <Package> + <Name>C</Name> + <Title>Root component 3</Title> + <Description>A package with treename (remote name conflicts with local treename)</Description> + <TreeName>componentA</TreeName> + <Version>1.0.0-1</Version> + <LastUpdateDate></LastUpdateDate> + <InstallDate>2021-01-01</InstallDate> + <Size>0</Size> + <Checkable>true</Checkable> + </Package> + <Package> + <Name>componentD</Name> + <Title>Root component 4</Title> + <Description>A package with treename (remote does not have treename)</Description> + <TreeName>componentDNew</TreeName> + <Version>1.0.0-1</Version> + <LastUpdateDate></LastUpdateDate> + <InstallDate>2021-01-01</InstallDate> + <Size>0</Size> + <Checkable>true</Checkable> + </Package> +</Packages> diff --git a/tests/auto/installer/treename/settings.qrc b/tests/auto/installer/treename/settings.qrc index eab771bee..9b31cbade 100644 --- a/tests/auto/installer/treename/settings.qrc +++ b/tests/auto/installer/treename/settings.qrc @@ -1,5 +1,7 @@ <RCC> <qresource prefix="/"> + <file>data/components.xml</file> + <file>data/repository/Updates.xml</file> <file>data/repository/componentA/1.0.0meta.7z</file> <file>data/repository/componentA/1.0.0content.7z</file> diff --git a/tests/auto/installer/treename/tst_treename.cpp b/tests/auto/installer/treename/tst_treename.cpp index 974bc08cc..3d42126eb 100644 --- a/tests/auto/installer/treename/tst_treename.cpp +++ b/tests/auto/installer/treename/tst_treename.cpp @@ -59,6 +59,8 @@ private slots: void replaceComponentWithTreeName(); void replaceComponentWithTreeNameMoveChildren(); + void remotePackageConflictsLocal(); + void init(); void cleanup(); @@ -381,6 +383,63 @@ void tst_TreeName::autoDependOnMovedSubItem() << "installcontentA.txt" << "installcontentA_1.txt" << "installcontentB.txt"); } +void tst_TreeName::remotePackageConflictsLocal() +{ + const QString packageHubFile = qApp->applicationDirPath() + QDir::separator() + "components.xml"; + QFile::remove(packageHubFile); + QVERIFY(QFile::copy(":///data/components.xml", packageHubFile)); + // For some reason Windows sets the read-only flag when we copy the resource.. + QVERIFY(setDefaultFilePermissions(packageHubFile, DefaultFilePermissions::NonExecutable)); + + QHash<QString, QString> params; + params.insert(scTargetDir, qApp->applicationDirPath()); + PackageManagerCore core(BinaryContent::MagicPackageManagerMarker, QList<OperationBlob>(), + QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production, params); + + core.settings().setAllowUnstableComponents(true); + core.settings().setDefaultRepositories(QSet<Repository>() + << Repository::fromUserInput(":///data/repository")); + + QVERIFY(core.fetchRemotePackagesTree()); + { + // Remote treename conflicts with local name + Component *const local = core.componentByName("ASub2ToRoot"); + QVERIFY(local && local->isInstalled()); + + Component *const remote = core.componentByName("componentA.sub2"); + QVERIFY(remote && remote->isUnstable()); + QCOMPARE(remote->treeName(), remote->name()); + } + { + // Remote treename conflicts with local treename + Component *const local = core.componentByName("B"); + QVERIFY(local && local->isInstalled() && local->treeName() == "BSub2ToRoot"); + + Component *const remote = core.componentByName("componentB.sub2"); + QVERIFY(remote && remote->isUnstable()); + QCOMPARE(remote->treeName(), remote->name()); + } + { + // Remote name conflicts with local treename + Component *const local = core.componentByName("C"); + QVERIFY(local && local->isInstalled() && local->treeName() == "componentA"); + + Component *const remote = core.componentByName("componentA"); + QVERIFY(!remote); + } + { + // Component has a treename in local but not in remote, add with local treename + Component *const component = core.componentByName("componentD"); + QVERIFY(component && component->isInstalled() && component->treeName() == "componentDNew"); + } + { + // Component has different treename in local and remote, add with local treename + Component *const component = core.componentByName("componentB.sub1.sub2"); + QVERIFY(component && component->isInstalled() && component->treeName() == "componentC.sub2"); + } + QVERIFY(QFile::remove(packageHubFile)); +} + void tst_TreeName::init() { m_installDir = QInstaller::generateTemporaryFileName(); |