Commit 8de5ff0c authored by Dario Freddi's avatar Dario Freddi

More work on the validation: now the versions should be handled correctly

Signed-off-by: default avatarDario Freddi <drf@kde.org>
parent b8987622
......@@ -86,7 +86,6 @@ void OperationRunner::start()
// Now start validating all the phases
d->phase = Operation::Phase1;
d->validateNextPhase();
}
void OperationRunner::cancel()
......
......@@ -26,9 +26,6 @@ public:
QHash<Operation::Phase, QList< Operation* > > operations;
void validateNextPhase();
void processNextPhase();
Operation::Phase phase;
};
......
......@@ -35,6 +35,29 @@ QString Package::Version::toString() const
return d->repr;
}
bool Package::Version::respectsConstraint(const QString& cV) const
{
// Check what kind of constraint is this
if (cV.startsWith('<')) {
// Is it <=?
if (cV.startsWith("<=")) {
return *this <= cV.split("<=").last();
} else {
return *this < cV.split('<').last();
}
} else if (cV.startsWith('>')) {
// Is it <=?
if (cV.startsWith(">=")) {
return *this >= cV.split(">=").last();
} else {
return *this > cV.split('>').last();
}
} else {
// The version must be the same
return *this == cV;
}
}
Package::Version& Package::Version::operator=(const Akabei::Package::Version& other)
{
d->repr = other.d->repr;
......@@ -70,6 +93,41 @@ bool Package::Version::operator>=(const Akabei::Package::Version& other) const
return compare_versions(d->repr.toUtf8().data(), other.toString().toUtf8().data()) >= 0;
}
Package::Version& Package::Version::operator=(const QString& other)
{
d->repr = other;
}
bool Package::Version::operator!=(const QString& other) const
{
return compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) != 0;
}
bool Package::Version::operator<(const QString& other) const
{
return compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) < 0;
}
bool Package::Version::operator<=(const QString& other) const
{
return compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) <= 0;
}
bool Package::Version::operator==(const QString& other) const
{
return compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) == 0;
}
bool Package::Version::operator>(const QString& other) const
{
return compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) > 0;
}
bool Package::Version::operator>=(const QString& other) const
{
return compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) >= 0;
}
////////////////////////////
Package::Package(Database *db, int databaseId, const QString &name)
......
......@@ -39,6 +39,7 @@ public:
~Version();
QString toString() const;
bool respectsConstraint(const QString &constraintedVersion) const;
Version &operator=(const Version &other);
bool operator==(const Version &other) const;
......@@ -48,6 +49,14 @@ public:
bool operator>(const Version &other) const;
bool operator>=(const Version &other) const;
Version &operator=(const QString &other);
bool operator==(const QString &other) const;
bool operator!=(const QString &other) const;
bool operator<(const QString &other) const;
bool operator<=(const QString &other) const;
bool operator>(const QString &other) const;
bool operator>=(const QString &other) const;
private:
class Private;
Private * const d;
......
......@@ -60,6 +60,20 @@ QHash< QString, QString > ValidatorThread::versionedTargets(const QStringList &t
return rethash;
}
QPair< QString, QString > ValidatorThread::versionedTarget(const QString& target) const
{
if (target.contains('<')) {
return qMakePair<QString, QString>(target.split('<').first(), '<' + target.split('<').last());
} else if (target.contains('>')) {
return qMakePair<QString, QString>(target.split('>').first(), '>' + target.split('>').last());
} else if (target.contains('=')) {
return qMakePair<QString, QString>(target.split('=').first(), target.split('=').last());
} else {
// No version costraint.
return qMakePair<QString, QString>(target, QString());
}
}
OperationPrivate* ValidatorThread::operationPrivateProxy(Operation* op)
{
return op->d_func();
......@@ -122,50 +136,118 @@ void ValidatorThread::processNextPhase()
e.exec();
// Now populate target names and dependencies
QStringList processTargetNames;
QStringList targetNames;
QHash< QString, Operation* > processTargetNames;
QHash< QString, Operation* > targetNames;
QStringList dependTargets;
foreach (Operation *op, processOps) {
processTargetNames << op->targetName();
foreach (const QString &target, op->targetAdditions()) {
if (!processTargetNames.contains(target)) {
processTargetNames[target] = op;
} else {
// Problem. There are two operations trying to add the same target.
// TODO Take action.
}
}
dependTargets << op->targetDependencies();
}
foreach (Operation *op, allOps) {
targetNames << op->targetName();
foreach (const QString &target, op->targetAdditions()) {
if (!targetNames.contains(target)) {
targetNames[target] = op;
} else {
// Problem. There are two operations trying to add the same target.
// TODO Take action.
}
}
}
// Check dependencies
dependTargets.removeDuplicates();
QHash< QString, QString > vrsDependTargets = versionedTargets(dependTargets);
QList< Package* > missingDeps;
QStringList unresolvableDeps;
foreach (const QString &dep, dependTargets) {
for (QHash< QString, QString >::const_iterator i = vrsDependTargets.constBegin(); i != vrsDependTargets.constEnd(); ++i) {
// Is it in the current operation?
if (targetNames.contains(dep)) {
// Cool, pass by
continue;
if (targetNames.contains(i.key())) {
// Is the version correct?
if (i.value().isEmpty()) {
// No version checks, so it's ok. Pass by.
continue;
} else {
// Check if the version matches
if (Package::Version(targetNames[i.key()]->targetVersion()).respectsConstraint(i.value())) {
// It does, dependency satisfied. Pass by.
continue;
}
}
}
// Is it in the local database?
if (Backend::instance()->localDatabase()->queryPackages(queryFromName(dep)).size() > 0) {
// TODO: eventually check for version
// Cool, pass by
continue;
// Not in the current operation. Is it in the local database?
QList<Package*> locals = Backend::instance()->localDatabase()->queryPackages(queryFromName(i.key()));
if (locals.size() > 0) {
// Ok. Now let's check if it has a version constraint.
if (i.value().isEmpty()) {
// No version checks around, just pass by.
continue;
} else {
// Huzzah, check the version.
bool found = false;
foreach (Package *p, locals) {
if (p->version().respectsConstraint(i.value())) {
found = true;
break;
}
}
if (found) {
// Cool, pass by
continue;
}
}
}
// The dependency is hereby missing. Is it resolvable? Let's see.
Helpers::PackageEventLoop loop;
connect(Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)),
&loop, SLOT(requestQuit(QUuid,QList<Akabei::Package*>)));
loop.setUuid(Backend::instance()->queryPackages(queryFromName(dep)));
loop.setUuid(Backend::instance()->queryPackages(queryFromName(i.key())));
loop.exec();
if (loop.result().size() > 0) {
// TODO: Check for version here.
// Ok, we just need to install it. Let's add the first target
// TODO: Better heuristics in case of multiple targets retrieved
missingDeps << loop.result().first();
} else {
// The dependency is not satisfiable
unresolvableDeps << dep;
Package *package = 0;
// Ok, we just need to install it. Let's loop the result and add the best target
foreach (Package *p, loop.result()) {
// Version constraint?
if (!i.value().isEmpty()) {
// Check it
if (!p->version().respectsConstraint(i.key())) {
// Not a good candidate, skip it
continue;
}
}
// Is it matching our target strictly by name?
if (p->name() == i.key()) {
// It's 100% our first choice
package = p;
} else {
// Add it only if there are no other targets
if (!package) {
package = p;
}
}
}
if (package) {
// A valid target was found. Add it to the missing dependencies and pass by
missingDeps << package;
continue;
}
// If we got here, all the possible checks have been done. The dependency is simply not satisfiable.
unresolvableDeps << i.key();
}
if (!unresolvableDeps.isEmpty()) {
......@@ -220,12 +302,14 @@ void ValidatorThread::processNextPhase()
// Iterate: we might have found targets that are not the ones we're looking for (due to version handling)
foreach (Package *p, ret) {
// Check also that the package itself is not being removed!
if (p->name() == target) {
if (p->name() == target && !targetRemovals.contains(target)) {
// Problem, attempting to remove a package which some installed packages depend on.
// TODO, handle.
}
}
}
// Good. The phase appears to be fully valid.
// Recurse over ourselves
processNextPhase();
}
......@@ -36,6 +36,7 @@ class ValidatorThread : public QThread
void requestCancel();
QHash< QString, QString > versionedTargets(const QStringList &targets) const;
QPair< QString, QString > versionedTarget(const QString &targets) const;
static OperationPrivate *operationPrivateProxy(Operation *op);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment