syncoperation.cpp 19 KB
Newer Older
Lisa's avatar
Lisa committed
1
/* This file is part of the Chakra project
Lukas Appelhans's avatar
Lukas Appelhans committed
2 3 4 5 6 7 8 9 10 11

   Copyright (C) 2010 Lukas Appelhans

   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 "syncoperation.h"
Lisa's avatar
Lisa committed
12
#include "queueoperation.h"
Lukas Appelhans's avatar
Lukas Appelhans committed
13

Lukas Appelhans's avatar
Lukas Appelhans committed
14 15 16 17
#include <akabeibackend.h>
#include <akabeipackage.h>
#include <akabeidatabase.h>
#include <akabeiclientbackend.h>
18
#include <akabeiconfig.h>
Lisa's avatar
Lisa committed
19 20 21 22 23 24
#include <akabeigroup.h>
#include <akabeiclientqueue.h>
#include <akabeiclienttransactionhandler.h>
#include <akabeioperation.h>
#include <akabeioperationrunner.h>

Lukas Appelhans's avatar
Lukas Appelhans committed
25
#include <QTextStream>
Lukas Appelhans's avatar
Lukas Appelhans committed
26
#include <QDateTime>
27
#include <QCoreApplication>
28 29
#include <QFile>
#include <QDir>
Lisa's avatar
Lisa committed
30 31 32 33

#include <klocale.h>
#include <kio/global.h>
#include <kdebug.h>
34
#include <kio/global.h>
Lukas Appelhans's avatar
Lukas Appelhans committed
35

Lisa's avatar
Lisa committed
36
#include <iostream>
Lukas Appelhans's avatar
Lukas Appelhans committed
37

Lisa's avatar
Lisa committed
38
SyncOperation::SyncOperation(QObject* parent)
Lisa's avatar
Lisa committed
39 40
    : QObject(parent)
    , m_maxDbNameLenght(0)
Lisa's avatar
Lisa committed
41
{}
Lukas Appelhans's avatar
Lukas Appelhans committed
42

Lisa's avatar
Lisa committed
43
SyncOperation::~SyncOperation() {}
Lukas Appelhans's avatar
Lukas Appelhans committed
44

Lukas Appelhans's avatar
TODO  
Lukas Appelhans committed
45 46 47
//TODO: Instead of putting all in operation, we want to split stuff like SkipDependencies into some special flags parameter :) that way
// we can have proper errorhandling
// or let shainer write that CLI parser
48
void SyncOperation::start(APM::OperationName operation, QHash<APM::OptionName, AkabeiOption> options, QStringList args)
Lukas Appelhans's avatar
Lukas Appelhans committed
49
{
Lisa's avatar
Lisa committed
50 51
    QTextStream err(stderr);
    Akabei::Backend *backend = Akabei::Backend::instance();
Lisa's avatar
Lisa committed
52

53
    m_operation = operation;
Lukas Appelhans's avatar
Lukas Appelhans committed
54 55
    m_options = options;
    m_args = args;
Lisa's avatar
Lisa committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

    switch (operation) {
    case APM::Search: {
        connect(backend, SIGNAL(queryPackagesCompleted(QUuid, QList<Akabei::Package*>)), SLOT(searchResult(QUuid, QList<Akabei::Package*>)));
        backend->searchPackages(args);
        break;
    }

    case APM::ListRepo: {
        listRepo(args.first());
        break;
    }

    case APM::ShowInformation: {
        connect(backend, SIGNAL(queryPackagesCompleted(QUuid, QList<Akabei::Package*>)), SLOT(showInformation(QUuid, QList<Akabei::Package*>)));
        backend->searchPackages(args, Akabei::SearchNameEqual);
        break;
    }

    case APM::ShowPackagesOfGroup: {
        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: {
        updateDatabases();
        break;
    }

    case APM::UpdateSystem: {
        updateSystem();
        break;
    }

    case APM::UpdateDatabaseAndSystem: {
        updateDatabases();
        updateSystem();
        break;
    }

    case APM::Install: {
        connect(backend, SIGNAL(queryPackagesCompleted(QUuid, QList<Akabei::Package*>)), SLOT(install(QUuid, QList<Akabei::Package*>)));
        queryId = backend->searchPackages(args, Akabei::SearchNameEqual);
        break;
    }

    default: {
        err << i18n("akabei: Operation not supported yet.") << endl;
        QCoreApplication::instance()->quit();
        return;
    }
108 109 110
    }
}

111 112 113 114 115
void SyncOperation::updateDatabases()
{
    QTextStream out(stdout);
    out << i18n("Starting database update") << endl;

Lisa's avatar
Lisa committed
116
    foreach(AkabeiClient::DatabaseHandler * db, AkabeiClient::Backend::instance()->databases()) {
117 118 119 120 121 122 123 124 125 126
        if (db->name().length() > m_maxDbNameLenght)
            m_maxDbNameLenght = db->name().length();
    }
    m_currentDatabasePos = 0;
    updateNextDatabase();
}

void SyncOperation::updateSystem()
{
    QStringList locals;
Lisa's avatar
Lisa committed
127
    foreach(Akabei::Package * p, Akabei::Backend::instance()->localDatabase()->packages()) {
128 129
        locals << p->name();
    }
Lisa's avatar
Lisa committed
130 131

    connect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid, QList<Akabei::Package*>)), SLOT(upgrade(QUuid, QList<Akabei::Package*>)));
132 133 134 135
    queryId = Akabei::Backend::instance()->searchPackages(locals, Akabei::SearchNameEqual);
}


Lukas Appelhans's avatar
Lukas Appelhans committed
136
void SyncOperation::upgrade(QUuid uuid, QList< Akabei::Package* > packages)
137
{
Lisa's avatar
Lisa committed
138
    if (packages.isEmpty() || queryId != uuid) {
Lukas Appelhans's avatar
Lukas Appelhans committed
139
        return;
Lisa's avatar
Lisa committed
140
    }
Lisa's avatar
Lisa committed
141

Lisa's avatar
Lisa committed
142
    QHash<QString, QList<Akabei::Package*> > mappedpkgs;
Lisa's avatar
Lisa committed
143
    foreach(Akabei::Package * pkg, packages) {
Lisa's avatar
Lisa committed
144
        mappedpkgs[pkg->name()].append(pkg);
145
    }
Lisa's avatar
Lisa committed
146

147
    QList<Akabei::Package*> toBeUpgraded;
Lisa's avatar
Lisa committed
148
    foreach(const QString & pkg, mappedpkgs.keys()) {
Lisa's avatar
Lisa committed
149
        QList<Akabei::Package*> candidates = mappedpkgs[pkg];
Lisa's avatar
Lisa committed
150

151 152 153
        if (!candidates.isEmpty()) {
            QMap<Akabei::Package::Version, Akabei::Package*> versions;
            Akabei::Package * local = 0;
Lisa's avatar
Lisa committed
154 155

            foreach(Akabei::Package * p, candidates) {
Lisa's avatar
Lisa committed
156
                if (p->database() == Akabei::Backend::instance()->localDatabase()) {
157
                    local = p;
Lisa's avatar
Lisa committed
158
                } else {
159
                    versions[p->version()] = p;
Lisa's avatar
Lisa committed
160
                }
161
            }
Lisa's avatar
Lisa committed
162

Lisa's avatar
Lisa committed
163 164
            /* Something is wrong */
            if (!local) {
165
                continue;
Lisa's avatar
Lisa committed
166
            }
