syncoperation.cpp 19.7 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(QList<APM::OperationName> operations, QHash<APM::OptionName, AkabeiOption> options, QStringList args, QObject* parent)
Lisa's avatar
Lisa committed
39 40
  : QObject(parent)
  , m_maxDbNameLenght(0)
Lisa's avatar
Lisa committed
41 42 43
  , m_operations(operations)
  , m_options(options)
  , m_args(args)
Lisa's avatar
Lisa committed
44
{}
Lukas Appelhans's avatar
Lukas Appelhans committed
45

Lisa's avatar
Lisa committed
46
SyncOperation::~SyncOperation() {}
Lukas Appelhans's avatar
Lukas Appelhans committed
47

Lukas Appelhans's avatar
TODO  
Lukas Appelhans committed
48 49 50
//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
Lisa's avatar
Lisa committed
51
void SyncOperation::start()
Lukas Appelhans's avatar
Lukas Appelhans committed
52
{
Lisa's avatar
Lisa committed
53 54
    QTextStream err(stderr);
    Akabei::Backend *backend = Akabei::Backend::instance();
Lisa's avatar
Lisa committed
55
    
Lisa's avatar
Lisa committed
56 57
    APM::OperationName operation = m_operations.takeFirst();
    
Lisa's avatar
Lisa committed
58 59 60 61 62
    
    switch(operation) {
        case APM::Search:
        {            
            connect(backend, SIGNAL(queryPackagesCompleted(QUuid, QList<Akabei::Package*>)), SLOT(searchResult(QUuid,QList<Akabei::Package*>)));
Lisa's avatar
Lisa committed
63
            backend->searchPackages(m_args);
Lisa's avatar
Lisa committed
64 65 66 67 68
            break;
        }
        
        case APM::ListRepo:
        {            
Lisa's avatar
Lisa committed
69
            listRepo(m_args.first());
Lisa's avatar
Lisa committed
70 71 72 73 74 75
            break;
        }
            
        case APM::ShowInformation:
        {
            connect(backend, SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(showInformation(QUuid,QList<Akabei::Package*>)));
Lisa's avatar
Lisa committed
76
            backend->searchPackages(m_args, Akabei::SearchNameEqual);
Lisa's avatar
Lisa committed
77 78 79 80 81 82
            break;
        }
            
        case APM::ShowPackagesOfGroup:
        {
            connect(backend, SIGNAL(queryGroupsCompleted(QUuid,QList<Akabei::Group*>)), SLOT(showGroup(QUuid,QList<Akabei::Group*>)));
Lisa's avatar
Lisa committed
83
            backend->queryGroups("SELECT * FROM groups WHERE name LIKE \"" + m_args.first() + "\"");
Lisa's avatar
Lisa committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
            break;
        }
            
        case APM::UpdateDatabases:
        {
            updateDatabases();
            break;
        }
        
        case APM::UpdateSystem:           
        {
            updateSystem();
            break;
        }
        
        case APM::Install:
        {            
            connect(backend, SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(install(QUuid,QList<Akabei::Package*>)));
Lisa's avatar
Lisa committed
102
            queryId = backend->searchPackages(m_args, Akabei::SearchNameEqual);
Lisa's avatar
Lisa committed
103 104 105 106 107 108 109 110 111
            break;
        }
        
        default:
        {
            err << i18n("akabei: Operation not supported yet.") << endl;
            QCoreApplication::instance()->quit();
            return;
        }
112 113 114
    }
}

115 116 117 118 119
void SyncOperation::updateDatabases()
{
    QTextStream out(stdout);
    out << i18n("Starting database update") << endl;

Lisa's avatar
Lisa committed
120
    foreach (AkabeiClient::DatabaseHandler* db, AkabeiClient::Backend::instance()->databases()) {
121 122 123 124 125 126 127 128 129 130
        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
131
    foreach (Akabei::Package *p, Akabei::Backend::instance()->localDatabase()->packages()) {
132 133
        locals << p->name();
    }
Lisa's avatar
Lisa committed
134 135
    
    connect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), SLOT(upgrade(QUuid,QList<Akabei::Package*>)));
136 137 138
    queryId = Akabei::Backend::instance()->searchPackages(locals, Akabei::SearchNameEqual);
}

