repoindex/lib/alpm/mingwbundle.cpp

595 lines
30 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;
using namespace ApplicationUtilities;
namespace RepoIndex {
using namespace Utilities;
const char *prefix = "mingw-w64-";
size_t prefixLen = 10;
IncludedPackage::IncludedPackage(const Package *package, bool dependencyOnly) :
package(package),
dependencyOnly(dependencyOnly)
{}
bool IncludedPackage::operator==(const Package *package) const
{
return this->package == package;
}
MingwBundle::MingwBundle(Manager &manager, const std::vector<const char *> &packages, const std::vector<const char *> &iconPackages, const std::vector<const char *> &extraPackages, const std::vector<const char *> &qtPlugins) :
m_manager(manager),
m_extraPackages(extraPackages),
m_qtPlugins(qtPlugins)
{
cerr << shchar << "Resolving dependencies ..." << endl;
string missing;
// add mingw-w64 packages
for(const char *pkgName : packages) {
if(auto *pkg = manager.packageProviding(Dependency(QString::fromLocal8Bit(strncmp(pkgName, prefix, prefixLen) ? pkgName : (prefix + string(pkgName)).data())))) {
if(find(m_packages.cbegin(), m_packages.cend(), pkg) == m_packages.cend()) {
m_packages.emplace_back(pkg, false);
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)))) {
if(find(m_packages.cbegin(), m_packages.cend(), pkg) == m_packages.cend()) {
m_packages.emplace_back(pkg, false);
}
} 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 IncludedPackage &pkg : m_packages) {
cerr << shchar << ' ' << pkg.package->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, true);
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, bool dependencyOnly = false, const vector<const char *> &qtPlugins = vector<const char *>()) :
name(name),
path(path),
dependencyOnly(dependencyOnly),
qtPlugins(qtPlugins),
failure(false)
{}
QString name;
QString path;
unique_ptr<KTar> archive;
list<RelevantFile> relevantFiles;
bool dependencyOnly;
const vector<const char *> &qtPlugins;
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((!pkgFileInfo.dependencyOnly && entryName.endsWith(QLatin1String(".exe"))) || entryName.indexOf(QLatin1String(".dll")) > 0) {
if(const auto *entry = binDir->entry(entryName)) {
// do only copy files and no symlinks
if(entry->isFile() && entry->symLinkTarget().isEmpty()) {
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(QStringLiteral("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 QString &entryName : categoryDir->entries()) {
if(const auto *pluginEntry = categoryDir->entry(entryName)) {
if(pluginEntry->isFile()) {
if(entryName.endsWith(QLatin1String(".dll"))) {
if(!pkgFileInfo.qtPlugins.empty()) {
string pluginName = entryName.toLocal8Bit().data();
pluginName.resize(pluginName.size() - 4);
if(find(pkgFileInfo.qtPlugins.cbegin(), pkgFileInfo.qtPlugins.cend(), pluginName) == pkgFileInfo.qtPlugins.cend()) {
continue;
}
}
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 {
if(pkgFileInfo.archive->device()) {
cerr << shchar << "Error: Unable to open the archive " << pkgFileInfo.path.toLocal8Bit().data() << ": " << pkgFileInfo.archive->device()->errorString().toLocal8Bit().data() << endl;
} else {
cerr << shchar << "Error: Unable to open the archive " << pkgFileInfo.path.toLocal8Bit().data() << ": Device hasn't been created." << endl;
}
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 IncludedPackage &includedPkg : m_packages) {
const Package *pkg = includedPkg.package;
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, includedPkg.dependencyOnly, m_qtPlugins);
}
for(const char *pkgFileRawStr : m_extraPackages) {
QString pkgFile = QString::fromLocal8Bit(pkgFileRawStr);
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, false, m_qtPlugins);
} else {
throw runtime_error("The specified extra package \"" + string(pkgFileRawStr) + "\" 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 IncludedPackage &pkg : m_packages) {
pkgArray << pkg.package->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