akabeipackage.cpp 14 KB
Newer Older
Dario Freddi's avatar
Dario Freddi committed
1 2 3 4 5 6 7 8 9 10
/* 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.
*/

11
#include "akabeipackage_p.h"
12

13
#include "akabeiconfig.h"
14 15
#include "akabeihelpers_p.h"
#include "akabeidatabase_p.h"
16 17

#include <QtCore/QFile>
18
#include <QtCore/QDir>
19
#include <QtCore/QDebug>
Dario Freddi's avatar
Dario Freddi committed
20

21
#include <sqlite3.h>
22
#include <archive_entry.h>
23

24 25
namespace Akabei {

Dario Freddi's avatar
Dario Freddi committed
26 27 28
class Package::Version::Private
{
    public:
29 30 31
        Private() {}

        QBasicAtomicInt ref;
Dario Freddi's avatar
Dario Freddi committed
32 33 34
        QString repr;
};

35 36 37 38
void PackagePrivate::attemptLoadFromCache()
{
    if (QFile::exists(Config::instance()->cacheDir().absoluteFilePath(filename))) {
        // It does!
39 40 41
        pathToArchive = Config::instance()->cacheDir().absoluteFilePath(filename);
        _p_validated = false;
        _p_md5checked = false;
42 43 44
    }
}

Dario Freddi's avatar
Dario Freddi committed
45 46 47 48 49 50
Package::Version::Version()
    : d(new Private)
{
    d->ref = 1;
}

Dario Freddi's avatar
Dario Freddi committed
51 52 53
Package::Version::Version(const QString& version)
    : d(new Private)
{
54
    d->ref = 1;
Dario Freddi's avatar
Dario Freddi committed
55
    d->repr = version;
Dario Freddi's avatar
Dario Freddi committed
56 57 58 59
}

Package::Version::~Version()
{
60 61 62
    if (!d->ref.deref()) {
        delete d;
    }
Dario Freddi's avatar
Dario Freddi committed
63 64
}

Dario Freddi's avatar
Dario Freddi committed
65 66 67 68 69
bool Package::Version::isValid() const
{
    return !d->repr.isEmpty();
}

Dario Freddi's avatar
Dario Freddi committed
70 71
QString Package::Version::toString() const
{
72 73
    d->ref.ref();
    return QString(d->repr);
Dario Freddi's avatar
Dario Freddi committed
74 75
}

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
bool Package::Version::respectsConstraint(const QString& cV) const
{
    // Check what kind of constraint is this
    if (cV.startsWith('<')) {
        // Is it <=?
        if (cV.startsWith("<=")) {
            return *this <= cV.split("<=").last();
        } else {
            return *this < cV.split('<').last();
        }
    } else if (cV.startsWith('>')) {
        // Is it <=?
        if (cV.startsWith(">=")) {
            return *this >= cV.split(">=").last();
        } else {
            return *this > cV.split('>').last();
        }
    } else {
        // The version must be the same
        return *this == cV;
    }
Dario Freddi's avatar
Dario Freddi committed
97 98 99 100 101 102 103
}
bool Package::Version::respectsConstraint(const QString& version, const QString& cV)
{
    // Check what kind of constraint is this
    if (cV.startsWith('<')) {
        // Is it <=?
        if (cV.startsWith("<=")) {
104
            return Helpers::compare_versions(version.toUtf8().data(), cV.split("<=").last().toUtf8().data()) <= 0;
Dario Freddi's avatar
Dario Freddi committed
105
        } else {
106
            return Helpers::compare_versions(version.toUtf8().data(), cV.split('<').last().toUtf8().data()) < 0;
Dario Freddi's avatar
Dario Freddi committed
107 108 109 110
        }
    } else if (cV.startsWith('>')) {
        // Is it <=?
        if (cV.startsWith(">=")) {
111
            return Helpers::compare_versions(version.toUtf8().data(), cV.split(">=").last().toUtf8().data()) >= 0;
Dario Freddi's avatar
Dario Freddi committed
112
        } else {
113
            return Helpers::compare_versions(version.toUtf8().data(), cV.split('>').last().toUtf8().data()) > 0;
Dario Freddi's avatar
Dario Freddi committed
114 115 116
        }
    } else {
        // The version must be the same
117
        return Helpers::compare_versions(version.toUtf8().data(), cV.split('=').last().toUtf8().data()) == 0;
Dario Freddi's avatar
Dario Freddi committed
118
    }
119 120
}

Dario Freddi's avatar
Dario Freddi committed
121 122
bool Package::Version::operator!=(const Akabei::Package::Version& other) const
{
123
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toString().toUtf8().data()) != 0;
Dario Freddi's avatar
Dario Freddi committed
124 125 126 127
}

