Make installer to check the dependency version

Installer was able to install dependency correctly. However, it ignored
the version dependency might have.
Dependencies>componentA->=4.0</Dependencies>
If there was already a dependency installed with lower version number,
the newer version, which was required by the selected component, was not
installed. Fixed so that maintenancetool will not only check if the
dependency is installed but also the installed version.

Change-Id: Ia26b5233cf8847bce73095d19a13c481318d27f2
Task-number: QTIFW-914
Reviewed-by: Iikka Eklund <iikka.eklund@qt.io>
This commit is contained in:
Katja Marttila 2017-03-14 14:30:09 +02:00
parent 9772474dd9
commit 7ee08852f3
5 changed files with 89 additions and 27 deletions

View File

@ -1241,9 +1241,13 @@ bool Component::isDefault() const
return d->m_vars.value(scDefault).compare(scTrue, Qt::CaseInsensitive) == 0; return d->m_vars.value(scDefault).compare(scTrue, Qt::CaseInsensitive) == 0;
} }
bool Component::isInstalled() const bool Component::isInstalled(const QString version) const
{ {
return scInstalled == d->m_vars.value(scCurrentState); if (version.isEmpty()) {
return scInstalled == d->m_vars.value(scCurrentState);
} else {
return d->m_vars.value(scInstalledVersion) == version;
}
} }
/*! /*!

View File

@ -166,7 +166,7 @@ public:
Q_INVOKABLE bool isAutoDependOn(const QSet<QString> &componentsToInstall) const; Q_INVOKABLE bool isAutoDependOn(const QSet<QString> &componentsToInstall) const;
Q_INVOKABLE void setInstalled(); Q_INVOKABLE void setInstalled();
Q_INVOKABLE bool isInstalled() const; Q_INVOKABLE bool isInstalled(const QString version = QString()) const;
Q_INVOKABLE bool installationRequested() const; Q_INVOKABLE bool installationRequested() const;
bool isSelectedForInstallation() const; bool isSelectedForInstallation() const;

View File

@ -92,9 +92,9 @@ QString InstallerCalculator::componentsToInstallError() const
return m_componentsToInstallError; return m_componentsToInstallError;
} }
void InstallerCalculator::realAppendToInstallComponents(Component *component) void InstallerCalculator::realAppendToInstallComponents(Component *component, const QString &version)
{ {
if (!component->isInstalled() || component->updateRequested()) { if (!component->isInstalled(version) || component->updateRequested()) {
m_orderedComponentsToInstall.append(component); m_orderedComponentsToInstall.append(component);
m_toInstallComponentIds.insert(component->name()); m_toInstallComponentIds.insert(component->name());
} }
@ -154,10 +154,10 @@ bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &co
return true; return true;
} }
bool InstallerCalculator::appendComponentToInstall(Component *component) bool InstallerCalculator::appendComponentToInstall(Component *component, const QString &version)
{ {
QSet<QString> allDependencies = component->dependencies().toSet(); QSet<QString> allDependencies = component->dependencies().toSet();
QString requiredDependencyVersion = version;
foreach (const QString &dependencyComponentName, allDependencies) { foreach (const QString &dependencyComponentName, allDependencies) {
// PackageManagerCore::componentByName returns 0 if dependencyComponentName contains a // PackageManagerCore::componentByName returns 0 if dependencyComponentName contains a
// version which is not available // version which is not available
@ -171,30 +171,50 @@ bool InstallerCalculator::appendComponentToInstall(Component *component)
m_componentsToInstallError.append(errorMessage); m_componentsToInstallError.append(errorMessage);
return false; return false;
} }
//Check if component requires higher version than what might be already installed
bool isUpdateRequired = false;
if (dependencyComponentName.contains(QChar::fromLatin1('-')) &&
!dependencyComponent->value(scInstalledVersion).isEmpty()) {
QRegExp compEx(QLatin1String("([<=>]+)(.*)"));
const QString installedVersion = compEx.exactMatch(dependencyComponent->value(scInstalledVersion)) ?
compEx.cap(2) : dependencyComponent->value(scInstalledVersion);
if ((!dependencyComponent->isInstalled() || dependencyComponent->updateRequested()) QString requiredVersion = dependencyComponentName.section(QLatin1Char('-'), 1);
&& !m_toInstallComponentIds.contains(dependencyComponent->name())) { requiredVersion = compEx.exactMatch(requiredVersion) ? compEx.cap(2) : requiredVersion;
if (m_visitedComponents.value(component).contains(dependencyComponent)) {
const QString errorMessage = recursionError(component);
qWarning().noquote() << 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 if (KDUpdater::compareVersion(requiredVersion, installedVersion) >= 1 ) {
insertInstallReason(dependencyComponent, InstallerCalculator::Dependent, isUpdateRequired = true;
component->name()); requiredDependencyVersion = requiredVersion;
}
}
//Check dependencies only if
//- Dependency is not installed or update requested, nor newer version of dependency component required
//- And dependency component is not already added for install
//- And component is not already added for install, then dependencies are already resolved
if (((!dependencyComponent->isInstalled() || dependencyComponent->updateRequested())
|| isUpdateRequired) && (!m_toInstallComponentIds.contains(dependencyComponent->name())
&& !m_toInstallComponentIds.contains(component->name()))) {
if (m_visitedComponents.value(component).contains(dependencyComponent)) {
const QString errorMessage = recursionError(component);
qWarning().noquote() << 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);
if (!appendComponentToInstall(dependencyComponent)) // add needed dependency components to the next run
return false; insertInstallReason(dependencyComponent, InstallerCalculator::Dependent,
component->name());
if (!appendComponentToInstall(dependencyComponent, requiredDependencyVersion))
return false;
} }
} }
if (!m_toInstallComponentIds.contains(component->name())) { if (!m_toInstallComponentIds.contains(component->name())) {
realAppendToInstallComponents(component); realAppendToInstallComponents(component, requiredDependencyVersion);
insertInstallReason(component, InstallerCalculator::Resolved); insertInstallReason(component, InstallerCalculator::Resolved);
} }
return true; return true;

View File

@ -64,8 +64,8 @@ private:
void insertInstallReason(Component *component, void insertInstallReason(Component *component,
InstallReasonType installReasonType, InstallReasonType installReasonType,
const QString &referencedComponentName = QString()); const QString &referencedComponentName = QString());
void realAppendToInstallComponents(Component *component); void realAppendToInstallComponents(Component *component, const QString &version = QString());
bool appendComponentToInstall(Component *components); bool appendComponentToInstall(Component *components, const QString &version = QString());
QString recursionError(Component *component); QString recursionError(Component *component);
QList<Component*> m_allComponents; QList<Component*> m_allComponents;

View File

@ -155,14 +155,18 @@ private slots:
componentA->appendComponent(componentAA); componentA->appendComponent(componentAA);
componentA->appendComponent(componentAB); componentA->appendComponent(componentAB);
NamedComponent *componentB = new NamedComponent(core, QLatin1String("B")); NamedComponent *componentB = new NamedComponent(core, QLatin1String("B"));
NamedComponent *componentB_NewVersion = new NamedComponent(core, QLatin1String("B_version"), QLatin1String("2.0.0"));
componentB->addDependency(QLatin1String("A.B")); componentB->addDependency(QLatin1String("A.B"));
componentAB->addDependency(QLatin1String("B_version->=2.0.0"));
core->appendRootComponent(componentA); core->appendRootComponent(componentA);
core->appendRootComponent(componentB); core->appendRootComponent(componentB);
core->appendRootComponent(componentB_NewVersion);
QTest::newRow("Installer resolved") << core QTest::newRow("Installer resolved") << core
<< (QList<Component *>() << componentB) << (QList<Component *>() << componentB)
<< (QList<Component *>() << componentAB << componentB) << (QList<Component *>() << componentB_NewVersion << componentAB << componentB)
<< (QList<int>() << (QList<int>()
<< InstallerCalculator::Dependent
<< InstallerCalculator::Dependent << InstallerCalculator::Dependent
<< InstallerCalculator::Resolved); << InstallerCalculator::Resolved);
} }
@ -186,6 +190,40 @@ private slots:
delete core; delete core;
} }
void unresolvedDependencyVersion_data()
{
QTest::addColumn<PackageManagerCore *>("core");
QTest::addColumn<QList<Component *> >("selectedComponents");
QTest::addColumn<QList<Component *> >("expectedResult");
PackageManagerCore *core = new PackageManagerCore();
core->setPackageManager();
NamedComponent *componentA = new NamedComponent(core, QLatin1String("A"));
NamedComponent *componentB = new NamedComponent(core, QLatin1String("B"), QLatin1String("1.0.0"));
componentA->addDependency(QLatin1String("B->=2.0.0"));
core->appendRootComponent(componentA);
core->appendRootComponent(componentB);
QTest::newRow("Installer resolved") << core
<< (QList<Component *>() << componentA)
<< (QList<Component *>());
}
void unresolvedDependencyVersion()
{
QFETCH(PackageManagerCore *, core);
QFETCH(QList<Component *> , selectedComponents);
QFETCH(QList<Component *> , expectedResult);
InstallerCalculator calc(core->components(PackageManagerCore::ComponentType::AllNoReplacements));
QTest::ignoreMessage(QtWarningMsg, "Cannot find missing dependency \"B->=2.0.0\" for \"A\".");
calc.appendComponentsToInstall(selectedComponents);
QList<Component *> result = calc.orderedComponentsToInstall();
QCOMPARE(result.count(), expectedResult.count());
delete core;
}
void resolveUninstaller_data() void resolveUninstaller_data()
{ {
QTest::addColumn<PackageManagerCore *>("core"); QTest::addColumn<PackageManagerCore *>("core");