summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2021-12-22 11:54:43 +0200
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-01-06 13:06:28 +0200
commitc048aecb4858286a1516dba50317b4568f0d5c3d (patch)
tree9565c33387ca7cc6f665182ddbf22847288ffee0
parent46ce6b3127061b4645ef91fe0a63119337da4848 (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.cpp43
-rw-r--r--tests/auto/installer/treename/data/components.xml59
-rw-r--r--tests/auto/installer/treename/settings.qrc2
-rw-r--r--tests/auto/installer/treename/tst_treename.cpp59
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();