bool Package::Version::operator<(const Akabei::Package::Version& other) const
{
128
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toString().toUtf8().data()) < 0;
Dario Freddi's avatar
Dario Freddi committed
129 130 131 132
}

bool Package::Version::operator<=(const Akabei::Package::Version& other) const
{
133
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toString().toUtf8().data()) <= 0;
Dario Freddi's avatar
Dario Freddi committed
134 135 136 137
}

bool Package::Version::operator==(const Akabei::Package::Version& other) const
{
138
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toString().toUtf8().data()) == 0;
Dario Freddi's avatar
Dario Freddi committed
139 140 141 142
}

bool Package::Version::operator>(const Akabei::Package::Version& other) const
{
143
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toString().toUtf8().data()) > 0;
Dario Freddi's avatar
Dario Freddi committed
144 145 146 147
}

bool Package::Version::operator>=(const Akabei::Package::Version& other) const
{
148
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toString().toUtf8().data()) >= 0;
Dario Freddi's avatar
Dario Freddi committed
149 150
}

151 152 153
Package::Version& Package::Version::operator=(const QString& other)
{
    d->repr = other;
154
    return *this;
155 156 157 158
}

bool Package::Version::operator!=(const QString& other) const
{
159
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) != 0;
160 161 162 163
}

bool Package::Version::operator<(const QString& other) const
{
164
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) < 0;
165 166 167 168
}

bool Package::Version::operator<=(const QString& other) const
{
169
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) <= 0;
170 171 172 173
}

bool Package::Version::operator==(const QString& other) const
{
174
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) == 0;
175 176 177 178
}

bool Package::Version::operator>(const QString& other) const
{
179
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) > 0;
180 181 182 183
}

bool Package::Version::operator>=(const QString& other) const
{
184
    return Helpers::compare_versions(d->repr.toUtf8().data(), other.toUtf8().data()) >= 0;
185 186
}

Dario Freddi's avatar
Dario Freddi committed
187 188
////////////////////////////

189 190
Package::Package(Database *db, int databaseId, const QString &name)
    : d_ptr(new PackagePrivate(db, databaseId, name))
191 192 193
{
}

194 195 196 197 198
Package::Package()
    : d_ptr(new PackagePrivate(0, -1, ""))
{
}

199 200 201 202 203 204 205 206 207 208 209
Package::~Package()
{

}

QString Package::name() const
{
    Q_D(const Package);
    return d->name;
}

210 211 212 213 214 215 216 217 218 219 220 221
QString Package::arch() const
{
    Q_D(const Package);
    return d->arch;
}

QDateTime Package::buildDate() const
{
    Q_D(const Package);
    return d->buildDate;
}

222 223
QString Package::retrieveChangelog() const
{
224
    return QString();
225 226 227 228
}

QString Package::retrieveLoggedActions() const
{
229
    return QString();
230 231 232 233
}

QStringList Package::conflictsWith() const
{
234 235
    Q_D(const Package);
    return d->conflicts;
236 237 238
}

Package::List Package::computeDependencies()
239
{
240 241
    // TODO
    return Package::List();
242
    //d->
243 244 245 246
}

Package::List Package::computeRequiredBy()
{
247
    return Package::List();
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
}

Database* Package::database()
{
    Q_D(Package);
    return d->database;
}

int Package::databaseId() const
{
    Q_D(const Package);
    return d->databaseId;
}

QString Package::description() const
{
    Q_D(const Package);
    return d->desc;
}

QString Package::filename() const
{
    Q_D(const Package);
    return d->filename;
}