Lisa's avatar
Lisa committed
167

168
            if (!versions.isEmpty() && versions.values().last()->version() > local->version()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
169
                toBeUpgraded << versions.values().last();
170 171 172
            }
        }
    }
Lisa's avatar
Lisa committed
173

Lukas Appelhans's avatar
Lukas Appelhans committed
174 175 176
    if (toBeUpgraded.isEmpty()) {
        return;
    }
Lisa's avatar
Lisa committed
177

178
    QueueOperation *op = new QueueOperation(m_operation, m_options, this);
179 180
    op->start(AkabeiClient::Update, toBeUpgraded);
    connect(op, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit()));
181 182
}

Lukas Appelhans's avatar
Lukas Appelhans committed
183
void SyncOperation::install(QUuid uuid, QList< Akabei::Package* > packages)
184
{
Lisa's avatar
Lisa committed
185
    if (queryId != uuid) {
Lukas Appelhans's avatar
Lukas Appelhans committed
186
        return;
Lisa's avatar
Lisa committed
187
    }
Lisa's avatar
Lisa committed
188 189 190

    disconnect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid, QList<Akabei::Package*>)), this, SLOT(install(QUuid, QList<Akabei::Package*>)));

Lukas Appelhans's avatar
Lukas Appelhans committed
191
    //FIXME: Cleanup and show all the packages and what is going to be done with them!
