562 lines
28 KiB
C++
562 lines
28 KiB
C++
#include "./mingwbundle.h"
|
|
#include "./utilities.h"
|
|
#include "./manager.h"
|
|
#include "./config.h"
|
|
|
|
#include <c++utilities/conversion/stringconversion.h>
|
|
#include <c++utilities/misc/memory.h>
|
|
|
|
#include <KTar>
|
|
#include <K7Zip>
|
|
#include <KZip>
|
|
|
|
#include <QtConcurrent/QtConcurrent>
|
|
#include <QStringBuilder>
|
|
#include <QJsonDocument>
|
|
#include <QJsonArray>
|
|
#include <QFile>
|
|
|
|
#include <string>
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
|
|
namespace RepoIndex {
|
|
|
|
using namespace Utilities;
|
|
|
|
const string prefix("mingw-w64-");
|
|
|
|
MingwBundle::MingwBundle(Manager &manager, const ApplicationUtilities::StringVector &packages, const ApplicationUtilities::StringVector &iconPackages, const ApplicationUtilities::StringVector &extraPackages) :
|
|
m_manager(manager),
|
|
m_extraPackages(extraPackages)
|
|
{
|
|
cerr << shchar << "Resolving dependencies ..." << endl;
|
|
string missing;
|
|
// add mingw-w64 packages
|
|
for(const auto &pkgName : packages) {
|
|
if(auto *pkg = manager.packageProviding(Dependency(QString::fromLocal8Bit(ConversionUtilities::startsWith(pkgName, prefix) ? pkgName.data() : (prefix + pkgName).data())))) {
|
|
if(find(m_packages.cbegin(), m_packages.cend(), pkg) == m_packages.cend()) {
|
|
m_packages.emplace_back(pkg);
|
|
addDependencies(pkg);
|
|
}
|
|
} else {
|
|
missing.push_back(' ');
|
|
missing.append(pkgName);
|
|
}
|
|
}
|
|
// add additional icon packages
|
|
for(const auto &pkgName : iconPackages) {
|
|
if(auto *pkg = manager.packageProviding(Dependency(QString::fromLocal8Bit(pkgName.data())))) {
|
|
if(find(m_packages.cbegin(), m_packages.cend(), pkg) == m_packages.cend()) {
|
|
m_packages.emplace_back(pkg);
|
|
}
|
|
} else {
|
|
missing.push_back(' ');
|
|
missing.append(pkgName);
|
|
}
|
|
}
|
|
if(!missing.empty()) {
|
|
throw runtime_error("The following packages can not be found:" + missing);
|
|
} else {
|
|
cerr << shchar << "Adding the following packages:";
|
|
for(const auto *pkg : m_packages) {
|
|
cerr << shchar << ' ' << pkg->name().toLocal8Bit().data();
|
|
}
|
|
cerr << shchar << endl;
|
|
}
|
|
}
|
|
|
|
void MingwBundle::addDependencies(const Package *pkg)
|
|
{
|
|
string missing;
|
|
for(const auto &dep : pkg->dependencies()) {
|
|
if(dep.name.startsWith(QLatin1String("mingw-w64-"), Qt::CaseInsensitive)) {
|
|
if(auto *pkg = m_manager.packageProviding(dep)) {
|
|
if(find(m_packages.cbegin(), m_packages.cend(), pkg) == m_packages.cend()) {
|
|
m_packages.emplace_back(pkg);
|
|
addDependencies(pkg);
|
|
}
|
|
} else {
|
|
missing.push_back(' ');
|
|
missing.append(dep.name.toLocal8Bit());
|
|
}
|
|
}
|
|
}
|
|
if(!missing.empty()) {
|
|
throw runtime_error("The following dependencies of the " + string(pkg->name().toLocal8Bit().data()) + " package can not be resolved:" + missing);
|
|
}
|
|
}
|
|
|
|
enum class RelevantFileType
|
|
{
|
|
Binary,
|
|
Data,
|
|
Translation,
|
|
QtTranslation,
|
|
QtPlugin,
|
|
Plugin,
|
|
SharedData,
|
|
GLib2Data,
|
|
GLib2Schemas,
|
|
Theme,
|
|
IconTheme
|
|
};
|
|
|
|
enum class RelevantFileArch
|
|
{
|
|
x86_64,
|
|
i686,
|
|
Any
|
|
};
|
|
|
|
struct RelevantFile
|
|
{
|
|
RelevantFile(const KArchiveFile *file, const KArchiveDirectory *containingDir, const RelevantFileType type, const RelevantFileArch arch, const QString &subDir = QString()) :
|
|
name(file->name()),
|
|
fileType(type),
|
|
arch(arch),
|
|
subDir(subDir)
|
|
{
|
|
if(file->symLinkTarget().isEmpty()) {
|
|
data = file->data();
|
|
} else if(const auto *targetEntry = containingDir->entry(file->symLinkTarget())) {
|
|
// Windows support for symlinks is not very well
|
|
if(targetEntry->isFile()) {
|
|
data = static_cast<const KArchiveFile *>(targetEntry)->data();
|
|
}
|
|
}
|
|
}
|
|
|
|
QString name;
|
|
QByteArray data;
|
|
RelevantFileType fileType;
|
|
RelevantFileArch arch;
|
|
QString subDir;
|
|
};
|
|
|
|
struct PkgFileInfo
|
|
{
|
|
PkgFileInfo(const QString &name, const QString &path) :
|
|
name(name),
|
|
path(path),
|
|
failure(false)
|
|
{}
|
|
|
|
QString name;
|
|
QString path;
|
|
unique_ptr<KTar> archive;
|
|
list<RelevantFile> relevantFiles;
|
|
bool failure;
|
|
};
|
|
|
|
void addEntries(PkgFileInfo &pkgFileInfo, RelevantFileType fileType, const KArchiveDirectory *dir, const QString &relPath = QString(), const QString &ext = QString(), RelevantFileArch relevantArch = RelevantFileArch::Any)
|
|
{
|
|
const QString newPath = relPath.isEmpty() ? dir->name() : relPath % QChar('/') % dir->name();
|
|
for(const auto &entryName : dir->entries()) {
|
|
if(auto *entry = dir->entry(entryName)) {
|
|
if(entry->isDirectory()) {
|
|
addEntries(pkgFileInfo, fileType, static_cast<const KArchiveDirectory *>(entry), newPath, ext, relevantArch);
|
|
} else if(entry->isFile()) {
|
|
if(ext.isEmpty() || entry->name().endsWith(ext)) {
|
|
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(entry), dir, fileType, relevantArch, newPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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"))
|
|
};
|
|
// add files for each architecture separately
|
|
for(const auto &root : roots) {
|
|
// get root entry
|
|
const auto *rootEntry = pkgFileInfo.archive->directory()->entry(root.second);
|
|
if(rootEntry && rootEntry->isDirectory()) {
|
|
const auto *rootDir = static_cast<const KArchiveDirectory *>(rootEntry);
|
|
|
|
// binary directory: *.exe and *.dll files required
|
|
const auto *binEntry = rootDir->entry(QStringLiteral("bin"));
|
|
if(binEntry && binEntry->isDirectory()) {
|
|
const auto *binDir = static_cast<const KArchiveDirectory *>(binEntry);
|
|
for(const QString &entryName : binDir->entries()) {
|
|
if(entryName.endsWith(QLatin1String(".exe")) || entryName.indexOf(QLatin1String(".dll")) > 0) {
|
|
if(const auto *entry = binDir->entry(entryName)) {
|
|
if(entry->isFile()) {
|
|
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(entry), binDir, RelevantFileType::Binary, root.first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// library directory: Qt, GTK and application specific libs/plugins required
|
|
const auto *libEntry = rootDir->entry(QStringLiteral("lib"));
|
|
if(libEntry && libEntry->isDirectory()) {
|
|
// Qt 5 plugins
|
|
const auto *libDir = static_cast<const KArchiveDirectory *>(libEntry);
|
|
const auto *qtEntry = libDir->entry("qt");
|
|
if(qtEntry && qtEntry->isDirectory()) {
|
|
const auto *qtDir = static_cast<const KArchiveDirectory *>(qtEntry);
|
|
const auto *pluginsEntry = qtDir->entry(QStringLiteral("plugins"));
|
|
if(pluginsEntry && pluginsEntry->isDirectory()) {
|
|
const auto *pluginsDir = static_cast<const KArchiveDirectory *>(pluginsEntry);
|
|
for(const auto &pluginCategory : pluginsDir->entries()) {
|
|
const auto *categoryEntry = pluginsDir->entry(pluginCategory);
|
|
if(categoryEntry && categoryEntry->isDirectory()) {
|
|
const auto *categoryDir = static_cast<const KArchiveDirectory *>(categoryEntry);
|
|
for(const auto &entryName : categoryDir->entries()) {
|
|
if(const auto *pluginEntry = categoryDir->entry(entryName)) {
|
|
if(pluginEntry->isFile()) {
|
|
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(pluginEntry), categoryDir, RelevantFileType::QtPlugin, root.first, categoryDir->name());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Qt 4 plugins
|
|
qtEntry = libDir->entry(QStringLiteral("qt4"));
|
|
if(qtEntry && qtEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::Plugin, static_cast<const KArchiveDirectory *>(qtEntry), QString(), QString(), root.first);
|
|
}
|
|
|
|
// GTK plugins
|
|
const auto *gtkEntry = libDir->entry(QStringLiteral("gtk-2.0"));
|
|
if(gtkEntry && gtkEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::Plugin, static_cast<const KArchiveDirectory *>(gtkEntry), QString(), QStringLiteral(".dll"), root.first);
|
|
}
|
|
gtkEntry = libDir->entry(QStringLiteral("gtk-3.0"));
|
|
if(gtkEntry && gtkEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::Plugin, static_cast<const KArchiveDirectory *>(gtkEntry), QString(), QStringLiteral(".dll"), root.first);
|
|
}
|
|
|
|
// app specific libs/plugins
|
|
const auto *evinceEntry = libDir->entry(pkgFileInfo.name);
|
|
if(evinceEntry && evinceEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::Plugin, static_cast<const KArchiveDirectory *>(evinceEntry), QString(), QStringLiteral(".dll"), root.first);
|
|
// required by evince
|
|
addEntries(pkgFileInfo, RelevantFileType::Plugin, static_cast<const KArchiveDirectory *>(evinceEntry), QString(), QStringLiteral(".evince-backend"), root.first);
|
|
}
|
|
}
|
|
|
|
// data directory: required by geany
|
|
const auto *dataEntry = rootDir->entry(QStringLiteral("data"));
|
|
if(dataEntry && dataEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::Data, static_cast<const KArchiveDirectory *>(dataEntry), QString(), QString(), root.first);
|
|
}
|
|
|
|
// share directory: translations, themes, icons, schemas
|
|
const auto *shareEntry = rootDir->entry(QStringLiteral("share"));
|
|
if(shareEntry && shareEntry->isDirectory()) {
|
|
const auto *shareDir = static_cast<const KArchiveDirectory *>(shareEntry);
|
|
|
|
// Qt translations
|
|
const auto *qtEntry = shareDir->entry(QStringLiteral("qt"));
|
|
if(qtEntry && qtEntry->isDirectory()) {
|
|
const auto *qtDir = static_cast<const KArchiveDirectory *>(qtEntry);
|
|
const auto *trEntry = qtDir->entry(QStringLiteral("translations"));
|
|
if(trEntry && trEntry->isDirectory()) {
|
|
const auto trDir = static_cast<const KArchiveDirectory *>(trEntry);
|
|
for(const auto &entryName : trDir->entries()) {
|
|
if(entryName.endsWith(QLatin1String(".qm"))) {
|
|
if(const auto *qmEntry = trDir->entry(entryName)) {
|
|
if(qmEntry->isFile()) {
|
|
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(qmEntry), trDir, RelevantFileType::QtTranslation, root.first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// GTK themes
|
|
const auto *themesEntry = shareDir->entry(QStringLiteral("themes"));
|
|
if(themesEntry && themesEntry->isDirectory()) {
|
|
const auto *themesDir = static_cast<const KArchiveDirectory *>(themesEntry);
|
|
for(const auto &themeName : themesDir->entries()) {
|
|
const auto *themeEntry = themesDir->entry(themeName);
|
|
if(themeEntry && themeEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::Theme, static_cast<const KArchiveDirectory *>(themeEntry), QString(), QString(), root.first);
|
|
}
|
|
}
|
|
}
|
|
|
|
// icon themes
|
|
const auto *iconsEntry = shareDir->entry(QStringLiteral("icons"));
|
|
if(iconsEntry && iconsEntry->isDirectory()) {
|
|
const auto *iconsDir = static_cast<const KArchiveDirectory *>(iconsEntry);
|
|
for(const auto &themeName : iconsDir->entries()) {
|
|
const auto *themeEntry = iconsDir->entry(themeName);
|
|
if(themeEntry && themeEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::IconTheme, static_cast<const KArchiveDirectory *>(themeEntry), QString(), QString(), root.first);
|
|
}
|
|
}
|
|
}
|
|
|
|
// glib2 stuff (need to compile glib2 schemes later)
|
|
const auto *glib2Entry = shareDir->entry(QStringLiteral("glib-2.0"));
|
|
if(glib2Entry && glib2Entry->isDirectory()) {
|
|
const auto *glib2Dir = static_cast<const KArchiveDirectory *>(glib2Entry);
|
|
for(const auto &glib2SubEntryName : glib2Dir->entries()) {
|
|
const auto *glib2SubEntry = glib2Dir->entry(glib2SubEntryName);
|
|
if(glib2SubEntry->isDirectory()) {
|
|
if(glib2SubEntry->name() == QLatin1String("schemas")) {
|
|
addEntries(pkgFileInfo, RelevantFileType::GLib2Schemas, static_cast<const KArchiveDirectory *>(glib2SubEntry), QStringLiteral("glib-2.0"), QString(), root.first);
|
|
} else {
|
|
addEntries(pkgFileInfo, RelevantFileType::GLib2Data, static_cast<const KArchiveDirectory *>(glib2SubEntry), QStringLiteral("glib-2.0"), QString(), root.first);
|
|
}
|
|
} else if(glib2SubEntry->isFile()) {
|
|
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(glib2SubEntry), glib2Dir, RelevantFileType::GLib2Data, root.first, QStringLiteral("glib-2.0"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// application specific stuff (Qt stuff is added separately, so skip Qt here)
|
|
if(pkgFileInfo.name.compare(QLatin1String("qt"))) {
|
|
const auto *appEntry = shareDir->entry(pkgFileInfo.name);
|
|
if(appEntry && appEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::SharedData, static_cast<const KArchiveDirectory *>(appEntry), QString(), QString(), root.first);
|
|
}
|
|
}
|
|
|
|
const auto *localeEntry = shareDir->entry(QStringLiteral("locale"));
|
|
if(localeEntry && localeEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::SharedData, static_cast<const KArchiveDirectory *>(localeEntry), QString(), QString(), root.first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// icons from regular package
|
|
const auto *iconsEntry = pkgFileInfo.archive->directory()->entry(QStringLiteral("usr/share/icons"));
|
|
if(iconsEntry && iconsEntry->isDirectory()) {
|
|
const auto *iconsDir = static_cast<const KArchiveDirectory *>(iconsEntry);
|
|
for(const auto &themeName : iconsDir->entries()) {
|
|
const auto *themeEntry = iconsDir->entry(themeName);
|
|
if(themeEntry && themeEntry->isDirectory()) {
|
|
addEntries(pkgFileInfo, RelevantFileType::IconTheme, static_cast<const KArchiveDirectory *>(themeEntry));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
pkgFileInfo.failure = true;
|
|
}
|
|
}
|
|
|
|
void makeArchive(const list<PkgFileInfo> &pkgFiles, const QByteArray &pkgList, const QByteArray &indexFile, RelevantFileArch arch, const QString &root, const string &targetDir, const string &targetName, const string &targetFormat)
|
|
{
|
|
// prepare archive
|
|
QString targetPath = qstr(targetDir) % QChar('/') % root % QChar('-') % qstr(targetName) % QChar('.') % qstr(targetFormat);
|
|
cerr << shchar << "Making archive \"" << targetPath.toLocal8Bit().data() << "\" ..." << endl;
|
|
unique_ptr<KArchive> targetArchive;
|
|
if(targetFormat == "7z") {
|
|
targetArchive = make_unique<K7Zip>(targetPath);
|
|
} else if(targetFormat == "zip") {
|
|
targetArchive = make_unique<KZip>(targetPath);
|
|
} else if(ConversionUtilities::startsWith<string>(targetFormat, "tar")) {
|
|
targetArchive = make_unique<KTar>(targetPath);
|
|
} else {
|
|
throw runtime_error("Specified archive format \"" + targetFormat + "\" is unknown.");
|
|
}
|
|
|
|
// add files to archive
|
|
if(targetArchive->open(QIODevice::WriteOnly)) {
|
|
// -> compile glib2 schemas and add
|
|
vector<const RelevantFile *> glib2SchemaFiles;
|
|
glib2SchemaFiles.reserve(16);
|
|
for(const auto &pkgFile : pkgFiles) {
|
|
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
|
|
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == arch) {
|
|
switch(relevantFile.fileType) {
|
|
case RelevantFileType::GLib2Schemas:
|
|
glib2SchemaFiles.push_back(&relevantFile);
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!glib2SchemaFiles.empty()) {
|
|
QTemporaryDir tempDir;
|
|
if(tempDir.isValid()) {
|
|
for(const RelevantFile *schemaFile : glib2SchemaFiles) {
|
|
QFile file(tempDir.path() % QChar('/') % schemaFile->name);
|
|
if(!file.open(QFile::WriteOnly) || !file.write(schemaFile->data)) {
|
|
cerr << shchar << "Unable to create glib2 schema file \"" << schemaFile->name.toLocal8Bit().data() << "\"." << endl;
|
|
}
|
|
}
|
|
QProcess compiler;
|
|
compiler.setProcessChannelMode(QProcess::ForwardedChannels);
|
|
compiler.start(QStringLiteral("glib-compile-schemas"), QStringList() << tempDir.path());
|
|
compiler.waitForFinished();
|
|
QFile compiledSchemas(tempDir.path() + QStringLiteral("/gschemas.compiled"));
|
|
if(compiledSchemas.open(QFile::ReadOnly)) {
|
|
targetArchive->writeFile(root + QStringLiteral("/share/glib-2.0/schemas/gschemas.compiled"), compiledSchemas.readAll());
|
|
} else {
|
|
cerr << shchar << "Unable to compile glib2 schemas: Compiled schemas (gschemas.compiled) not found." << endl;
|
|
}
|
|
|
|
} else {
|
|
cerr << shchar << "Unable to compile glib2 schemas: Can't create temp dir." << endl;
|
|
}
|
|
}
|
|
|
|
// -> add note
|
|
targetArchive->writeFile(root + QStringLiteral("/note.txt"), QByteArray("This archive has been created with Martchus' repository indexing tool.\n"
|
|
"List of included packages (name, version, license info and upstream URL): var/lib/repoindex/packages.list\n"
|
|
"More info: http://martchus.netai.net/page.php?name=programming"));
|
|
// -> add package list
|
|
if(!pkgList.isEmpty()) {
|
|
targetArchive->writeFile(root + QStringLiteral("/var/lib/repoindex/packages.list"), pkgList);
|
|
}
|
|
// -> set default icon theme
|
|
if(!indexFile.isEmpty()) {
|
|
targetArchive->writeFile(root + QStringLiteral("/share/icons/default/index.theme"), indexFile);
|
|
}
|
|
// -> add relevant files from packages
|
|
for(const auto &pkgFile : pkgFiles) {
|
|
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
|
|
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == arch) {
|
|
QString path;
|
|
mode_t mode;
|
|
switch(relevantFile.fileType) {
|
|
case RelevantFileType::Binary:
|
|
path = root % QStringLiteral("/bin/") % relevantFile.name;
|
|
mode = 0100755;
|
|
break;
|
|
case RelevantFileType::Data:
|
|
path = root % QStringLiteral("/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
|
mode = 0100644;
|
|
break;
|
|
case RelevantFileType::Translation:
|
|
path = root % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.name;
|
|
mode = 0100644;
|
|
break;
|
|
case RelevantFileType::QtTranslation:
|
|
path = root % QStringLiteral("/share/qt/translations/") % relevantFile.name;
|
|
mode = 0100644;
|
|
break;
|
|
case RelevantFileType::QtPlugin:
|
|
path = root % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
|
mode = 0100755;
|
|
break;
|
|
case RelevantFileType::Plugin:
|
|
path = root % QStringLiteral("/lib/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
|
mode = 0100755;
|
|
break;
|
|
case RelevantFileType::SharedData:
|
|
case RelevantFileType::GLib2Data:
|
|
case RelevantFileType::GLib2Schemas:
|
|
path = root % QStringLiteral("/share/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
|
mode = 0100644;
|
|
break;
|
|
case RelevantFileType::Theme:
|
|
path = root % QStringLiteral("/share/themes/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
|
mode = 0100644;
|
|
break;
|
|
case RelevantFileType::IconTheme:
|
|
path = root % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
|
mode = 0100644;
|
|
break;
|
|
}
|
|
// write the file
|
|
// disable symlinks: there is no decent support for symlinks under Windows
|
|
//if(relevantFile.symlinkTarget.isEmpty()) {
|
|
targetArchive->writeFile(path, relevantFile.data, mode);
|
|
//} else {
|
|
// targetArchive->writeSymLink(path, relevantFile.symlinkTarget, QString(), QString(), mode);
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
} else if(targetArchive->device()) {
|
|
cerr << shchar << "Error: Unable to open target archive: " << targetArchive->device()->errorString().toLocal8Bit().data() << endl;
|
|
} else {
|
|
cerr << shchar << "Error: Unable to open target archive." << endl;
|
|
}
|
|
}
|
|
|
|
void MingwBundle::createBundle(const string &targetDir, const string &targetName, const string &targetFormat, const string &defaultIconTheme) const
|
|
{
|
|
cerr << shchar << "Gathering relevant files ..." << endl;
|
|
// get package files
|
|
list<PkgFileInfo> pkgFiles;
|
|
for(const Package *pkg : m_packages) {
|
|
QString pkgFile;
|
|
if(!pkg->repository()->packagesDirectory().isEmpty()) {
|
|
pkgFile = pkg->repository()->packagesDirectory() % QChar('/') % pkg->fileName();
|
|
}
|
|
if(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
|
|
if(!m_manager.pacmanCacheDir().isEmpty()) {
|
|
pkgFile = m_manager.pacmanCacheDir() % QChar('/') % pkg->fileName();
|
|
}
|
|
if(pkgFile.isEmpty() || !QFile::exists(pkgFile)) {
|
|
throw runtime_error("The package file " + string(pkg->fileName().toLocal8Bit().data()) + " can't be found.");
|
|
// TODO: download package from mirror
|
|
}
|
|
}
|
|
// strip "mingw-w64-"-prefix and vcs-suffix (if present)
|
|
QStringRef pkgName = pkg->name().startsWith(QLatin1String("mingw-w64-")) ? pkg->name().midRef(10) : QStringRef(&pkg->name());
|
|
if(pkgName.endsWith(QLatin1String("-svn")) || pkgName.endsWith(QLatin1String("-git"))) {
|
|
pkgName = pkgName.mid(0, pkgName.length() - 4);
|
|
} else if(pkgName.endsWith(QLatin1String("-hg"))) {
|
|
pkgName = pkgName.mid(0, pkgName.length() - 3);
|
|
}
|
|
pkgFiles.emplace_back(pkgName.toString(), pkgFile);
|
|
}
|
|
for(const auto &pkgFileStdStr : m_extraPackages) {
|
|
QString pkgFile = QString::fromLocal8Bit(pkgFileStdStr.data());
|
|
if(QFile::exists(pkgFile)) {
|
|
const auto pkg = make_unique<AlpmPackage>(pkgFile); // do not catch the exception here
|
|
pkgFiles.emplace_back(pkg->name().startsWith(QLatin1String("mingw-w64-")) ? pkg->name().mid(10) : pkg->name(), pkgFile);
|
|
} else {
|
|
throw runtime_error("The specified extra package \"" + pkgFileStdStr + "\" can't be found.");
|
|
}
|
|
}
|
|
// get relevant files from packages
|
|
QtConcurrent::blockingMap(pkgFiles, getFiles);
|
|
// check whether all packages could be opened
|
|
string failed;
|
|
for(const auto &pkgFile : pkgFiles) {
|
|
if(pkgFile.failure) {
|
|
failed.push_back(' ');
|
|
failed.append(pkgFile.path.toLocal8Bit().data());
|
|
}
|
|
}
|
|
if(!failed.empty()) {
|
|
throw runtime_error("Unable to open the following package files:" + failed);
|
|
}
|
|
// make a list with package info to be included in the target archive
|
|
QJsonArray pkgArray;
|
|
for(const Package *pkg : m_packages) {
|
|
pkgArray << pkg->simpleInfo();
|
|
}
|
|
QJsonDocument pkgList;
|
|
pkgList.setArray(pkgArray);
|
|
const QByteArray pkgListBytes = pkgList.toJson();
|
|
QByteArray indexFileBytes;
|
|
if(!defaultIconTheme.empty()) {
|
|
indexFileBytes.reserve(23 + defaultIconTheme.size());
|
|
indexFileBytes.append("[Icon Theme]\nInherits=");
|
|
indexFileBytes.append(defaultIconTheme.data());
|
|
indexFileBytes.append('\n');
|
|
}
|
|
// make target archive
|
|
auto run1 = QtConcurrent::run(bind(makeArchive, ref(pkgFiles), ref(pkgListBytes), ref(indexFileBytes), RelevantFileArch::x86_64, QStringLiteral("x86_64-w64-mingw32"), ref(targetDir), ref(targetName), ref(targetFormat)));
|
|
auto run2 = QtConcurrent::run(bind(makeArchive, ref(pkgFiles), ref(pkgListBytes), ref(indexFileBytes), RelevantFileArch::i686, QStringLiteral("i686-w64-mingw32"), ref(targetDir), ref(targetName), ref(targetFormat)));
|
|
run1.waitForFinished();
|
|
run2.waitForFinished();
|
|
}
|
|
|
|
} // namespace PackageManagement
|
|
|