274
QStringList Package::retrieveFiles()
275
{
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    Q_D(Package);
    if (d->files.isEmpty()) {
        // We should cache the files here.
        if (d->database != 0 && d->databaseId >= 0) {
            // Ok, query the db
            // Add files
            QString sql = "SELECT * FROM files WHERE Package=" + QString::number(d->databaseId);
            sqlite3_stmt *statement = 0;
            int result = sqlite3_prepare16_v2(d->database->d_func()->dbHandle, sql.constData(), (sql.size() + 1) * sizeof(QChar),
                                              &statement, 0);
            switch (result) {
            case SQLITE_OK:
                // Everything went fine and the handle is ready
                break;
            default:
                break;
            }

            if (sqlite3_step(statement) == SQLITE_ROW) {
                // Add them
Dario Freddi's avatar
Dario Freddi committed
296
                d->files = Helpers::filesFromDb(statement);
297 298 299 300 301 302
            }

            sqlite3_finalize(statement);
        }
    }

303 304 305 306 307 308 309 310 311
    return d->files;
}

QList< Group* > Package::groups() const
{
    Q_D(const Package);
    return d->groups;
}

312
QStringList Package::retrieveHooks()
313
{
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    Q_D(Package);
    if (d->hooks.isEmpty() && d->hasHooks) {
        // We should cache the files here.
        if (d->database != 0 && d->databaseId >= 0) {
            // Ok, query the db
            // Add files
            QString sql = "SELECT * FROM hooks WHERE Packages LIKE \"%;" + QString::number(d->databaseId) + ";%\"";
            sqlite3_stmt *statement = 0;
            int result = sqlite3_prepare16_v2(d->database->d_func()->dbHandle, sql.constData(), (sql.size() + 1) * sizeof(QChar),
                                              &statement, 0);
            switch (result) {
            case SQLITE_OK:
                // Everything went fine and the handle is ready
                break;
            default:
                break;
            }

            while (sqlite3_step(statement) == SQLITE_ROW) {
                // Add them
                d->hooks << QSTRING_FROM_DB(statement, 1);
            }

            sqlite3_finalize(statement);
        }
    }

341
    return d->hooks;
342 343 344 345
}

bool Package::isValid() const
{
346 347
    Q_D(const Package);
    return d;
348 349
}

350
QByteArray Package::md5sum() const
351
{
352 353
    Q_D(const Package);
    return d->md5sum;
354 355 356 357
}

QStringList Package::mimetypes() const
{
358 359
    Q_D(const Package);
    return d->mimetypes;
360 361 362 363
}

QString Package::packager() const
{
364 365
    Q_D(const Package);
    return d->packager;
366 367 368 369
}

QString Package::pathToArchive() const
{
370
    Q_D(const Package);
371
    return d->pathToArchive;
372 373
}

Dario Freddi's avatar
Dario Freddi committed
374
QStringList Package::provides() const
375
{
376 377
    Q_D(const Package);
    return d->providers;
378 379 380 381
}

qint32 Package::size() const
{
382 383
    Q_D(const Package);
    return d->size;
384 385
}

386
QUrl Package::url() const
387
{
388 389
    Q_D(const Package);
    return d->url;
390 391
}

Dario Freddi's avatar
Dario Freddi committed
392
Package::Version Package::version() const
393
{
Dario Freddi's avatar
Dario Freddi committed
394 395
    Q_D(const Package);
    return d->version;
396 397
}

398
QStringList Package::dependencies() const
399
{
400 401 402
    Q_D(const Package);
    return d->deps;
}
403

404
QString Package::retrieveScriptlet()
405
{
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
    Q_D(Package);
    if (d->scriptlet.isEmpty() && d->hasScriptlet) {
        // We should cache the files here.
        if (d->database != 0 && d->databaseId >= 0) {
            // Ok, query the db
            // Add files
            QString sql = "SELECT * FROM scriptlets WHERE Package=" + QString::number(d->databaseId);
            sqlite3_stmt *statement = 0;
            int result = sqlite3_prepare16_v2(d->database->d_func()->dbHandle, sql.constData(), (sql.size() + 1) * sizeof(QChar),
                                              &statement, 0);
            switch (result) {
            case SQLITE_OK:
                // Everything went fine and the handle is ready
                break;
            default:
                break;
            }

            if (sqlite3_step(statement) == SQLITE_ROW) {
                // Add them
                d->scriptlet = QSTRING_FROM_DB(statement, 1);
            }

            sqlite3_finalize(statement);
        }
    }

433 434 435
    return d->scriptlet;
}

Dario Freddi's avatar
Dario Freddi committed
436 437 438 439 440 441 442 443 444 445
QList< Delta* > Package::retrieveDeltas()
{

}

QList< Delta* > Package::retrieveDeltaTo(const Akabei::Package::Version& version)
{

}

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
QDateTime Package::installDate() const
{
    Q_D(const Package);
    return d->installDate;
}

