repoindex/alpm/alpmdatabase.cpp

187 lines
6.4 KiB
C++

#include "./alpmdatabase.h"
#include "./upgradelookup.h"
#include "./alpmpackage.h"
#include "./utilities.h"
#include <c++utilities/misc/memory.h>
#include <KTar>
#include <KArchiveDirectory>
#include <QList>
#include <QJsonObject>
#include <QtConcurrent>
#include <iostream>
using namespace std;
namespace RepoIndex {
using namespace Utilities;
/*!
* \class AlpmDatabase
* \brief The AlpmDatabase class wraps an ALPM data base struct and holds additional meta information.
*
* All packages returned by the AlpmDatabase class are AlpmPackage instances.
*/
class LoadPackage
{
public:
LoadPackage(AlpmDatabase *database, PackageOrigin origin) :
m_db(database),
m_origin(origin)
{}
void operator()(const QPair<QString, QList<QByteArray> > &description)
{
m_db->addPackageFromDescription(description.first, description.second, m_origin);
}
private:
AlpmDatabase *const m_db;
const PackageOrigin m_origin;
};
void AlpmDatabase::loadDescriptions(QList<QPair<QString, QList<QByteArray> > > &descriptions)
{
QFileInfo pathInfo(databasePath());
if(pathInfo.isDir()) {
static const QStringList relevantFiles = QStringList() << QStringLiteral("desc") << QStringLiteral("files");
QDir dbDir(databasePath());
QStringList pkgDirNames = dbDir.entryList(QDir::Dirs | QDir::Readable | QDir::Executable | QDir::NoDotAndDotDot);
descriptions.reserve(pkgDirNames.size());
for(QString &pkgDirName : pkgDirNames) {
if(dbDir.cd(pkgDirName)) {
Utilities::stripVersion(pkgDirName);
const QStringList descFileNames = dbDir.entryList(relevantFiles, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);
QList<QByteArray> descData;
descData.reserve(descFileNames.size());
for(const QString &descFileName : descFileNames) {
QFile descFile(dbDir.absoluteFilePath(descFileName));
if(descFile.open(QFile::ReadOnly)) {
descData << descFile.readAll();
} else {
// TODO: error handling (can't open pkg file)
}
}
if(!descData.isEmpty()) {
descriptions << qMakePair(pkgDirName, descData);
}
dbDir.cdUp();
} else {
// TODO: error handling (can't enter pkg dir)
}
}
} else if(pathInfo.isFile()) {
KTar tar(databasePath());
const KArchiveDirectory *dbDir;
if(tar.open(QIODevice::ReadOnly) && (dbDir = tar.directory())) {
QStringList pkgDirNames = dbDir->entries();
descriptions.reserve(pkgDirNames.size());
for(QString &pkgDirName : pkgDirNames) {
if(const auto *pkgEntry = dbDir->entry(pkgDirName)) {
if(pkgEntry->isDirectory()) {
Utilities::stripVersion(pkgDirName);
const auto *pkgDir = static_cast<const KArchiveDirectory *>(pkgEntry);
const QStringList descFileNames = pkgDir->entries();
QList<QByteArray> descData;
descData.reserve(descFileNames.size());
for(const QString &descFileName : descFileNames) {
if(const auto *descEntry = pkgDir->entry(descFileName)) {
if(descEntry->isFile()) {
descData << static_cast<const KArchiveFile *>(descEntry)->data();
} else {
// there shouldn't be any subdirs
}
}
}
if(!descData.isEmpty()) {
descriptions << qMakePair(pkgDirName, descData);
}
} else {
// there shouldn't be any files
}
}
}
} else {
// TODO: error handling (can't open sync db file)
}
} else {
// TODO: error handling
}
}
AlpmPackageLoader::AlpmPackageLoader(AlpmDatabase *repository, PackageOrigin origin)
{
repository->loadDescriptions(m_descriptions);
m_future = QtConcurrent::map(m_descriptions, LoadPackage(repository, origin));
}
/*!
* \brief Creates a new instance wrapping the specified database struct.
*/
AlpmDatabase::AlpmDatabase(const QString &name, const QString &dbPath, RepositoryUsage usage, SignatureLevel sigLevel, uint32 index, QObject *parent) :
Repository(name, index, parent),
m_dbPath(dbPath)
{
m_usage = usage;
m_sigLevel = sigLevel;
}
AlpmPackageLoader *AlpmDatabase::init()
{
// set description, determine origin
PackageOrigin origin;
if(m_name.compare(QLatin1String("local"), Qt::CaseInsensitive) == 0) {
m_description = QStringLiteral("The local database");
origin = PackageOrigin::LocalDb;
} else {
if((m_usage & RepositoryUsage::Sync) || (m_usage & RepositoryUsage::Install) || (m_usage & RepositoryUsage::Upgrade)) {
m_description = QStringLiteral("Sync database »%1«").arg(m_name);
} else {
m_description = QStringLiteral("Database »%1«").arg(m_name);
}
origin = PackageOrigin::SyncDb;
}
// initialization of packages is done concurrently via AlpmPackageLoader: ~ 4 sec
return new AlpmPackageLoader(this, origin);
// without concurrency: ~ 12 sec
//QList<QPair<QString, QList<QByteArray> > > descriptions;
//loadDescriptions(descriptions);
//for(const auto &description : descriptions) {
// addPackageFromDescription(description.first, description.second, origin);
//}
//return nullptr;
}
RepositoryType AlpmDatabase::type() const
{
return RepositoryType::AlpmDatabase;
}
PackageDetailAvailability AlpmDatabase::requestsRequired(PackageDetail packageDetail) const
{
switch(packageDetail) {
case PackageDetail::Basics:
case PackageDetail::Dependencies:
case PackageDetail::PackageInfo:
case PackageDetail::AllAvailable:
return PackageDetailAvailability::Immediately;
default:
return PackageDetailAvailability::Never;
}
}
std::unique_ptr<Package> AlpmDatabase::emptyPackage()
{
return make_unique<AlpmPackage>(this);
}
} // namespace Alpm