Commit 22c43891 authored by Dario Freddi's avatar Dario Freddi

And with error handling, validatethread should be bare working

Signed-off-by: default avatarDario Freddi <drf@kde.org>
parent 29907d9f
...@@ -8,6 +8,7 @@ set(AKABEI_CORE_SRCS ...@@ -8,6 +8,7 @@ set(AKABEI_CORE_SRCS
akabeibackend.cpp akabeibackend.cpp
akabeiconfig.cpp akabeiconfig.cpp
akabeidatabase.cpp akabeidatabase.cpp
akabeierror.cpp
akabeigroup.cpp akabeigroup.cpp
akabeihelpers_p.cpp akabeihelpers_p.cpp
akabeioperation.cpp akabeioperation.cpp
......
/* This file is part of the Chakra project
Copyright (C) 2010 Dario Freddi <drf@chakra-project.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#include "akabeierror.h"
namespace Akabei
{
class Error::Private
{
public:
Private() {}
virtual ~Private() {}
Type type;
QString desc;
Operation *op;
QList<Package*> packages;
};
Error::Error(Error::Type type, const QString& description, Operation* op)
: d(new Private)
{
d->type = type;
d->desc = description;
d->op = op;
}
Error::~Error()
{
delete d;
}
QString Error::description() const
{
return d->desc;
}
Operation* Error::operation()
{
return d->op;
}
void Error::setDescription(const QString& description)
{
d->desc = description;
}
void Error::setOperation(Operation* op)
{
d->op = op;
}
void Error::setTargets(const QList< Package* >& targets)
{
d->packages = targets;
}
QList< Package* > Error::targets() const
{
return d->packages;
}
Error::Type Error::type() const
{
return d->type;
}
}
/* This file is part of the Chakra project
Copyright (C) 2010 Dario Freddi <drf@chakra-project.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#ifndef AKABEI_AKABEIERROR_H
#define AKABEI_AKABEIERROR_H
#include <QtCore/QString>
#include <QtCore/QList>
namespace Akabei {
class Package;
class Operation;
class Error
{
public:
enum Type {
UnknownError = 0,
FilesystemConflictError = 1,
PackageConflictError = 2,
DuplicateTargetError = 3,
UnresolvableDependenciesError = 4,
//
GenericError = 128,
AkabeiInternalError = 129
};
explicit Error(Type type, const QString &description = QString(), Operation *op = 0);
virtual ~Error();
Type type() const;
QString description() const;
void setDescription(const QString &description);
Operation *operation();
void setOperation(Operation *op);
QList<Package*> targets() const;
void setTargets(const QList<Package*> &targets);
private:
class Private;
Private * const d;
};
}
#endif // AKABEI_AKABEIERROR_H
...@@ -22,12 +22,16 @@ ...@@ -22,12 +22,16 @@
#include "akabeihelpers_p.h" #include "akabeihelpers_p.h"
#include "akabeipackage.h" #include "akabeipackage.h"
#include "akabeioperation_p.h" #include "akabeioperation_p.h"
#include "akabeierror.h"
#include <QtCore/QDir>
using namespace Akabei; namespace Akabei {
QString queryFromName(const QString &name) QString queryFromName(const QString &name)
{ {
QString sql = "SELECT * FROM packages WHERE Name = \"%1\" OR Provides LIKE \"%u;%1;%u\"";
sql.arg(name);
return sql;
} }
ValidatorThread::ValidatorThread(QObject* parent) ValidatorThread::ValidatorThread(QObject* parent)
...@@ -128,6 +132,33 @@ void ValidatorThread::processNextPhase() ...@@ -128,6 +132,33 @@ void ValidatorThread::processNextPhase()
if (processOps.isEmpty()) { if (processOps.isEmpty()) {
// We can advance to the next phase, if any // We can advance to the next phase, if any
switch (m_currentPhase) {
case Operation::Phase1:
m_currentPhase = Operation::Phase2;
break;
case Operation::Phase2:
m_currentPhase = Operation::Phase3;
break;
case Operation::Phase3:
m_currentPhase = Operation::Phase4;
break;
case Operation::Phase4:
m_currentPhase = Operation::Phase5;
break;
case Operation::Phase5:
// If we're here, we're successfully over.
emit validationFinished(true);
return;
break;
default:
// Urgh.. what?
Error *error = new Error(Akabei::Error::AkabeiInternalError,
tr("An internal error occurred during validation"));
manageErrors(QList<Error*>() << error);
return;
break;
}
processNextPhase();
return; return;
} }
...@@ -140,29 +171,26 @@ void ValidatorThread::processNextPhase() ...@@ -140,29 +171,26 @@ void ValidatorThread::processNextPhase()
watcher.setFuture(future); watcher.setFuture(future);
e.exec(); e.exec();
QList<Error*> errors;
// Now populate target names and dependencies // Now populate target names and dependencies
QHash< QString, Operation* > processTargetNames; QHash< QString, Operation* > processTargetNames;
QHash< QString, Operation* > targetNames; QHash< QString, Operation* > targetNames;
QStringList dependTargets; QStringList dependTargets;
foreach (Operation *op, processOps) { foreach (Operation *op, processOps) {
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(); dependTargets << op->targetDependencies();
} }
foreach (Operation *op, allOps) { foreach (Operation *op, allOps) {
foreach (const QString &target, op->targetAdditions()) { foreach (const QString &target, op->targetAdditions()) {
if (!targetNames.contains(target)) { if (!targetNames.contains(target)) {
targetNames[target] = op; targetNames[target] = op;
processTargetNames[target] = op;
} else { } else {
// Problem. There are two operations trying to add the same target. // Problem. There are two operations trying to add the same target.
// TODO Take action. Error *error = new Error(Akabei::Error::DuplicateTargetError,
tr("The target %1 is being added by %2 and %3")
.arg(target).arg(targetNames[target]->targetName()).arg(op->targetName()));
errors << error;
} }
} }
} }
...@@ -255,10 +283,11 @@ void ValidatorThread::processNextPhase() ...@@ -255,10 +283,11 @@ void ValidatorThread::processNextPhase()
unresolvableDeps << i.key(); unresolvableDeps << i.key();
} }
if (!unresolvableDeps.isEmpty()) { foreach (const QString &uD, unresolvableDeps) {
// failure. // failure.
// TODO: take action Error *error = new Error(Akabei::Error::UnresolvableDependenciesError,
return; tr("A dependency is not resolvable: %1").arg(uD));
errors << error;
} }
if (!missingDeps.isEmpty()) { if (!missingDeps.isEmpty()) {
...@@ -271,25 +300,35 @@ void ValidatorThread::processNextPhase() ...@@ -271,25 +300,35 @@ void ValidatorThread::processNextPhase()
// Ok, now check validity of stuff. // Ok, now check validity of stuff.
QStringList filesystemAdditions; QStringList filesystemAdditions;
QStringList targetRemovals; QStringList targetRemovals;
QDir rootDir(Config::instance()->root());
foreach (Operation *op, allOps) { foreach (Operation *op, allOps) {
filesystemAdditions << op->fileSystemAdditions(); filesystemAdditions << op->fileSystemAdditions();
targetRemovals << op->targetRemovals(); targetRemovals << op->targetRemovals();
// Check filesystem conflicts // Check filesystem conflicts
foreach (const QString &target, op->fileSystemAdditions()) { foreach (const QString &target, op->fileSystemAdditions()) {
if (QFile::exists(Config::instance()->root() + target)) { if (QFile::exists(rootDir.absoluteFilePath(target))) {
// Problem, FS conflict. // Problem, FS conflict.
// TODO handle Error *error = new Error(Akabei::Error::FilesystemConflictError,
tr("%1 already exists in the filesystem").arg(rootDir.absoluteFilePath(target)));
errors << error;
} }
} }
foreach (const QString &target, op->conflictingTargets()) { foreach (const QString &target, op->conflictingTargets()) {
if (targetNames.contains(target)) { if (targetNames.contains(target)) {
// Problem, attempting to install a package conflicting with something in the transaction. // Problem, attempting to install a package conflicting with something in the transaction.
// TODO handle Error *error = new Error(Akabei::Error::PackageConflictError,
tr("%1 is about to be installed, but conflicts with %2, which is being "
"installed as well.").arg(target).arg(op->targetName()));
errors << error;
} }
// Now check the local database // Now check the local database
if (Backend::instance()->localDatabase()->queryPackages(queryFromName(target)).size() > 0) { if (Backend::instance()->localDatabase()->queryPackages(queryFromName(target)).size() > 0) {
// Problem, trying to install a package conflicting with an installed package // Problem, trying to install a package conflicting with an installed package
// TODO handle Error *error = new Error(Akabei::Error::PackageConflictError,
tr("%1 is about to be installed, but conflicts with %2, which is installed")
.arg(op->targetName())
.arg(Backend::instance()->localDatabase()->queryPackages(queryFromName(target)).first()->name()));
errors << error;
} }
} }
} }
...@@ -298,7 +337,10 @@ void ValidatorThread::processNextPhase() ...@@ -298,7 +337,10 @@ void ValidatorThread::processNextPhase()
int dupCount = filesystemAdditions.removeDuplicates(); int dupCount = filesystemAdditions.removeDuplicates();
if (dupCount > 0) { if (dupCount > 0) {
// Internal conflicts // Internal conflicts
//TODO handle // TODO: Be more verbose
Error *error = new Error(Akabei::Error::FilesystemConflictError,
tr("A file is contained in more than one package"));
errors << error;
} }
// Check if we are breaking dependencies somehow // Check if we are breaking dependencies somehow
...@@ -307,15 +349,33 @@ void ValidatorThread::processNextPhase() ...@@ -307,15 +349,33 @@ void ValidatorThread::processNextPhase()
QList<Package*> ret = Backend::instance()->localDatabase()->queryPackages(sql); QList<Package*> ret = Backend::instance()->localDatabase()->queryPackages(sql);
// Iterate: we might have found targets that are not the ones we're looking for (due to version handling) // Iterate: we might have found targets that are not the ones we're looking for (due to version handling)
foreach (Package *p, ret) { foreach (Package *p, ret) {
// Check also that the package itself is not being removed! // Check also that the package itself is not being removed and a target is not being added
if (p->name() == target && !targetRemovals.contains(target)) { if (p->name() == target && !targetRemovals.contains(target)) {
// Problem, attempting to remove a package which some installed packages depend on. // Problem, attempting to remove a package which some installed packages depend on.
// TODO, handle. Error *error = new Error(Akabei::Error::UnresolvableDependenciesError,
tr("%1 depends on %2, which is being removed")
.arg(p->name()).arg(target));
errors << error;
} }
} }
} }
// Good. The phase appears to be fully valid. // Good. Any errors?
if (!errors.isEmpty()) {
// Ah. report them back and interrupt here
manageErrors(errors);
return;
}
// Ok, The phase appears to be fully valid.
// Recurse over ourselves // Recurse over ourselves
processNextPhase(); processNextPhase();
} }
void ValidatorThread::manageErrors(const QList< Error* >& errors)
{
emit errorsOccurred(errors);
emit validationFinished(false);
}
}
\ No newline at end of file
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <QtCore/QHash> #include <QtCore/QHash>
namespace Akabei { namespace Akabei {
class Error;
class OperationPrivate; class OperationPrivate;
/* /*
...@@ -43,18 +44,23 @@ class ValidatorThread : public QThread ...@@ -43,18 +44,23 @@ class ValidatorThread : public QThread
protected: protected:
virtual void run(); virtual void run();
Q_SIGNALS:
void errorsOccurred(const QList<Error*> &errors);
void validationFinished(bool success);
private Q_SLOTS:
void streamValidationProgress(int);
private: private:
void processNextPhase(); void processNextPhase();
QList< Operation* > joinOperations(Operation *op, bool shouldBeReady); QList< Operation* > joinOperations(Operation *op, bool shouldBeReady);
void manageErrors(const QList<Error*> &errors);
private: private:
QHash<Operation::Phase, QList< Operation* > > m_operations; QHash<Operation::Phase, QList< Operation* > > m_operations;
Operation::Phase m_currentPhase; Operation::Phase m_currentPhase;
friend class OperationRunner; friend class OperationRunner;
public slots:
void streamValidationProgress(int);
}; };
} }
......
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