192
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
193
    QTextStream err(stderr);
Lisa's avatar
Lisa committed
194

195
    QMap<QString, Akabei::Package*> toBeInstalled;
196 197
    QMap<QString, Akabei::Package*> toBeUpgraded;
    QMap<QString, Akabei::Package*> toBeReinstalled;
198
    QMap<QString, Akabei::Package*> local;
Lisa's avatar
Lisa committed
199 200

    foreach(Akabei::Package * pkg, packages) {
201
        qDebug() << "Found" << pkg->name();
202
        if (pkg->database() == Akabei::Backend::instance()->localDatabase()) {
203
            qDebug() << "Local";
204
            local[pkg->name()] = pkg;
205 206 207
            packages.removeAll(pkg);
        }
    }
Lisa's avatar
Lisa committed
208

209
    if (packages.isEmpty()) {
Lisa's avatar
Lisa committed
210 211
        err << i18n("No appropriate packages found") << endl;
        err.flush();
212
        return;
213
    }
Lisa's avatar
Lisa committed
214 215

    foreach(Akabei::Package * pkg, packages) {
216 217 218 219 220 221 222 223 224 225 226 227
        if (toBeInstalled.contains(pkg->name()) && toBeInstalled[pkg->name()]->version() < pkg->version()) {
            toBeInstalled[pkg->name()] = pkg;
        } else if (toBeUpgraded.contains(pkg->name()) && toBeUpgraded[pkg->name()]->version() < pkg->version()) {
            toBeUpgraded[pkg->name()] = pkg;
        } else if (toBeReinstalled.contains(pkg->name()) && toBeReinstalled[pkg->name()]->version() < pkg->version()) {
            toBeReinstalled.remove(pkg->name());
            toBeUpgraded[pkg->name()] = pkg;
        } else if (local.contains(pkg->name())) {
            if (local[pkg->name()]->version() == pkg->version()) {
                toBeReinstalled[pkg->name()] = pkg;
            } else if (local[pkg->name()]->version() < pkg->version()) {
                toBeUpgraded[pkg->name()] = pkg;
Lukas Appelhans's avatar
Lukas Appelhans committed
228
            }
229 230
        } else {
            toBeInstalled[pkg->name()] = pkg;
231
        }
Lisa's avatar
Lisa committed
232

233
    }
Lisa's avatar
Lisa committed
234

235 236 237 238
    if (toBeInstalled.isEmpty() && toBeUpgraded.isEmpty() && toBeReinstalled.isEmpty()) {
        out << i18n("No appropriate packages found") << endl;
        out.flush();
        QCoreApplication::instance()->quit();
239
        return;
240
    }
Lisa's avatar
Lisa committed
241

