Commit 58aff3b6 authored by AlmAck's avatar AlmAck
Browse files

introduced new class PolkitReplaceOperation

parent 74dade3e
......@@ -41,8 +41,9 @@ operations/akabeiplainscriptletoperation.cpp
operations/akabeiplainupgradeoperation.cpp
operations/akabeipolkitupgradeoperation.cpp
operations/akabeipolkitinstalloperation.cpp
operations/akabeioperationutils.cpp
operations/akabeiplainreplaceoperation.cpp
operations/akabeipolkitreplaceoperation.cpp
operations/akabeioperationutils.cpp
)
set(AKABEI_CORE_HDRS
......@@ -85,6 +86,8 @@ operations/akabeipolkitremoveoperation.h
operations/akabeiplainscriptletoperation.h
operations/akabeiplainupgradeoperation.h
operations/akabeipolkitupgradeoperation.h
operations/akabeiplainreplaceoperation.h
operations/akabeipolkitreplaceoperation.h
operations/akabeiplainhookoperation.h
operations/akabeioperationutils.h
)
......
/*
This file is part of the Chakra project
Copyright (C) 2010 Dario Freddi <drf@chakra-project.org>
Copyright (C) 2013 Lukas Appelhans <boom1992@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 "akabeipolkitreplaceoperation.h"
#include "akabeiplainscriptletoperation.h"
#include "akabeioperationutils.h"
#include "akabeiplainhookoperation.h"
#include <akabeipackage.h>
#include <akabeihelpers.h>
#include <akabeiconfig.h>
#include <akabeibackend.h>
#include <akabeilog.h>
#include <akabeierror.h>
#include <akabeidatabase.h>
#include <akabeiquery.h>
#include <QDateTime>
#include <QStringList>
#include <QDBusInterface>
#include <QDBusPendingCall>
namespace Akabei {
class PolkitReplaceOperation::Private
{
public:
Private(Package *p, const QList<Package*> &r, PolkitReplaceOperation * op) : package(p), replaces(r), q(op), iface(0) {}
~Private() {
delete iface;
}
void __k__polkitFinished(const QString &archive, bool success);
void __k__progressUpdated(const QString &archive, int progress);
void __k__newMessage(const QString &archive, const QString &message);
void __k__error(const QString &archive, int type, const QString &error);
void __k__removeFileProgress(int progress);
void __k__removeFileFinished();
void __k__removeFileErrors(const QStringList &errors);
Package *package;
QList<Package*> replaces;
PolkitReplaceOperation * q;
QDBusInterface * iface;
};
PolkitReplaceOperation::PolkitReplaceOperation(Package *package, const QList<Package*> &replaces)
: Operation(package->name())
, d(new Private(package, replaces, this))
{
setPhase(Phase3); // Replacement happens in phase 3.
setPriority(50); // Replacement has a low priority.
setCanBeConcurrent(false); // And it can not be concurrent.
setTargetVersion(package->version().toByteArray());
setDescription(QObject::tr("Replacing packages with %1...").arg(package->name())); //TODO: Give better description
//Basically we replace our own package as well :)
QList<Package*> installed = Backend::instance()->localDatabase()->queryPackages(Queries::selectPackages("name", "=", d->package->name()));
if (!installed.isEmpty())
d->replaces.append(installed.first());
}
PolkitReplaceOperation::~PolkitReplaceOperation()
{
delete d;
}
void PolkitReplaceOperation::run()
{
qDebug() << "Run replace";
OperationUtils util;
if (!(processingOptions().testFlag(Akabei::DatabaseOnly))) {
if (!util.validatePackage(d->package)) {
setErrors(Error::List() << Error(Error::UnknownError, util.errorMessage(), this));
setFinished(false);
return;
}
QStringList files;
const int numberPackages = d->replaces.count();
// get the list of all files
for (int i = 0; i != numberPackages; ++i) {
Package * replacedpkg = d->replaces[i];
files.append(replacedpkg->retrieveFiles());
}
// remove them
for (int i = 0; i != numberPackages; ++i) {
Package * replacedpkg = d->replaces[i];
QMap<QString, QString> backup = replacedpkg->backupFiles();
foreach (const QString &b, backup.keys()) {
if (b.isEmpty() || backup[b].isEmpty())
continue;
files.removeAll(b);
}
}
if (!Akabei::Helpers::checkAuthorizationSync("org.chakraproject.akabeicorehelper.filesystem.remove")) {
setErrors(Error::List() << Error(Error::PermissionError, tr("There has been an error with your polkit configuration!"), this));
setFinished(false);
return;
}
d->iface = new QDBusInterface("org.chakraproject.akabeicorehelper", "/filesystem", "org.chakraproject.akabeicorehelper.filesystem", QDBusConnection::systemBus());
connect(d->iface, SIGNAL(removeFilesFinished()), this, SLOT(__k__removeFileFinished()));
connect(d->iface, SIGNAL(removeFilesErrors(QStringList)), this, SLOT(__k__removeFileErrors(QStringList)));
connect(d->iface, SIGNAL(removeFilesProgress(int)), this, SLOT(__k__removeFileProgress(int)));
QDBusPendingCall c = d->iface->asyncCall("removeFiles", files, (int) processingOptions());
//NOTE: Do we need error handling here?!
} else {
d->__k__removeFileFinished();
}
}
void PolkitReplaceOperation::Private::__k__removeFileProgress(int progress)
{
q->setProgress(progress / 2);
}
void PolkitReplaceOperation::Private::__k__removeFileErrors(const QStringList &errors)
{
Error::List list;
foreach (const QString &error, errors) {
list << Error(Error::UnknownError, error, q);
}
q->setErrors(list);
}
void PolkitReplaceOperation::Private::__k__removeFileFinished()
{
q->disconnect(iface, SIGNAL(removeFilesFinished()), q, SLOT(__k__removeFileFinished()));
q->disconnect(iface, SIGNAL(removeFilesErrors(QStringList)), q, SLOT(__k__removeFileErrors(QStringList)));
q->disconnect(iface, SIGNAL(removeFilesProgress(int)), q, SLOT(__k__removeFileProgress(int)));
delete iface;
QVariantMap b;
const int numberPackages = replaces.count();
for (int i = 0; i != numberPackages; ++i) {
Package * replacedpkg = replaces[i];
QMap<QString, QString> backup = replacedpkg->backupFiles();
foreach (const QString &k, backup)
b.insert(k, backup[k]);
}
qDebug() << "Now let's do the dbus stuff";
if (!Akabei::Helpers::checkAuthorizationSync("org.chakraproject.akabeicorehelper.install")) {
q->setErrors(Error::List() << Error(Error::PermissionError, QObject::tr("There has been an error with your polkit configuration!"), q));
q->setFinished(false);
return;
}
iface = new QDBusInterface("org.chakraproject.akabeicorehelper", "/install", "org.chakraproject.akabeicorehelper.installhelper", QDBusConnection::systemBus());
q->connect(iface, SIGNAL(finished(QString, bool)), SLOT(__k__polkitFinished(QString, bool)));
q->connect(iface, SIGNAL(newMessage(QString, QString)), SLOT(__k__newMessage(QString, QString)));
q->connect(iface, SIGNAL(updateProgress(QString, int)), SLOT(__k__progressUpdated(QString, int)));
q->connect(iface, SIGNAL(error(QString,int,QString)), SLOT(__k__error(QString,int,QString)));
Package::InstallReason reason = package->installReason();
if (q->processingOptions().testFlag(InstallAsDependencies)) {
reason = Package::InstalledAsDependencyReason;
} else if (q->processingOptions().testFlag(InstallAsExplicit)) {
reason = Package::ExplicitlyInstalledReason;
}
iface->asyncCall("upgrade", package->pathToArchive(), Akabei::Config::instance()->root(), (int) q->processingOptions(), reason, Akabei::Backend::instance()->localDatabase()->name());
}
void PolkitReplaceOperation::Private::__k__polkitFinished(const QString &archive, bool success)
{
qDebug() << "Finished" << archive;
if (archive != package->pathToArchive())
return;
q->disconnect(iface, SIGNAL(finished(QString)), q, SLOT(__k__polkitFinished(QString)));
q->disconnect(iface, SIGNAL(newMessage(QString, QString)), q, SLOT(__k__newMessage(QString, QString)));
q->disconnect(iface, SIGNAL(updateProgress(QString, int)), q, SLOT(__k__progressUpdated(QString, int)));
q->disconnect(iface, SIGNAL(error(QString,int,QString)), q, SLOT(__k__error(QString,int,QString)));
if (!(q->processingOptions().testFlag(Akabei::DatabaseOnly))) {
// Add the archive to the cache.
// Simply copy it over to our cachedir.
Cache cache;
cache.writePackage(package->pathToArchive(), package->filename());
}
// Done!
qDebug() << "Before log" << QTime::currentTime();
log() << "replaced " << package->name() << " (" << package->version().toByteArray() << ")" << Akabei::endlog;
qDebug() << "After log" << QTime::currentTime();
q->setProgress(100);
q->setFinished(success);
}
void PolkitReplaceOperation::Private::__k__progressUpdated(const QString &archive, int progress)
{
if (archive == package->pathToArchive())
q->setProgress(50 + progress / 2);
}
void PolkitReplaceOperation::Private::__k__newMessage(const QString &archive, const QString &message)
{
if (archive == package->pathToArchive())
q->addMessage(message);
}
void PolkitReplaceOperation::Private::__k__error(const QString &archive, int type, const QString &message)
{
if (archive != package->pathToArchive())
return;
q->setErrors(Error::List() << q->errors() << Error((Error::Type)type, message, q));
}
void PolkitReplaceOperation::validate()
{
// Add conflicts.
setConflictingTargets(d->package->conflictsWith());
if (!(processingOptions().testFlag(Akabei::SkipDependencies))) {
// Add additional targets.
QStringList targets = QStringList() << d->package->name() << Helpers::unversionedTargets(d->package->provides());
targets.removeDuplicates();
setTargetAdditions(targets);
QStringList targetsRemoved;
foreach (Package * r, d->replaces)
targetsRemoved << r->name();
setTargetRemovals(targetsRemoved);
}
if (!(processingOptions().testFlag(Akabei::DatabaseOnly))) {
// Now let’s set the conflicting targets & stuff.
// Since this is an installation, we’re adding stuff to the filesystem.
{
QSet<QString> oldFiles;
foreach (Package * r, d->replaces)
oldFiles.unite(r->retrieveFiles(Package::FilepathNoPrefix).toSet());
QSet<QString> newFiles = d->package->retrieveFiles(Package::FilepathNoPrefix).toSet();
QSet<QString> add = newFiles;
add.subtract(oldFiles);
QSet<QString> remove = oldFiles;
remove.subtract(newFiles);
if (!(processingOptions().testFlag(Akabei::Force))) {
setFileSystemAdditions(add.toList());
}
setFileSystemRemovals(remove.toList());
}
bool upgrade = false;
foreach (Package * package, d->replaces) {
if (package->name() == d->package->name()) {
upgrade = true;
continue;
}
// If it has a scriptlet, we need a new suboperation
if (package->hasScriptlet()) {
// Does it have a pre install function?
if (package->retrieveScriptlet().contains("pre_remove")) {
// Ok, it has
QStringList args;
args << "pre_remove";// << d->package->version().toByteArray();
setPreOperations(Operation::List() << new PlainScriptletOperation(d->package, args));//FIXME: Make this the polkitscriptletoperation
}
// Does it have a post install function?
if (package->retrieveScriptlet().contains("post_remove")) {
// Ok, it has
QStringList args;
args << "post_remove";// << d->package->version().toByteArray();
setPostOperations(Operation::List() << new PlainScriptletOperation(d->package, args));
}
}
}
const QString operation = upgrade ? "upgrade" : "install";
//Install/Upgrade scriptlets, Remove scriplets, hooks
// If it has a scriptlet, we need a new suboperation.
if (d->package->hasScriptlet()) {
// Does it have a pre-install function?
if (d->package->retrieveScriptlet().contains("pre_" + operation)) {
// Ok, it does.
QStringList args;
args << "pre_" + operation;
setPreOperations(Operation::List() << new PlainScriptletOperation(d->package, args));
}
// Does it have a post-install function?
if (d->package->retrieveScriptlet().contains("post_" + operation)) {
// Ok, it does.
QStringList args;
args << "post_" + operation;
setPostOperations(Operation::List() << new PlainScriptletOperation(d->package, args));
}
}
// Same for hooks.
if (d->package->hasHooks()) {
akabeiDebug() << "We have hooks" << d->package->hooks();
PlainHookOperation::instance()->add(d->package->retrieveHooks(), "post_install");
}
QSet<Hook*> removeHooks;
foreach (Package * package, d->replaces) {
removeHooks.unite(package->retrieveHooks().toSet());
}
if (!removeHooks.isEmpty()) {
PlainHookOperation::instance()->add(removeHooks.toList(), "post_remove");
}
}
if (!(processingOptions().testFlag(Akabei::SkipDependencies))) {
// Compute dependencies and stuff.
setTargetDependencies(d->package->dependencies());
}
// Ok, validated!
setValidationFinished(true);
}
}
#include "akabeipolkitreplaceoperation.moc"
/* This file is part of the Chakra project
Copyright (C) 2010 Dario Freddi <drf@chakra-project.org>
Copyright (C) 2013 Lukas Appelhans <boom1992@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 AKABEIPOLKITREPLACEOPERATION_H
#define AKABEIPOLKITREPLACEOPERATION_H
#include <akabeicore_global.h>
#include <akabeioperation.h>
#include <akabeipackage.h>
namespace Akabei {
class Package;
/**
* @class PolkitReplaceOperation
* @brief Operation to replace a package from the system using polkit.
*/
class AKABEICORESHARED_EXPORT PolkitReplaceOperation : public Operation
{
Q_OBJECT
Q_DISABLE_COPY(PolkitReplaceOperation)
public:
explicit PolkitReplaceOperation(Package *package, const QList<Package*> &replaces);
virtual ~PolkitReplaceOperation();
protected:
void run();
void validate();
private:
class Private;
Private * const d;
Q_PRIVATE_SLOT(d, void __k__polkitFinished(QString, bool))
Q_PRIVATE_SLOT(d, void __k__progressUpdated(QString, int))
Q_PRIVATE_SLOT(d, void __k__newMessage(QString, QString))
Q_PRIVATE_SLOT(d, void __k__error(QString, int, QString))
Q_PRIVATE_SLOT(d, void __k__removeFileProgress(int))
Q_PRIVATE_SLOT(d, void __k__removeFileFinished())
Q_PRIVATE_SLOT(d, void __k__removeFileErrors(QStringList))
};
}
#endif // AKABEIPOLKITREPLACEOPERATION_H
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