171 lines
5.5 KiB
C++
171 lines
5.5 KiB
C++
|
#include "mingwbundle.h"
|
||
|
#include "manager.h"
|
||
|
|
||
|
#include <c++utilities/conversion/stringconversion.h>
|
||
|
#include <c++utilities/misc/memory.h>
|
||
|
|
||
|
#include <KTar>
|
||
|
|
||
|
#include <QFile>
|
||
|
#include <QtConcurrent/QtConcurrent>
|
||
|
|
||
|
#include <string>
|
||
|
#include <iostream>
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
namespace PackageManagement {
|
||
|
|
||
|
const string prefix("mingw-w64-");
|
||
|
|
||
|
MingwBundle::MingwBundle(const Manager &manager, const ApplicationUtilities::StringVector &packages) :
|
||
|
m_manager(manager)
|
||
|
{
|
||
|
string missing;
|
||
|
for(const auto &pkgName : packages) {
|
||
|
bool found = false;
|
||
|
for(const auto &syncDb : manager.syncDataBases()) {
|
||
|
if(auto pkg = syncDb.second.package(ConversionUtilities::startsWith(pkgName, prefix) ? pkgName.data() : (prefix + pkgName).data())) {
|
||
|
if(missing.empty()) {
|
||
|
m_packages.emplace_back(syncDb.second, pkg);
|
||
|
}
|
||
|
addDependencies(pkg);
|
||
|
found = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(!found) {
|
||
|
missing.push_back(' ');
|
||
|
missing.append(pkgName);
|
||
|
}
|
||
|
}
|
||
|
if(!missing.empty()) {
|
||
|
throw runtime_error("The following packages can not be found:" + missing);
|
||
|
} else {
|
||
|
cerr << "Adding the following packages:";
|
||
|
for(const auto &pkg : m_packages) {
|
||
|
cerr << ' ' << pkg.second.name();
|
||
|
}
|
||
|
cerr << endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enum class RelevantFileType
|
||
|
{
|
||
|
Binary,
|
||
|
Translation
|
||
|
};
|
||
|
|
||
|
enum class RelevantFileArch
|
||
|
{
|
||
|
x86_64,
|
||
|
i686
|
||
|
};
|
||
|
|
||
|
struct RelevantFile
|
||
|
{
|
||
|
RelevantFile(const KArchiveFile *file, const RelevantFileType type, const RelevantFileArch arch) :
|
||
|
file(file),
|
||
|
fileType(type),
|
||
|
arch(arch)
|
||
|
{}
|
||
|
const KArchiveFile *file;
|
||
|
RelevantFileType fileType;
|
||
|
RelevantFileArch arch;
|
||
|
};
|
||
|
|
||
|
struct PkgFileInfo
|
||
|
{
|
||
|
PkgFileInfo(const QString &path) : path(path), failure(false) {}
|
||
|
QString path;
|
||
|
unique_ptr<KTar> archive;
|
||
|
list<RelevantFile> relevantFiles;
|
||
|
bool failure;
|
||
|
};
|
||
|
|
||
|
void getFiles(PkgFileInfo &pkgFileInfo)
|
||
|
{
|
||
|
pkgFileInfo.archive = make_unique<KTar>(pkgFileInfo.path);
|
||
|
if(pkgFileInfo.archive->open(QIODevice::ReadOnly)) {
|
||
|
static const pair<RelevantFileArch, QString> roots[] = {
|
||
|
make_pair(RelevantFileArch::x86_64, QStringLiteral("/usr/x86_64-w64-mingw32")),
|
||
|
make_pair(RelevantFileArch::i686, QStringLiteral("/usr/i686-w64-mingw32"))
|
||
|
};
|
||
|
for(const auto &root : roots) {
|
||
|
const auto *rootEntry = pkgFileInfo.archive->directory()->entry(root.second);
|
||
|
if(rootEntry && rootEntry->isDirectory()) {
|
||
|
const auto *rootDir = static_cast<const KArchiveDirectory *>(rootEntry);
|
||
|
const auto *binEntry = rootDir->entry(QStringLiteral("bin"));
|
||
|
if(binEntry && binEntry->isDirectory()) {
|
||
|
const auto *binDir = static_cast<const KArchiveDirectory *>(binEntry);
|
||
|
for(const auto &entryName : binDir->entries()) {
|
||
|
if(entryName.endsWith(QLatin1String(".exe")) || entryName.endsWith(QLatin1String(".dll"))) {
|
||
|
if(const auto *entry = binDir->entry(entryName)) {
|
||
|
if(entry->isFile()) {
|
||
|
const auto *binFile = static_cast<const KArchiveFile *>(entry);
|
||
|
pkgFileInfo.relevantFiles.emplace_back(binFile, RelevantFileType::Binary, root.first);
|
||
|
cerr << entryName.toLocal8Bit().data() << endl;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
pkgFileInfo.failure = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void MingwBundle::createBundle(const string &path) const
|
||
|
{
|
||
|
list<PkgFileInfo> pkgFiles;
|
||
|
for(const auto &entry : m_packages) {
|
||
|
QString pkgFile;
|
||
|
if(!entry.first.packagesDirectory().isEmpty()) {
|
||
|
pkgFile = QStringLiteral("%1/%2").arg(entry.first.packagesDirectory(), QString::fromLocal8Bit(entry.second.fileName()));
|
||
|
}
|
||
|
if(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
|
||
|
if(!m_manager.pacmanCacheDir().isEmpty()) {
|
||
|
pkgFile = QStringLiteral("%1/%2").arg(m_manager.pacmanCacheDir(), QString::fromLocal8Bit(entry.second.fileName()));
|
||
|
}
|
||
|
if(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
|
||
|
throw runtime_error("The package file " + string(entry.second.fileName()) + " can't be found.");
|
||
|
// TODO: download package from mirror
|
||
|
}
|
||
|
}
|
||
|
pkgFiles.emplace_back(pkgFile);
|
||
|
}
|
||
|
QtConcurrent::blockingMap(pkgFiles, getFiles);
|
||
|
}
|
||
|
|
||
|
void MingwBundle::addDependencies(const AlpmPackage &pkg)
|
||
|
{
|
||
|
string missing;
|
||
|
for(const auto &depInfo : pkg.dependencies()) {
|
||
|
bool found = false;
|
||
|
for(const auto &syncDb : m_manager.syncDataBases()) {
|
||
|
if(auto pkg = syncDb.second.package(depInfo->name)) {
|
||
|
if(missing.empty()) {
|
||
|
m_packages.emplace_back(syncDb.second, pkg);
|
||
|
}
|
||
|
addDependencies(pkg);
|
||
|
found = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(!found) {
|
||
|
missing.push_back(' ');
|
||
|
missing.append(depInfo->name);
|
||
|
}
|
||
|
}
|
||
|
if(!missing.empty()) {
|
||
|
throw runtime_error("The following dependencies of the " + string(pkg.name()) + " package can not be resolved:" + missing);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace PackageManagement
|
||
|
|