Lukas Appelhans's avatar
Lukas Appelhans committed
139
void SyncOperation::upgrade(QUuid uuid, QList< Akabei::Package* > packages)
140
{
Lisa's avatar
Lisa committed
141
    if (packages.isEmpty() || queryId != uuid) {
Lukas Appelhans's avatar
Lukas Appelhans committed
142
        return;
Lisa's avatar
Lisa committed
143
    }
Lisa's avatar
Lisa committed
144
    
Lisa's avatar
Lisa committed
145
    QHash<QString, QList<Akabei::Package*> > mappedpkgs;
Lisa's avatar
Lisa committed
146
    foreach (Akabei::Package * pkg, packages) {
Lisa's avatar
Lisa committed
147
        mappedpkgs[pkg->name()].append(pkg);
148
    }
Lisa's avatar
Lisa committed
149
    
150
    QList<Akabei::Package*> toBeUpgraded;
Lisa's avatar
Lisa committed
151
    foreach (const QString &pkg, mappedpkgs.keys()) {
Lisa's avatar
Lisa committed
152
        QList<Akabei::Package*> candidates = mappedpkgs[pkg];
Lisa's avatar
Lisa committed
153
        
154 155 156
        if (!candidates.isEmpty()) {
            QMap<Akabei::Package::Version, Akabei::Package*> versions;
            Akabei::Package * local = 0;
Lisa's avatar
Lisa committed
157 158
            
            foreach (Akabei::Package* p, candidates) {
Lisa's avatar
Lisa committed
159
                if (p->database() == Akabei::Backend::instance()->localDatabase()) {
160
                    local = p;
Lisa's avatar
Lisa committed
161
                } else {
162
                    versions[p->version()] = p;
Lisa's avatar
Lisa committed
163
                }
164
            }
Lisa's avatar
Lisa committed
165
            
Lisa's avatar
Lisa committed
166 167
            /* Something is wrong */
            if (!local) {
168
                continue;
Lisa's avatar
Lisa committed
169
            }
Lisa's avatar
Lisa committed
170
           
171
            if (!versions.isEmpty() && versions.values().last()->version() > local->version()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
172
                toBeUpgraded << versions.values().last();
173 174 175
            }
        }
    }
Lisa's avatar
Lisa committed
176
    
Lukas Appelhans's avatar
Lukas Appelhans committed
177 178 179
    if (toBeUpgraded.isEmpty()) {
        return;
    }
Lisa's avatar
Lisa committed
180
    
Lisa's avatar
Lisa committed
181
    QueueOperation *op = new QueueOperation(APM::UpdateSystem, m_options, this);
182
    op->start(AkabeiClient::Update, toBeUpgraded);
Lisa's avatar
Lisa committed
183
    connect(op, SIGNAL(finished()), QCoreApplication::instance(), SLOT(nextOperation()));
184 185
}

Lukas Appelhans's avatar
Lukas Appelhans committed
186
void SyncOperation::install(QUuid uuid, QList< Akabei::Package* > packages)
187
{
Lisa's avatar
Lisa committed
188
    if (queryId != uuid) {
Lukas Appelhans's avatar
Lukas Appelhans committed
189
        return;
Lisa's avatar
Lisa committed
190
    }
Lisa's avatar
Lisa committed
191 192 193
   
    disconnect(Akabei::Backend::instance(), SIGNAL(queryPackagesCompleted(QUuid,QList<Akabei::Package*>)), this, SLOT(install(QUuid,QList<Akabei::Package*>)));
    
Lukas Appelhans's avatar
Lukas Appelhans committed
194
    //FIXME: Cleanup and show all the packages and what is going to be done with them!
195
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
196
    QTextStream err(stderr);
Lisa's avatar
Lisa committed
197
    
198
    QMap<QString, Akabei::Package*> toBeInstalled;
199 200
    QMap<QString, Akabei::Package*> toBeUpgraded;
    QMap<QString, Akabei::Package*> toBeReinstalled;
201
    QMap<QString, Akabei::Package*> local;
Lisa's avatar
Lisa committed
202 203
    
    foreach (Akabei::Package * pkg, packages) {
204
        qDebug() << "Found" << pkg->name();
205
        if (pkg->database() == Akabei::Backend::instance()->localDatabase()) {
206
            qDebug() << "Local";
207
            local[pkg->name()] = pkg;
208 209 210
            packages.removeAll(pkg);
        }
    }
Lisa's avatar
Lisa committed
211
    
212
    if (packages.isEmpty()) {
Lisa's avatar
Lisa committed
213 214
        err << i18n("No appropriate packages found") << endl;
        err.flush();
215
        return;
216
    }
Lisa's avatar
Lisa committed
217 218
    
    foreach (Akabei::Package * pkg, packages) {
219 220 221 222 223 224 225 226 227 228 229 230
        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
231
            }
232 233
        } else {
            toBeInstalled[pkg->name()] = pkg;
234
        }