242 243 244
    if (!toBeReinstalled.isEmpty() || !toBeUpgraded.isEmpty()) {
        Akabei::Package::List pkgs = toBeReinstalled.values();
        pkgs << toBeUpgraded.values();
Lisa's avatar
Lisa committed
245

246 247 248 249
        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;
Lisa's avatar
Lisa committed
250

251 252 253 254 255 256 257
            if (!toBeReinstalled.isEmpty()) {
                out << i18n("Do you want to reinstall it?[Y/n]");
            } else {
                out << i18n("Do you want to upgrade it to version %1?[Y/n]").arg(QString(pkg->version().toByteArray()));
            }
        } else { //Multiple packages
            out << i18n("Some packages were already found on your system.") << endl;
Lisa's avatar
Lisa committed
258

259 260
            if (!toBeUpgraded.isEmpty()) {
                out << i18n("The following packages are going to be upgraded:");
Lisa's avatar
Lisa committed
261 262

                foreach(Akabei::Package * p, toBeUpgraded.values()) {
263 264 265 266 267 268 269
                    out << " " << p->name() << " (" << local[p->name()]->version().toByteArray().data() << " -> " << p->version().toByteArray() << ")";
                    if (p != toBeUpgraded.values().last())
                        out << ",";
                    else
                        out << endl;
                }
            }
Lisa's avatar
Lisa committed
270

271 272
            if (!toBeReinstalled.isEmpty()) {
                out << i18n("The following packages are going to be reinstalled:");
Lisa's avatar
Lisa committed
273 274

                foreach(Akabei::Package * p, toBeReinstalled.values()) {
275 276 277 278 279 280 281 282 283 284
                    out << " " << p->name() << " (" << p->version().toByteArray().data() << ")";
                    if (p != toBeReinstalled.values().last())
                        out << ",";
                    else
                        out << endl;
                }
            }
            out << i18n("Do you want to continue?[Y/n]");
        }
        out.flush();
285 286 287

        std::string input;
        getline(std::cin, input);
288 289
        if (!input.empty() && input != i18n("y").toStdString()) {
            QCoreApplication::instance()->quit();
290
            return;
291
        }
292 293
    }

294
    QueueOperation *op = new QueueOperation(m_operation, m_options, this);
295
    op->start(AkabeiClient::Install, toBeInstalled.values() + toBeUpgraded.values() + toBeReinstalled.values());
296
    connect(op, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit()));
297 298
}

Lukas Appelhans's avatar
Lukas Appelhans committed
299 300
void SyncOperation::searchResult(QUuid , QList< Akabei::Package* > packages)
{
301 302
    if (packages.isEmpty()) {
        QCoreApplication::instance()->quit();
Lukas Appelhans's avatar
Lukas Appelhans committed
303
        return;
304
    }
Lisa's avatar
Lisa committed
305

Lukas Appelhans's avatar
Lukas Appelhans committed
306
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
307 308

    foreach(Akabei::Package * p, packages) {
Lukas Appelhans's avatar
Lukas Appelhans committed
309 310
        if (p->database() == Akabei::Backend::instance()->localDatabase())
            continue;
Lisa's avatar
Lisa committed
311

Lukas Appelhans's avatar
Lukas Appelhans committed
312
        bool installed = !Akabei::Backend::instance()->localDatabase()->queryPackages("SELECT * FROM packages WHERE name=\"" + p->name() + "\" AND version=\"" + p->version().toByteArray() + "\"").isEmpty();
Lukas Appelhans's avatar
Lukas Appelhans committed
313
        AkabeiClient::DatabaseHandler * db = 0;
Lisa's avatar
Lisa committed
314
        foreach(AkabeiClient::DatabaseHandler * database, AkabeiClient::Backend::instance()->databases()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
315 316 317 318 319
            if (database->database() == p->database()) {
                db = database;
                break;
            }
        }
Lisa's avatar
Lisa committed
320

Lukas Appelhans's avatar
Lukas Appelhans committed
321 322
        if (!db)
            continue;
Lisa's avatar
Lisa committed
323

Lukas Appelhans's avatar
Lukas Appelhans committed
324 325 326
        out << db->name() << '/' << p->name() << ' ' << p->version().toByteArray().data();
        if (installed)
            out << ' ' << i18n("[Installed]");
Lisa's avatar
Lisa committed
327

Lukas Appelhans's avatar
Lukas Appelhans committed
328 329 330
        out << endl;
        out << "    " << p->description() << endl;
    }
Lisa's avatar
Lisa committed
331

Lukas Appelhans's avatar
Lukas Appelhans committed
332
    out.flush();
333
    QCoreApplication::instance()->quit();
Lukas Appelhans's avatar
Lukas Appelhans committed
334
}
Lukas Appelhans's avatar
Lukas Appelhans committed
335