qint32 Package::installedSize() const
{
    Q_D(const Package);
    return d->isize;
}

Package::InstallReason Package::installReason()
{
    Q_D(const Package);
    return d->reason;
}

QUrl Package::screenshot() const
{
    Q_D(const Package);
    return d->screenshot;
}

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
QStringList Package::backupFiles() const
{
    Q_D(const Package);
    return d->backup;
}

QString Package::license() const
{
    Q_D(const Package);
    return d->license;
}

QStringList Package::optionalDependencies() const
{
    Q_D(const Package);
    return d->optdepends;
}

QStringList Package::replaces() const
{
    Q_D(const Package);
    return d->replaces;
}

494 495 496 497 498 499 500 501 502 503 504 505
bool Package::hasHooks() const
{
    Q_D(const Package);
    return d->hasHooks;
}

bool Package::hasScriptlet() const
{
    Q_D(const Package);
    return d->hasScriptlet;
}

506 507 508
void Package::setPathToArchive(const QString& path)
{
    Q_D(Package);
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
    d->pathToArchive = path;
}

bool Package::checkMD5Sum()
{
    Q_D(Package);

    if (d->_p_md5checked) {
        return true;
    }

    // Check integrity
    if (Helpers::md5sumOfFile(d->pathToArchive) != d->md5sum) {
        d->_p_md5checked = false;
    } else {
        d->_p_md5checked = true;
    }

    return d->_p_md5checked;
}

bool Package::checkArchiveValidity()
{
    Q_D(Package);

    if (d->_p_validated) {
        return true;
    }

    // Ok, now let's check that we are actually able to load the archive.
    struct archive *a;
    struct archive_entry *entry;
    int r;

    a = archive_read_new();
    archive_read_support_compression_all(a);
    archive_read_support_format_all(a);
    r = archive_read_open_filename(a, d->pathToArchive.toUtf8().data(), 10240); // Note 1
    if (r != ARCHIVE_OK) {
        // Utter fail.
        d->_p_validated = false;
        archive_read_finish(a);
        return false;
    }

    d->_p_validated = false;
    while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
        if (QString(archive_entry_pathname(entry)) == ".PKGINFO") {
            d->_p_validated = true;
        }
        archive_read_data_skip(a);  // Note 2
    }
    r = archive_read_finish(a);  // Note 3

    return d->_p_validated;
564 565
}

566 567 568 569 570 571
Package* Package::generateInstalledPackage(Package::InstallReason ireason, const QDateTime& idate)
{
    Q_D(Package);
    // Create a new package from this one
    Package *p = new Package(0, -1, name());
    p->d_func()->arch = d->arch;
572
    p->d_func()->pathToArchive = d->pathToArchive;
Dario Freddi's avatar
Dario Freddi committed
573
    p->d_func()->backup = d->backup;
574 575 576 577 578 579 580
    p->d_func()->buildDate = d->buildDate;
    p->d_func()->conflicts = d->conflicts;
    p->d_func()->deps = d->deps;
    p->d_func()->desc = d->desc;
    p->d_func()->filename = d->filename;
    p->d_func()->files = d->files;
    p->d_func()->groups = d->groups;
Dario Freddi's avatar
Dario Freddi committed
581 582
    p->d_func()->hasHooks = d->hasHooks;
    p->d_func()->hasScriptlet = d->hasScriptlet;
583 584 585
    p->d_func()->hooks = d->hooks;
    p->d_func()->installDate = idate;
    p->d_func()->isize = d->isize;
Dario Freddi's avatar
Dario Freddi committed
586
    p->d_func()->license = d->license;
587 588
    p->d_func()->md5sum = d->md5sum;
    p->d_func()->mimetypes = d->mimetypes;
Dario Freddi's avatar
Dario Freddi committed
589
    p->d_func()->optdepends = d->optdepends;
590 591 592
    p->d_func()->packager = d->packager;
    p->d_func()->providers = d->providers;
    p->d_func()->reason = ireason;
Dario Freddi's avatar
Dario Freddi committed
593
    p->d_func()->replaces = d->replaces;
594 595 596 597 598 599 600 601 602
    p->d_func()->screenshot = d->screenshot;
    p->d_func()->scriptlet = d->scriptlet;
    p->d_func()->size = d->size;
    p->d_func()->url = d->url;
    p->d_func()->version = d->version.toString();

    return p;
}

603
}