Lisa's avatar
Lisa committed
235

236
    }
Lisa's avatar
Lisa committed
237

238 239 240 241
    if (toBeInstalled.isEmpty() && toBeUpgraded.isEmpty() && toBeReinstalled.isEmpty()) {
        out << i18n("No appropriate packages found") << endl;
        out.flush();
        QCoreApplication::instance()->quit();
242
        return;
243
    }
Lisa's avatar
Lisa committed
244
    
245 246 247
    if (!toBeReinstalled.isEmpty() || !toBeUpgraded.isEmpty()) {
        Akabei::Package::List pkgs = toBeReinstalled.values();
        pkgs << toBeUpgraded.values();
Lisa's avatar
Lisa committed
248
        
249 250 251 252
        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
253
            
254 255 256 257 258 259 260
            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
261
            
262 263
            if (!toBeUpgraded.isEmpty()) {
                out << i18n("The following packages are going to be upgraded:");
Lisa's avatar
Lisa committed
264 265
                
                foreach (Akabei::Package * p, toBeUpgraded.values()) {
266 267 268 269 270 271 272
                    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
273
            
274 275
            if (!toBeReinstalled.isEmpty()) {
                out << i18n("The following packages are going to be reinstalled:");
Lisa's avatar
Lisa committed
276 277
                
                foreach (Akabei::Package * p, toBeReinstalled.values()) {
278 279 280 281 282 283 284 285 286 287
                    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();
288 289 290

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

Lisa's avatar
Lisa committed
297
    QueueOperation *op = new QueueOperation(APM::Install, m_options, this);
298
    op->start(AkabeiClient::Install, toBeInstalled.values() + toBeUpgraded.values() + toBeReinstalled.values());
Lisa's avatar
Lisa committed
299
    connect(op, SIGNAL(finished()), QCoreApplication::instance(), SLOT(nextOperation()));
300 301
}

Lukas Appelhans's avatar
Lukas Appelhans committed
302 303
void SyncOperation::searchResult(QUuid , QList< Akabei::Package* > packages)
{
304 305
    if (packages.isEmpty()) {
        QCoreApplication::instance()->quit();
Lukas Appelhans's avatar
Lukas Appelhans committed
306
        return;
307
    }
Lisa's avatar
Lisa committed
308
    
Lukas Appelhans's avatar
Lukas Appelhans committed
309
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
310 311
    
    foreach (Akabei::Package * p, packages) {
Lukas Appelhans's avatar
Lukas Appelhans committed
312 313
        if (p->database() == Akabei::Backend::instance()->localDatabase())
            continue;
Lisa's avatar
Lisa committed
314
        
Lukas Appelhans's avatar
Lukas Appelhans committed
315
        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
316
        AkabeiClient::DatabaseHandler * db = 0;
Lisa's avatar
Lisa committed
317
        foreach (AkabeiClient::DatabaseHandler *database, AkabeiClient::Backend::instance()->databases()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
318 319 320 321 322
            if (database->database() == p->database()) {
                db = database;
                break;
            }
        }
Lisa's avatar
Lisa committed
323
        
Lukas Appelhans's avatar
Lukas Appelhans committed
324 325
        if (!db)
            continue;
Lisa's avatar
Lisa committed
326
        
Lukas Appelhans's avatar
Lukas Appelhans committed
327 328 329
        out << db->name() << '/' << p->name() << ' ' << p->version().toByteArray().data();
        if (installed)
            out << ' ' << i18n("[Installed]");
Lisa's avatar
Lisa committed
330
        
Lukas Appelhans's avatar
Lukas Appelhans committed
331 332 333
        out << endl;
        out << "    " << p->description() << endl;
    }
Lisa's avatar
Lisa committed
334
    
Lukas Appelhans's avatar
Lukas Appelhans committed
335
    out.flush();
Lisa's avatar
Lisa committed
336
    nextOperation();
Lukas Appelhans's avatar
Lukas Appelhans committed
337
}
Lukas Appelhans's avatar
Lukas Appelhans committed
338

Lukas Appelhans's avatar
Lukas Appelhans committed
339 340 341
void SyncOperation::listRepo(const QString &repo)
{
    AkabeiClient::DatabaseHandler * db = 0;
Lisa's avatar
Lisa committed
342
    foreach (AkabeiClient::DatabaseHandler * database, AkabeiClient::Backend::instance()->databases()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
343 344 345 346 347 348 349 350
        if (database->name() == repo) {
            db = database;
            break;
        }
    }
    if (!db)
        return;
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
351
    foreach (Akabei::Package * pkg, db->database()->packages()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
352 353 354 355 356 357 358 359 360 361 362
        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();
Lisa's avatar
Lisa committed
363
    nextOperation();
Lukas Appelhans's avatar
Lukas Appelhans committed
364 365
}

Lisa's avatar
Lisa committed
366
void SyncOperation::showInformation(QUuid,QList<Akabei::Package*> packages)
Lukas Appelhans's avatar
Lukas Appelhans committed
367
{
Lisa's avatar
Lisa committed
368
    if (packages.isEmpty()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
369
        return;
Lisa's avatar
Lisa committed
370
    }
Lisa's avatar
Lisa committed
371
    
Lisa's avatar
Lisa committed
372 373 374 375 376
    /*
     * 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
377
    foreach (Akabei::Package *p, packages) {
Lisa's avatar
Lisa committed
378 379 380
        mappedpkgs[p->name()] = p;
    }
    packages.clear();
Lisa's avatar
Lisa committed
381 382
    
    foreach (const QString& name, mappedpkgs.keys()) {
Lisa's avatar
Lisa committed
383
        if (mappedpkgs.count(name) > 1) {
Lisa's avatar
Lisa committed
384
            foreach (Akabei::Package *p, mappedpkgs.values(name)) {
Lisa's avatar
Lisa committed
385 386 387 388 389 390 391 392
                if (p->database() != Akabei::Backend::instance()->localDatabase()) {
                    packages << p;
                }
            }
        } else {
            packages << mappedpkgs[name];
        }
    }
Lisa's avatar
Lisa committed
393
    
Lukas Appelhans's avatar
Lukas Appelhans committed
394
    QTextStream out(stdout);
Lisa's avatar
Lisa committed
395
    
Lisa's avatar
Lisa committed
396
    /* TODO: discover how to disable these features: reset() doesn't work */
Lukas Appelhans's avatar
Lukas Appelhans committed
397 398
    out.setFieldWidth(30);
    out.setFieldAlignment(QTextStream::AlignLeft);
Lisa's avatar
Lisa committed
399
    
Lisa's avatar
Lisa committed
400
    /* Prints the information for every package */
Lisa's avatar
Lisa committed
401
    foreach (Akabei::Package *pkg, packages) {
Lisa's avatar
Lisa committed
402
        AkabeiClient::DatabaseHandler * db = 0;
Lisa's avatar
Lisa committed
403
        foreach (AkabeiClient::DatabaseHandler * database, AkabeiClient::Backend::instance()->databases()) {
Lisa's avatar
Lisa committed
404 405 406 407
            if (database->database() == pkg->database()) {
                db = database;
                break;
            }
Lukas Appelhans's avatar
Lukas Appelhans committed
408
        }
Lisa's avatar
Lisa committed
409
        
Lisa's avatar
Lisa committed
410 411 412 413 414
        if (db) {
            out << i18n("Repository") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << db->name() << endl;
        } else {
            kDebug() << pkg->database()->name();
        }
Lisa's avatar
Lisa committed
415
        
Lisa's avatar
Lisa committed
416
        out << i18n("Name") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << pkg->name() << endl;
417
        out << i18n("APM::Version") << qSetFieldWidth(2) << ":" << qSetFieldWidth(20) << QString(pkg->version().toByteArray().data()) << endl;
Lisa's avatar
Lisa committed
418 419 420
        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
421 422
        foreach (Akabei::Group * g, pkg->groups())
            groups << g->name();
Lisa's avatar
Lisa committed
423 424 425 426 427 428 429 430 431 432 433 434 435
        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
436
    }
Lisa's avatar
Lisa committed
437
    
Lisa's avatar
Lisa committed
438
    out.reset();
Lisa's avatar
Lisa committed
439
    nextOperation();
Lukas Appelhans's avatar
Lukas Appelhans committed
440 441
}

Lisa's avatar
Lisa committed
442
void SyncOperation::showGroup(QUuid uuid,QList<Akabei::Group*> groups)
Lukas Appelhans's avatar
Lukas Appelhans committed
443 444
{
    Q_UNUSED(uuid)
Lisa's avatar
Lisa committed
445
    
Lisa's avatar
Lisa committed
446
    if (groups.isEmpty()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
447
        return;
Lisa's avatar
Lisa committed
448
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
449
    Akabei::Group * group = groups.first();
Lisa's avatar
Lisa committed
450
    
Lukas Appelhans's avatar
Lukas Appelhans committed
451 452
    QTextStream out(stdout);
    QMap<QString, Akabei::Package*> sorted;
Lisa's avatar
Lisa committed
453 454
    
    foreach (Akabei::Package * pkg, group->packages()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
455
        sorted[pkg->name()] = pkg;
Lisa's avatar
Lisa committed
456
    }
Lisa's avatar
Lisa committed
457 458
    
    foreach (Akabei::Package * pkg, sorted.values()) {
Lukas Appelhans's avatar
Lukas Appelhans committed
459
        out << group->name() << ' ' << pkg->name() << endl;
Lisa's avatar
Lisa committed
460
    }
Lisa's avatar
Lisa committed
461
    
Lukas Appelhans's avatar
Lukas Appelhans committed
462
    out.flush();
Lisa's avatar
Lisa committed
463
    nextOperation();
Lukas Appelhans's avatar
Lukas Appelhans committed
464 465
}

466 467
void SyncOperation::updateNextDatabase()
{
Lukas Appelhans's avatar
Lukas Appelhans committed
468
    if (m_currentDatabasePos == AkabeiClient::Backend::instance()->databases().count()) {
469
        QTextStream out(stdout);
470
        out << i18n("Updating all databases finished") << endl;
Lisa's avatar
Lisa committed
471
        nextOperation();
472 473
        return;
    }
Lukas Appelhans's avatar
Lukas Appelhans committed
474
    AkabeiClient::DatabaseHandler* db = AkabeiClient::Backend::instance()->databases().at(m_currentDatabasePos);
475 476 477
    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)));
478
    db->update(m_options.contains(APM::Force));
479 480
}

Lukas Appelhans's avatar
Lukas Appelhans committed
481 482
void SyncOperation::databaseErrorTriggered(int error)
{
483
    Q_UNUSED(error)
Lisa's avatar
Lisa committed
484
    QTextStream err(stderr);
Lukas Appelhans's avatar
Lukas Appelhans committed
485
    //FIXME: Show proper error message
Lisa's avatar
Lisa committed
486
    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
487 488 489 490 491
}

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

void SyncOperation::databaseStatusChanged(AkabeiClient::DatabaseHandler::Status status)
{
Lisa's avatar
Lisa committed
513 514 515
    if (status != AkabeiClient::DatabaseHandler::StatusFinished && 
        status != AkabeiClient::DatabaseHandler::StatusUpToDate && 
        status != AkabeiClient::DatabaseHandler::StatusError) {
516
        return;
Lisa's avatar
Lisa committed
517
    }
Lisa's avatar
Lisa committed
518
    
Lukas Appelhans's avatar
Lukas Appelhans committed
519
    AkabeiClient::DatabaseHandler* db = AkabeiClient::Backend::instance()->databases().at(m_currentDatabasePos);
520 521 522
    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
523
    
524 525 526
    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
527 528
    } else if (status == AkabeiClient::DatabaseHandler::StatusError) {
        out << i18n("%1 could not be updated!", db->name()) << endl;
529 530 531
    } else {
        out << i18n("%1 updated!", db->name()) << endl;
    }
532

Lukas Appelhans's avatar
Lukas Appelhans committed
533
    m_currentDatabasePos++;
534
    updateNextDatabase();
Lukas Appelhans's avatar
Lukas Appelhans committed
535
}
Lisa's avatar
Lisa committed
536 537 538 539 540 541 542 543 544

void SyncOperation::nextOperation()
{
    if (m_operations.isEmpty()) {
        QCoreApplication::instance()->quit();
        return;
    }
    start();
}