Lukas Appelhans's avatar
Lukas Appelhans committed
336 337 338
void SyncOperation::listRepo(const QString &repo)
{
    AkabeiClient::DatabaseHandler * db = 0;
Lisa's avatar
Lisa committed
339
    foreach(AkabeiClient::DatabaseHandler * database, AkabeiClient::Backend::instance()->databases()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
340 341 342 343 344 345 346 347
        if (database->name() == repo) {
            db = database;
            break;
        }
    }
    if (!db)
        return;
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
348
    foreach(Akabei::Package * pkg, db->database()->packages()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
349 350 351 352 353 354 355 356 357 358 359
        Akabei::Package::List installed = Akabei::Backend::instance()->localDatabase()->queryPackages("SELECT * FROM packages WHERE Name LIKE \"" + pkg->name() + "\"");
        out << db->name() << ' ' << pkg->name() << ' ' << pkg->version().toByteArray().data();
        if (!installed.isEmpty()) {
            if (installed.first()->version() == pkg->version())
                out << ' ' << i18n("[Installed]");
            else
                out << ' ' << i18n("[Installed: %1]", installed.first()->version().toByteArray().data());
        }
        out << endl;
    }
    out.flush();
360
    QCoreApplication::instance()->quit();
Lukas Appelhans's avatar
Lukas Appelhans committed
361 362
}

