Commit d64928f9 authored by Lisa's avatar Lisa

Some refactoring around

parent b919153d
......@@ -74,7 +74,7 @@ void APM::start()
}
default:
break;
}
}
}
#include "apm.moc"
......@@ -44,6 +44,7 @@ public:
ShowUpgradeable,
ShowLess,
///Sync operations
Install,
AsDeps,//Also in upgrade
AsExplicit,//Also in upgrade
RemoveOldPackages,
......@@ -59,6 +60,7 @@ public:
UpdateDatabases,
UpdateSystem,
///Remove operations
Remove,
Cascade,
DatabaseOnly,//Also in upgrade
RemoveConfig,
......
......@@ -164,6 +164,8 @@ int main(int argc, char** argv)
list.append(APM::ShowLess);
} else if (args->isSet("R")) {
type = APM::RemoveOperationType;
list.append(APM::Remove);
if (args->isSet("c"))
list.append(APM::Cascade);
if (args->isSet("d"))
......@@ -178,6 +180,8 @@ int main(int argc, char** argv)
list.append(APM::Unneeded);
} else if (args->isSet("S")) {
type = APM::SyncOperationType;
list.append(APM::Install);
if (args->isSet("y"))
list.append(APM::UpdateDatabases);
if (args->isSet("u"))
......@@ -229,8 +233,9 @@ int main(int argc, char** argv)
if (args->isSet("w"))
list.append(APM::DownloadOnly);
} else {
fprintf(stderr, "Please select an operation to do!\nCall akabei --help for explanation.\n");
return app.exec();
QTextStream err(stderr);
err << "Please select an operation to do!\nCall akabei --help for explanation.\n";
return -1;
}
QString root = args->getOption("root");
opts.insert(APM::RootDir, root);
......@@ -241,6 +246,15 @@ int main(int argc, char** argv)
QString cache = args->getOption("cachedir");
opts.insert(APM::CacheDir, cache);
/*
* APM::Remove or APM::Install must remain only when they're alone
* otherwise another operation has been requested
*/
if (list.size() > 1) {
list.removeOne(APM::Remove);
list.removeOne(APM::Install);
}
QStringList rest;
for (int i = 0; i < args->count(); i++) {
......@@ -250,6 +264,5 @@ int main(int argc, char** argv)
args->clear(); // Free up some memory
APM apm(type, list, opts, rest);
return app.exec();
}
/* This file is part of the KDE project
/* This file is part of the Chakra project
Copyright (C) 2010 Lukas Appelhans
......@@ -9,138 +9,189 @@
*/
#include "syncoperation.h"
#include "queueoperation.h"
#include <akabeibackend.h>
#include <akabeipackage.h>
#include <akabeidatabase.h>
#include <akabeiclientbackend.h>
#include <akabeiconfig.h>
#include <klocale.h>
#include <akabeigroup.h>
#include <akabeiclientqueue.h>
#include <akabeiclienttransactionhandler.h>
#include <akabeioperation.h>
#include <akabeioperationrunner.h>
#include <QTextStream>
#include <QDateTime>
#include <kio/global.h>
#include <akabeigroup.h>
#include <kdebug.h>
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <akabeiclientqueue.h>
#include <akabeiclienttransactionhandler.h>
#include <iostream>
#include <klocale.h>
#include <kio/global.h>
#include <kdebug.h>
#include <kio/global.h>
#include <akabeioperation.h>
#include <akabeioperationrunner.h>
#include "queueoperation.h"
SyncOperation::SyncOperation(QObject* parent)
: QObject(parent),
m_maxDbNameLenght(0)
{
}
#include <iostream>
SyncOperation::~SyncOperation()
{
SyncOperation::SyncOperation(QObject* parent)
: QObject(parent)
, m_maxDbNameLenght(0)
{}
}
SyncOperation::~SyncOperation() {}
void SyncOperation::start(QList<APM::Operation> operations, QMultiHash<APM::Operation, QString> options, QStringList args)
{
APM::Operation operation = operations.takeFirst();
QTextStream err(stderr);
Akabei::Backend *backend = Akabei::Backend::instance();
m_operations = operations;
m_options = options;
m_args = args;
APM::Operation operation = APM::NoOperation;
if (!operations.isEmpty()) {
operation = operations.first();
}
if (operation == APM::Search) {
if (args.isEmpty())
return;
connect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)),
SLOT(searchResult(QUuid,QList<Akabei::Package*>)));
Akabei::Backend::instance()->searchPackages(args.first());
} else if (operation == APM::ListRepo) {
if (args.isEmpty())
return;
listRepo(args.first());
} else if (operation == APM::ShowInformation) {
if (args.isEmpty())
return;
connect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)),
SLOT(showInformation(QUuid,QList<Akabei::Package*>)));
Akabei::Backend::instance()->searchPackages(args.first());
} else if (operation == APM::ShowPackagesOfGroup) {
if (args.isEmpty())
return;
connect(Akabei::Backend::instance(), SIGNAL(queryGroupsCompleted(QUuid,QList<Akabei::Group*>)),
SLOT(showGroup(QUuid,QList<Akabei::Group*>)));
Akabei::Backend::instance()->queryGroups("SELECT * FROM groups WHERE name LIKE \"" + args.first() + "\"");
} else if (operation == APM::UpdateDatabases) {
if (AkabeiClient::Backend::instance()->databases().isEmpty())
return;
QTextStream out(stdout);
out << i18n("Starting database update") << endl;
foreach (AkabeiClient::DatabaseHandler* db, AkabeiClient::Backend::instance()->databases()) {
if (db->name().length() > m_maxDbNameLenght)
m_maxDbNameLenght = db->name().length();
switch(operation) {
case APM::Search:
{
if (args.isEmpty()) {
err << "akabei: An argument is needed." << endl;
return;
}
connect(backend, SIGNAL(queryPackagesCompleted(QUuid, QList<Akabei::Package*>)), SLOT(searchResult(QUuid,QList<Akabei::Package*>)));
backend->searchPackages(args);
break;
}
m_currentDatabasePos = 0;
updateNextDatabase();
} else if (operation == APM::UpdateSystem) {
QString query = "SELECT * FROM packages WHERE";
QList<Akabei::Package*> locals = Akabei::Backend::instance()->localDatabase()->packages();
QList<Akabei::Package*>::iterator it = locals.begin();
for ( ; it != locals.end(); it++) {
if (it != locals.begin())
query = query + " OR";
query = query + " name LIKE \"" + (*it)->name() + "\"";
case APM::ListRepo:
{
if (args.isEmpty()) {
err << "akabei: An argument is needed." << endl;
return;
}
listRepo(args.first());
break;
}
connect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(upgrade(QUuid,QList<Akabei::Package*>)));
queryId = Akabei::Backend::instance()->queryPackages(query);
} else if (!args.isEmpty()) {
QString query = "SELECT * FROM packages WHERE";
foreach (const QString &pkg, args) {
query = query + " name LIKE \"" + pkg + "\"";
if (args.last() != pkg)
query = query + " OR";
case APM::ShowInformation:
{
if (args.isEmpty()) {
err << "akabei: An argument is needed" << endl;
return;
}
connect(backend, SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(showInformation(QUuid,QList<Akabei::Package*>)));
backend->searchPackages(args);
break;
}
case APM::ShowPackagesOfGroup:
{
if (args.isEmpty()) {
err << "akabei: An argument is needed" << endl;
return;
}
connect(backend, SIGNAL(queryGroupsCompleted(QUuid,QList<Akabei::Group*>)), SLOT(showGroup(QUuid,QList<Akabei::Group*>)));
backend->queryGroups("SELECT * FROM groups WHERE name LIKE \"" + args.first() + "\"");
break;
}
case APM::UpdateDatabases:
{
if (AkabeiClient::Backend::instance()->databases().isEmpty()) {
return;
}
QTextStream out(stdout);
out << i18n("Starting database update") << endl;
foreach (AkabeiClient::DatabaseHandler* db, AkabeiClient::Backend::instance()->databases()) {
if (db->name().length() > m_maxDbNameLenght)
m_maxDbNameLenght = db->name().length();
}
m_currentDatabasePos = 0;
updateNextDatabase();
break;
}
case APM::UpdateSystem:
{
QStringList locals;
foreach (Akabei::Package *p, Akabei::Backend::instance()->localDatabase()->packages()) {
locals << p->name();
}
connect(backend, SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(upgrade(QUuid,QList<Akabei::Package*>)));
queryId = backend->searchPackages(locals);
break;
}
case APM::Install:
{
if (args.isEmpty()) {
err << "akabei: An argument is needed." << endl;
}
connect(backend, SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(install(QUuid,QList<Akabei::Package*>)));
queryId = backend->searchPackages(args);
break;
}
default:
{
err << "akabei: No operation specified." << endl;
QCoreApplication::instance()->quit();
return;
}
connect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(install(QUuid,QList<Akabei::Package*>)));
queryId = Akabei::Backend::instance()->queryPackages(query);
} else {
QCoreApplication::instance()->quit();
}
}
void SyncOperation::upgrade(QUuid uuid, QList< Akabei::Package* > packages)
{
if (packages.isEmpty() || queryId != uuid)
if (packages.isEmpty() || queryId != uuid) {
return;
QHash<QString, QList<Akabei::Package*> > pkgs;
}
QHash<QString, QList<Akabei::Package*> > mappedpkgs;
foreach (Akabei::Package * pkg, packages) {
pkgs[pkg->name()].append(pkg);
mappedpkgs[pkg->name()].append(pkg);
}
QList<Akabei::Package*> toBeUpgraded;
foreach (const QString &pkg, pkgs.keys()) {
QList<Akabei::Package*> candidates = pkgs[pkg];
foreach (const QString &pkg, mappedpkgs.keys()) {
QList<Akabei::Package*> candidates = mappedpkgs[pkg];
if (!candidates.isEmpty()) {
QMap<Akabei::Package::Version, Akabei::Package*> versions;
Akabei::Package * local = 0;
foreach (Akabei::Package* p, candidates) {
if (p->database() == Akabei::Backend::instance()->localDatabase())
if (p->database() == Akabei::Backend::instance()->localDatabase()) {
local = p;
else
} else {
versions[p->version()] = p;
}
}
if (!local) //Something obviously is wrong here
/* Something is wrong */
if (!local) {
continue;
}
if (!versions.isEmpty() && versions.values().last()->version() > local->version()) {
toBeUpgraded << versions.values().last();
}
}
}
if (toBeUpgraded.isEmpty()) {
QCoreApplication::instance()->quit();
return;
}
QueueOperation *op = new QueueOperation(m_operations, m_options, this);
op->start(AkabeiClient::Update, toBeUpgraded);
connect(op, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit()));
......@@ -148,29 +199,34 @@ void SyncOperation::upgrade(QUuid uuid, QList< Akabei::Package* > packages)
void SyncOperation::install(QUuid uuid, QList< Akabei::Package* > packages)
{
if (queryId != uuid)
if (queryId != uuid) {
return;
}
disconnect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), this, SLOT(install(QUuid,QList<Akabei::Package*>)));
//FIXME: Cleanup and show all the packages and what is going to be done with them!
QTextStream out(stdout);
QTextStream err(stderr);
QMap<QString, Akabei::Package*> toBeInstalled;
QMap<QString, Akabei::Package*> toBeUpgraded;
QMap<QString, Akabei::Package*> toBeReinstalled;
QMap<QString, Akabei::Package*> local;
foreach (Akabei::Package * pkg, packages) {
qDebug() << "Queried" << pkg->name();
if (pkg->database() == Akabei::Backend::instance()->localDatabase()) {
qDebug() << "It's a local package";
local[pkg->name()] = pkg;
packages.removeAll(pkg);
}
}
if (packages.isEmpty()) {
out << i18n("No appropriate packages found") << endl;
out.flush();
QCoreApplication::instance()->quit();
err << i18n("No appropriate packages found") << endl;
err.flush();
return;
}
foreach (Akabei::Package * pkg, packages) {
if (toBeInstalled.contains(pkg->name()) && toBeInstalled[pkg->name()]->version() < pkg->version()) {
toBeInstalled[pkg->name()] = pkg;
......@@ -188,26 +244,25 @@ void SyncOperation::install(QUuid uuid, QList< Akabei::Package* > packages)
} else {
toBeInstalled[pkg->name()] = pkg;
}
/* if (!toBeInstalled[pkg->name()] || toBeInstalled[pkg->name()]->version() < pkg->version()) {
toBeInstalled[pkg->name()] = pkg;
if (local.contains(pkg->name()) && (pkg->version() > local[pkg->name()]->version())) {
local.remove(pkg->name());
}
}*/
}
if (toBeInstalled.isEmpty() && toBeUpgraded.isEmpty() && toBeReinstalled.isEmpty()) {
out << i18n("No appropriate packages found") << endl;
out.flush();
QCoreApplication::instance()->quit();
return;
}
if (!toBeReinstalled.isEmpty() || !toBeUpgraded.isEmpty()) {
Akabei::Package::List pkgs = toBeReinstalled.values();
pkgs << toBeUpgraded.values();
if (pkgs.count() == 1) { //It's only one package
Akabei::Package * pkg = pkgs.first();
out << i18n("The following package was already found on your system: ")
<< pkg->name() << " (" << local[pkg->name()]->version().toByteArray() << ")" << endl;
if (!toBeReinstalled.isEmpty()) {
out << i18n("Do you want to reinstall it?[Y/n]");
} else {
......@@ -215,8 +270,10 @@ void SyncOperation::install(QUuid uuid, QList< Akabei::Package* > packages)
}
} else { //Multiple packages
out << i18n("Some packages were already found on your system.") << endl;
if (!toBeUpgraded.isEmpty()) {
out << i18n("The following packages are going to be upgraded:");
foreach (Akabei::Package * p, toBeUpgraded.values()) {
out << " " << p->name() << " (" << local[p->name()]->version().toByteArray().data() << " -> " << p->version().toByteArray() << ")";
if (p != toBeUpgraded.values().last())
......@@ -225,8 +282,10 @@ void SyncOperation::install(QUuid uuid, QList< Akabei::Package* > packages)
out << endl;
}
}
if (!toBeReinstalled.isEmpty()) {
out << i18n("The following packages are going to be reinstalled:");
foreach (Akabei::Package * p, toBeReinstalled.values()) {
out << " " << p->name() << " (" << p->version().toByteArray().data() << ")";
if (p != toBeReinstalled.values().last())
......@@ -238,24 +297,6 @@ void SyncOperation::install(QUuid uuid, QList< Akabei::Package* > packages)
out << i18n("Do you want to continue?[Y/n]");
}
out.flush();
/*if (local.count() > 1) {
out << i18n("The following packages were already installed on your system:");
foreach (Akabei::Package* pkg, local.values()) {
out << " " << pkg->name() << " (" << pkg->version().toByteArray().data() << ")";
if (pkg != local.values().last())
out << ",";
}
out << "." << endl;
out << i18n("Do you want to reinstall them?[Y/n]");
} else {
Akabei::Package * pkg = local.values().first();
out << i18n("The package %1 (%2) is already installed.", pkg->name(), pkg->version().toByteArray().data()) << endl;
if (pkg->version() == toBeInstalled[pkg->name()]->version())
out << i18n("Do you want to reinstall it?[Y/n]");
else
out << i18n("Do you want to upgrade it to %1?[Y/n]").arg(QString(toBeInstalled[pkg->name()]->version().toByteArray()));
}
out.flush();*/
std::string input;
getline(std::cin, input);
......@@ -276,10 +317,13 @@ void SyncOperation::searchResult(QUuid , QList< Akabei::Package* > packages)
QCoreApplication::instance()->quit();
return;
}
QTextStream out(stdout);
foreach (Akabei::Package * p, packages) {
if (p->database() == Akabei::Backend::instance()->localDatabase())
continue;
bool installed = !Akabei::Backend::instance()->localDatabase()->queryPackages("SELECT * FROM packages WHERE name=\"" + p->name() + "\" AND version=\"" + p->version().toByteArray() + "\"").isEmpty();
AkabeiClient::DatabaseHandler * db = 0;
foreach (AkabeiClient::DatabaseHandler *database, AkabeiClient::Backend::instance()->databases()) {
......@@ -288,21 +332,20 @@ void SyncOperation::searchResult(QUuid , QList< Akabei::Package* > packages)
break;
}
}
if (!db)
continue;
out << db->name() << '/' << p->name() << ' ' << p->version().toByteArray().data();
if (installed)
out << ' ' << i18n("[Installed]");
out << endl;
out << " " << p->description() << endl;
}
out.flush();
QList<APM::Operation> opts = m_operations;
opts.removeAll(APM::Search);
QStringList args = m_args;
if (!args.isEmpty())
args.removeFirst();
start(opts, m_options, args);
nextOperation();
}
void SyncOperation::listRepo(const QString &repo)
......@@ -329,89 +372,128 @@ void SyncOperation::listRepo(const QString &repo)
out << endl;
}
out.flush();
QList<APM::Operation> opts = m_operations;
opts.removeAll(APM::ListRepo);
QStringList args = m_args;
if (!args.isEmpty())
args.removeFirst();
start(opts, m_options, args);
nextOperation();
}
void SyncOperation::showInformation(QUuid,QList<Akabei::Package*> packages)
{
if (packages.isEmpty())
if (packages.isEmpty()) {
return;
//We only take the local package when we have really no chance
Akabei::Package * pkg = 0;
QList<Akabei::Package*>::iterator it = packages.begin();
while ((*it) && (*it)->database() == Akabei::Backend::instance()->localDatabase())
it++;
pkg = *it;
if (!pkg)
pkg = packages.first();
}
/*
* If a package is present more than one time, it means it's on the local db too.
* Take the local package only when no other choice is present.
*/
QHash<QString, Akabei::Package *> mappedpkgs;
foreach (Akabei::Package *p, packages) {
mappedpkgs[p->name()] = p;
}
packages.clear();
foreach (const QString& name, mappedpkgs.keys()) {
if (mappedpkgs.count(name) > 1) {
foreach (Akabei::Package *p, mappedpkgs.values(name)) {
if (p->database() != Akabei::Backend::instance()->localDatabase()) {
packages << p;
}
}
} else {
packages << mappedpkgs[name];
}
}
QTextStream out(stdout);
/* TODO: discover how to disable these features: reset() doesn't work */
out.setFieldWidth(30);
out.setFieldAlignment(QTextStream::AlignLeft);
AkabeiClient::DatabaseHandler * db = 0;
foreach (AkabeiClient::DatabaseHandler * database, AkabeiClient::Backend::instance()->databases()) {
if (database->database() == pkg->database()) {
db = database;
break;
/* Prints the information for every package */
foreach (Akabei::Package *pkg, packages) {
AkabeiClient::DatabaseHandler * db = 0;
foreach (AkabeiClient::DatabaseHandler * database, AkabeiClient::Backend::instance()->databases()) {
if (database->database() == pkg->database()) {
db = database;
break;
}
}
if (db) {
out << i18n("Repository") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << db->name() << endl;
} else {
kDebug() << pkg->database()->name();
}
out << i18n("Name") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->name() << endl;
out << i18n("Version") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << QString(pkg->version().toByteArray().data()) << endl;
out << i18n("URL") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->url().toString() << endl;
out << i18n("Licenses") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->license() << endl;
QStringList groups;
foreach (Akabei::Group * g, pkg->groups())
groups << g->name();
out << i18n("Groups") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << groups.join(" ") << endl;
out << i18n("Provides") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->provides().join(" ") << endl;
out << i18n("Depends on") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->dependencies().join(" ") << endl;
out << i18n("Optional dependencies") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->optionalDependencies().join(" ") << endl;
//out << i18n("Required by:") << pkg->
out << i18n("Replaces") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->replaces().join(" ") << endl;
out << i18n("Installation size") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << KIO::convertSize(pkg->size()) << endl;
out << i18n("Packager") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->packager() << endl;
out << i18n("Architecture") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->arch() << endl;
out << i18n("Creation time") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->buildDate().toString() << endl;
out << i18n("MD5 sum") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->md5sum().data() << endl;
out << i18n("Description") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->description() << endl << endl;
out.flush();
}
if (db) {
out << i18n("Repository") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << db->name() << endl;
} else {
kDebug() << pkg->database()->name();
}
out << i18n("Name") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->name() << endl;
out << i18n("Version") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << QString(pkg->version().toByteArray().data()) << endl;
out << i18n("URL") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->url().toString() << endl;
out << i18n("Licenses") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->license() << endl;
QStringList groups;
foreach (Akabei::Group * g, pkg->groups())
groups << g->name();
out << i18n("Groups") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << groups.join(" ") << endl;
out << i18n("Provides") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->provides().join(" ") << endl;
out << i18n("Depends on") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->dependencies().join(" ") << endl;
out << i18n("Optional dependencies") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->optionalDependencies().join(" ") << endl;
//out << i18n("Required by:") << pkg->
out << i18n("Replaces"