Lisa's avatar
Lisa committed
363
void SyncOperation::showInformation(QUuid, QList<Akabei::Package*> packages)
Lukas Appelhans's avatar
Lukas Appelhans committed
364
{
Lisa's avatar
Lisa committed
365
    if (packages.isEmpty()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
366
        return;
Lisa's avatar
Lisa committed
367
    }
Lisa's avatar
Lisa committed
368

Lisa's avatar
Lisa committed
369 370 371 372 373
    /*
     * 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;
Lisa's avatar
Lisa committed
374
    foreach(Akabei::Package * p, packages) {
Lisa's avatar
Lisa committed
375 376 377
        mappedpkgs[p->name()] = p;
    }
    packages.clear();
Lisa's avatar
Lisa committed
378 379

    foreach(const QString & name, mappedpkgs.keys()) {
Lisa's avatar
Lisa committed
380
        if (mappedpkgs.count(name) > 1) {
Lisa's avatar
Lisa committed
381
            foreach(Akabei::Package * p, mappedpkgs.values(name)) {
Lisa's avatar
Lisa committed
382 383 384 385 386 387 388 389
                if (p->database() != Akabei::Backend::instance()->localDatabase()) {
                    packages << p;
                }
            }
        } else {
            packages << mappedpkgs[name];
        }
    }
Lisa's avatar
Lisa committed
390

Lukas Appelhans's avatar
Lukas Appelhans committed
391
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
392

Lisa's avatar
Lisa committed
393
    /* TODO: discover how to disable these features: reset() doesn't work */
Lukas Appelhans's avatar
Lukas Appelhans committed
394 395
    out.setFieldWidth(30);
    out.setFieldAlignment(QTextStream::AlignLeft);
Lisa's avatar
Lisa committed
396

Lisa's avatar
Lisa committed
397
    /* Prints the information for every package */
Lisa's avatar
Lisa committed
398
    foreach(Akabei::Package * pkg, packages) {
Lisa's avatar
Lisa committed
399
        AkabeiClient::DatabaseHandler * db = 0;
Lisa's avatar
Lisa committed
400
        foreach(AkabeiClient::DatabaseHandler * database, AkabeiClient::Backend::instance()->databases()) {
Lisa's avatar
Lisa committed
401 402 403 404
            if (database->database() == pkg->database()) {
                db = database;
                break;
            }
Lukas Appelhans's avatar
Lukas Appelhans committed
405
        }
Lisa's avatar
Lisa committed
406

Lisa's avatar
Lisa committed
407 408 409 410 411
        if (db) {
            out << i18n("Repository") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << db->name() << endl;
        } else {
            kDebug() << pkg->database()->name();
        }
Lisa's avatar
Lisa committed
412

Lisa's avatar
Lisa committed
413
        out << i18n("Name") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->name() << endl;
414
        out << i18n("APM::Version") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << QString(pkg->version().toByteArray().data()) << endl;
Lisa's avatar
Lisa committed
415 416 417
        out << i18n("URL") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->url().toString() << endl;
        out << i18n("Licenses") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->license() << endl;
        QStringList groups;
Lisa's avatar
Lisa committed
418 419
        foreach(Akabei::Group * g, pkg->groups())
        groups << g->name();
Lisa's avatar
Lisa committed
420 421 422 423 424 425 426 427 428 429 430 431 432
        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();
Lukas Appelhans's avatar
Lukas Appelhans committed
433
    }
Lisa's avatar
Lisa committed
434

Lisa's avatar
Lisa committed
435
    out.reset();
436
    QCoreApplication::instance()->quit();
Lukas Appelhans's avatar
Lukas Appelhans committed
437 438
}

Lisa's avatar
Lisa committed
439
void SyncOperation::showGroup(QUuid uuid, QList<Akabei::Group*> groups)
Lukas Appelhans's avatar
Lukas Appelhans committed
440 441
{
    Q_UNUSED(uuid)
Lisa's avatar
Lisa committed
442

Lisa's avatar
Lisa committed
443
    if (groups.isEmpty()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
444
        return;
Lisa's avatar
Lisa committed
445
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
446
    Akabei::Group * group = groups.first();
Lisa's avatar
Lisa committed
447

Lukas Appelhans's avatar
Lukas Appelhans committed
448 449
    QTextStream out(stdout);
    QMap<QString, Akabei::Package*> sorted;
Lisa's avatar
Lisa committed
450 451

    foreach(Akabei::Package * pkg, group->packages()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
452
        sorted[pkg->name()] = pkg;
Lisa's avatar
Lisa committed
453
    }
Lisa's avatar
Lisa committed
454 455

    foreach(Akabei::Package * pkg, sorted.values()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
456
        out << group->name() << ' ' << pkg->name() << endl;
Lisa's avatar
Lisa committed
457
    }
Lisa's avatar
Lisa committed
458

Lukas Appelhans's avatar
Lukas Appelhans committed
459
    out.flush();
460
    QCoreApplication::instance()->quit();
Lukas Appelhans's avatar
Lukas Appelhans committed
461 462
}

463 464
void SyncOperation::updateNextDatabase()
{
Lukas Appelhans's avatar
Lukas Appelhans committed
465
    if (m_currentDatabasePos == AkabeiClient::Backend::instance()->databases().count()) {
466
        QTextStream out(stdout);
467
        out << i18n("Updating all databases finished") << endl;
468 469
        return;
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
470
    AkabeiClient::DatabaseHandler* db = AkabeiClient::Backend::instance()->databases().at(m_currentDatabasePos);
471 472 473
    connect(db, SIGNAL(statusChanged(AkabeiClient::DatabaseHandler::Status)), this, SLOT(databaseStatusChanged(AkabeiClient::DatabaseHandler::Status)));
    connect(db, SIGNAL(progress(int)), this, SLOT(databaseProgressChanged(int)));
    connect(db, SIGNAL(errorTriggered(int)), this, SLOT(databaseErrorTriggered(int)));
474
    db->update(m_options.contains(APM::Force));
475 476
}

Lukas Appelhans's avatar
Lukas Appelhans committed
477 478
void SyncOperation::databaseErrorTriggered(int error)
{
479
    Q_UNUSED(error)
Lisa's avatar
Lisa committed
480
    QTextStream err(stderr);
Lukas Appelhans's avatar
Lukas Appelhans committed
481
    //FIXME: Show proper error message
Lisa's avatar
Lisa committed
482
    err << i18n("There has been an error while updating %1!", static_cast<AkabeiClient::DatabaseHandler*>(QObject::sender())->name()) << endl;
Lukas Appelhans's avatar
Lukas Appelhans committed
483 484 485 486 487
}

void SyncOperation::databaseProgressChanged(int progress)
{
    QTextStream out(stdout);
488
    out.reset();
Lukas Appelhans's avatar
Lukas Appelhans committed
489
    out << qSetFieldWidth(m_maxDbNameLenght) << static_cast<AkabeiClient::DatabaseHandler*>(QObject::sender())->name() << qSetFieldWidth(0);
Lukas Appelhans's avatar
Lukas Appelhans committed
490 491 492 493 494 495 496 497
    out << " [";
    for (int i = 1; i != 11; i++) {
        if (progress / i >= 10) {
            out << "#";
        } else {
            out << "-";
        }
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
498
    out << "] " << progress << "%                                   ";//FIXME
499 500 501
    //if (progress == 100) {
    //    out << endl;
    //} else {
Lisa's avatar
Lisa committed
502
    out << "\r";
503
    //}
Lukas Appelhans's avatar
Lukas Appelhans committed
504 505 506 507 508
    out.flush();
}

void SyncOperation::databaseStatusChanged(AkabeiClient::DatabaseHandler::Status status)
{
Lisa's avatar
Lisa committed
509 510 511
    if (status != AkabeiClient::DatabaseHandler::StatusFinished &&
            status != AkabeiClient::DatabaseHandler::StatusUpToDate &&
            status != AkabeiClient::DatabaseHandler::StatusError) {
512
        return;
Lisa's avatar
Lisa committed
513
    }
Lisa's avatar
Lisa committed
514

Lukas Appelhans's avatar
Lukas Appelhans committed
515
    AkabeiClient::DatabaseHandler* db = AkabeiClient::Backend::instance()->databases().at(m_currentDatabasePos);
516 517 518
    disconnect(db, SIGNAL(statusChanged(AkabeiClient::DatabaseHandler::Status)), this, SLOT(databaseStatusChanged(AkabeiClient::DatabaseHandler::Status)));
    disconnect(db, SIGNAL(progress(int)), this, SLOT(databaseProgressChanged(int)));
    disconnect(db, SIGNAL(errorTriggered(int)), this, SLOT(databaseErrorTriggered(int)));
Lisa's avatar
Lisa committed
519

520 521 522
    QTextStream out(stdout);
    if (status == AkabeiClient::DatabaseHandler::StatusUpToDate) {
        out << i18n("%1 already up to date!", db->name()) << endl;
Lukas Appelhans's avatar
Lukas Appelhans committed
523 524
    } else if (status == AkabeiClient::DatabaseHandler::StatusError) {
        out << i18n("%1 could not be updated!", db->name()) << endl;
525 526 527
    } else {
        out << i18n("%1 updated!", db->name()) << endl;
    }
528

Lukas Appelhans's avatar
Lukas Appelhans committed
529
    m_currentDatabasePos++;
530
    updateNextDatabase();
Lukas Appelhans's avatar
Lukas Appelhans committed
531
}