improved build-order and mingw-w64-bundle
This commit is contained in:
parent
1f1d46c5dd
commit
39e3ccc77c
|
@ -91,9 +91,15 @@ void MingwBundle::addDependencies(const Package *pkg)
|
||||||
enum class RelevantFileType
|
enum class RelevantFileType
|
||||||
{
|
{
|
||||||
Binary,
|
Binary,
|
||||||
|
Data,
|
||||||
Translation,
|
Translation,
|
||||||
QtTranslation,
|
QtTranslation,
|
||||||
QtPlugin,
|
QtPlugin,
|
||||||
|
Plugin,
|
||||||
|
SharedData,
|
||||||
|
GLib2Data,
|
||||||
|
GLib2Schemas,
|
||||||
|
Theme,
|
||||||
IconTheme,
|
IconTheme,
|
||||||
ConfigFile
|
ConfigFile
|
||||||
};
|
};
|
||||||
|
@ -122,6 +128,7 @@ struct RelevantFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
RelevantFileType fileType;
|
RelevantFileType fileType;
|
||||||
|
@ -136,6 +143,7 @@ struct PkgFileInfo
|
||||||
path(path),
|
path(path),
|
||||||
failure(false)
|
failure(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
QString path;
|
QString path;
|
||||||
unique_ptr<KTar> archive;
|
unique_ptr<KTar> archive;
|
||||||
|
@ -143,15 +151,17 @@ struct PkgFileInfo
|
||||||
bool failure;
|
bool failure;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addEntries(PkgFileInfo &pkgFileInfo, RelevantFileType fileType, const KArchiveDirectory *dir, const QString &relPath = QString())
|
void addEntries(PkgFileInfo &pkgFileInfo, RelevantFileType fileType, const KArchiveDirectory *dir, const QString &relPath = QString(), const QString &ext = QString(), RelevantFileArch relevantArch = RelevantFileArch::Any)
|
||||||
{
|
{
|
||||||
QString newPath = relPath.isEmpty() ? dir->name() : relPath % QChar('/') % dir->name();
|
const QString newPath = relPath.isEmpty() ? dir->name() : relPath % QChar('/') % dir->name();
|
||||||
for(const auto &entryName : dir->entries()) {
|
for(const auto &entryName : dir->entries()) {
|
||||||
if(auto *entry = dir->entry(entryName)) {
|
if(auto *entry = dir->entry(entryName)) {
|
||||||
if(entry->isDirectory()) {
|
if(entry->isDirectory()) {
|
||||||
addEntries(pkgFileInfo, fileType, static_cast<const KArchiveDirectory *>(entry), newPath);
|
addEntries(pkgFileInfo, fileType, static_cast<const KArchiveDirectory *>(entry), newPath, ext, relevantArch);
|
||||||
} else if(entry->isFile()) {
|
} else if(entry->isFile()) {
|
||||||
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(entry), dir, fileType, RelevantFileArch::Any, newPath);
|
if(ext.isEmpty() || entry->name().endsWith(ext)) {
|
||||||
|
pkgFileInfo.relevantFiles.emplace_back(static_cast<const KArchiveFile *>(entry), dir, fileType, relevantArch, newPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,10 +175,14 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
||||||
make_pair(RelevantFileArch::x86_64, QStringLiteral("/usr/x86_64-w64-mingw32")),
|
make_pair(RelevantFileArch::x86_64, QStringLiteral("/usr/x86_64-w64-mingw32")),
|
||||||
make_pair(RelevantFileArch::i686, QStringLiteral("/usr/i686-w64-mingw32"))
|
make_pair(RelevantFileArch::i686, QStringLiteral("/usr/i686-w64-mingw32"))
|
||||||
};
|
};
|
||||||
|
// add files for each architecture separately
|
||||||
for(const auto &root : roots) {
|
for(const auto &root : roots) {
|
||||||
|
// get root entry
|
||||||
const auto *rootEntry = pkgFileInfo.archive->directory()->entry(root.second);
|
const auto *rootEntry = pkgFileInfo.archive->directory()->entry(root.second);
|
||||||
if(rootEntry && rootEntry->isDirectory()) {
|
if(rootEntry && rootEntry->isDirectory()) {
|
||||||
const auto *rootDir = static_cast<const KArchiveDirectory *>(rootEntry);
|
const auto *rootDir = static_cast<const KArchiveDirectory *>(rootEntry);
|
||||||
|
|
||||||
|
// binary directory: *.exe and *.dll files required
|
||||||
const auto *binEntry = rootDir->entry(QStringLiteral("bin"));
|
const auto *binEntry = rootDir->entry(QStringLiteral("bin"));
|
||||||
if(binEntry && binEntry->isDirectory()) {
|
if(binEntry && binEntry->isDirectory()) {
|
||||||
const auto *binDir = static_cast<const KArchiveDirectory *>(binEntry);
|
const auto *binDir = static_cast<const KArchiveDirectory *>(binEntry);
|
||||||
|
@ -182,8 +196,11 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// library directory: Qt, GTK and application specific libs/plugins required
|
||||||
const auto *libEntry = rootDir->entry(QStringLiteral("lib"));
|
const auto *libEntry = rootDir->entry(QStringLiteral("lib"));
|
||||||
if(libEntry && libEntry->isDirectory()) {
|
if(libEntry && libEntry->isDirectory()) {
|
||||||
|
// Qt 5 plugins
|
||||||
const auto *libDir = static_cast<const KArchiveDirectory *>(libEntry);
|
const auto *libDir = static_cast<const KArchiveDirectory *>(libEntry);
|
||||||
const auto *qtEntry = libDir->entry("qt");
|
const auto *qtEntry = libDir->entry("qt");
|
||||||
if(qtEntry && qtEntry->isDirectory()) {
|
if(qtEntry && qtEntry->isDirectory()) {
|
||||||
|
@ -206,7 +223,38 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// shared directory: translations, themes, icons, schemas
|
||||||
const auto *shareEntry = rootDir->entry(QStringLiteral("share"));
|
const auto *shareEntry = rootDir->entry(QStringLiteral("share"));
|
||||||
if(shareEntry && shareEntry->isDirectory()) {
|
if(shareEntry && shareEntry->isDirectory()) {
|
||||||
const auto *shareDir = static_cast<const KArchiveDirectory *>(shareEntry);
|
const auto *shareDir = static_cast<const KArchiveDirectory *>(shareEntry);
|
||||||
|
@ -227,16 +275,46 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto *iconsEntry = shareDir->entry(QStringLiteral("icons"));
|
const auto *iconsEntry = shareDir->entry(QStringLiteral("icons"));
|
||||||
if(iconsEntry && iconsEntry->isDirectory()) {
|
if(iconsEntry && iconsEntry->isDirectory()) {
|
||||||
const auto *iconsDir = static_cast<const KArchiveDirectory *>(iconsEntry);
|
const auto *iconsDir = static_cast<const KArchiveDirectory *>(iconsEntry);
|
||||||
for(const auto &themeName : iconsDir->entries()) {
|
for(const auto &themeName : iconsDir->entries()) {
|
||||||
const auto *themeEntry = iconsDir->entry(themeName);
|
const auto *themeEntry = iconsDir->entry(themeName);
|
||||||
if(themeEntry && themeEntry->isDirectory()) {
|
if(themeEntry && themeEntry->isDirectory()) {
|
||||||
addEntries(pkgFileInfo, RelevantFileType::IconTheme, static_cast<const KArchiveDirectory *>(themeEntry));
|
addEntries(pkgFileInfo, RelevantFileType::IconTheme, static_cast<const KArchiveDirectory *>(themeEntry), QString(), QString(), root.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(pkgFileInfo.name.compare(QLatin1String("qt"))) {
|
if(pkgFileInfo.name.compare(QLatin1String("qt"))) {
|
||||||
const auto *appEntry = shareDir->entry(pkgFileInfo.name);
|
const auto *appEntry = shareDir->entry(pkgFileInfo.name);
|
||||||
if(appEntry && appEntry->isDirectory()) {
|
if(appEntry && appEntry->isDirectory()) {
|
||||||
|
@ -285,9 +363,16 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"));
|
const auto *iconsEntry = pkgFileInfo.archive->directory()->entry(QStringLiteral("usr/share/icons"));
|
||||||
if(iconsEntry && iconsEntry->isDirectory()) {
|
if(iconsEntry && iconsEntry->isDirectory()) {
|
||||||
const auto *iconsDir = static_cast<const KArchiveDirectory *>(iconsEntry);
|
const auto *iconsDir = static_cast<const KArchiveDirectory *>(iconsEntry);
|
||||||
|
@ -305,6 +390,7 @@ void getFiles(PkgFileInfo &pkgFileInfo)
|
||||||
|
|
||||||
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)
|
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);
|
QString targetPath = qstr(targetDir) % QChar('/') % root % QChar('-') % qstr(targetName) % QChar('.') % qstr(targetFormat);
|
||||||
cerr << shchar << "Making archive \"" << targetPath.toLocal8Bit().data() << "\" ..." << endl;
|
cerr << shchar << "Making archive \"" << targetPath.toLocal8Bit().data() << "\" ..." << endl;
|
||||||
unique_ptr<KArchive> targetArchive;
|
unique_ptr<KArchive> targetArchive;
|
||||||
|
@ -317,20 +403,63 @@ void makeArchive(const list<PkgFileInfo> &pkgFiles, const QByteArray &pkgList, c
|
||||||
} else {
|
} else {
|
||||||
throw runtime_error("Specified archive format \"" + targetFormat + "\" is unknown.");
|
throw runtime_error("Specified archive format \"" + targetFormat + "\" is unknown.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add files to archive
|
||||||
if(targetArchive->open(QIODevice::WriteOnly)) {
|
if(targetArchive->open(QIODevice::WriteOnly)) {
|
||||||
// add note
|
// -> 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"
|
targetArchive->writeFile(root + QStringLiteral("/note.txt"), QByteArray("This archive has been created with Martchus' repository indexing tool.\n"
|
||||||
"List of included packages: var/lib/repoindex/packages.list\n"
|
"List of included packages: var/lib/repoindex/packages.list\n"
|
||||||
"More info: http://martchus.netai.net/page.php?name=programming"));
|
"More info: http://martchus.netai.net/page.php?name=programming"));
|
||||||
// add package list
|
// -> add package list
|
||||||
if(!pkgList.isEmpty()) {
|
if(!pkgList.isEmpty()) {
|
||||||
targetArchive->writeFile(root + QStringLiteral("/var/lib/repoindex/packages.list"), pkgList);
|
targetArchive->writeFile(root + QStringLiteral("/var/lib/repoindex/packages.list"), pkgList);
|
||||||
}
|
}
|
||||||
// set default icon theme
|
// -> set default icon theme
|
||||||
if(!indexFile.isEmpty()) {
|
if(!indexFile.isEmpty()) {
|
||||||
targetArchive->writeFile(root + QStringLiteral("/share/icons/default/index.theme"), indexFile);
|
targetArchive->writeFile(root + QStringLiteral("/share/icons/default/index.theme"), indexFile);
|
||||||
}
|
}
|
||||||
// add relevant files from packages
|
// -> add relevant files from packages
|
||||||
for(const auto &pkgFile : pkgFiles) {
|
for(const auto &pkgFile : pkgFiles) {
|
||||||
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
|
for(const RelevantFile &relevantFile : pkgFile.relevantFiles) {
|
||||||
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == arch) {
|
if(relevantFile.arch == RelevantFileArch::Any || relevantFile.arch == arch) {
|
||||||
|
@ -341,6 +470,10 @@ void makeArchive(const list<PkgFileInfo> &pkgFiles, const QByteArray &pkgList, c
|
||||||
path = root % QStringLiteral("/bin/") % relevantFile.name;
|
path = root % QStringLiteral("/bin/") % relevantFile.name;
|
||||||
mode = 0100755;
|
mode = 0100755;
|
||||||
break;
|
break;
|
||||||
|
case RelevantFileType::Data:
|
||||||
|
path = root % QStringLiteral("/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
||||||
|
mode = 0100644;
|
||||||
|
break;
|
||||||
case RelevantFileType::Translation:
|
case RelevantFileType::Translation:
|
||||||
path = root % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.name;
|
path = root % QStringLiteral("/share/") % pkgFile.name % QStringLiteral("/translations/") % relevantFile.name;
|
||||||
mode = 0100644;
|
mode = 0100644;
|
||||||
|
@ -353,6 +486,20 @@ void makeArchive(const list<PkgFileInfo> &pkgFiles, const QByteArray &pkgList, c
|
||||||
path = root % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
path = root % QStringLiteral("/bin/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
||||||
mode = 0100755;
|
mode = 0100755;
|
||||||
break;
|
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:
|
case RelevantFileType::IconTheme:
|
||||||
path = root % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
path = root % QStringLiteral("/share/icons/") % relevantFile.subDir % QChar('/') % relevantFile.name;
|
||||||
mode = 0100644;
|
mode = 0100644;
|
||||||
|
|
|
@ -123,6 +123,9 @@ void Package::computeRequiredBy(Manager &manager)
|
||||||
m_requiredByComputed = true;
|
m_requiredByComputed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Checks whether the specified \a name and the specified \a version match the specified \a dependency.
|
||||||
|
*/
|
||||||
bool Package::matches(const QString &name, const QString &version, const Dependency &dependency)
|
bool Package::matches(const QString &name, const QString &version, const Dependency &dependency)
|
||||||
{
|
{
|
||||||
if(name == dependency.name) {
|
if(name == dependency.name) {
|
||||||
|
@ -147,6 +150,25 @@ bool Package::matches(const QString &name, const QString &version, const Depende
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Checks whether the package matches the specified \a dependency.
|
||||||
|
*/
|
||||||
|
bool Package::matches(const Dependency &dependency)
|
||||||
|
{
|
||||||
|
// check whether package matches "directly"
|
||||||
|
if(matches(name(), version(), dependency)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// check whether at least one of the provides matches
|
||||||
|
for(const auto &provide : provides()) {
|
||||||
|
if(matches(provide.name, provide.version, dependency)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \cond
|
* \cond
|
||||||
*/
|
*/
|
||||||
|
@ -663,6 +685,24 @@ Dependency::Dependency(const QString &dependency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Dependency::toString() const
|
||||||
|
{
|
||||||
|
switch(mode) {
|
||||||
|
case ALPM_DEP_MOD_EQ:
|
||||||
|
return name % QChar('=') % version;
|
||||||
|
case ALPM_DEP_MOD_GE:
|
||||||
|
return name % QChar('>') % QChar('=') % version;
|
||||||
|
case ALPM_DEP_MOD_LE:
|
||||||
|
return name % QChar('<') % QChar('=') % version;
|
||||||
|
case ALPM_DEP_MOD_GT:
|
||||||
|
return name % QChar('>') % version;
|
||||||
|
case ALPM_DEP_MOD_LT:
|
||||||
|
return name % QChar('<') % version;
|
||||||
|
default:
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns a JSON object for the current instance.
|
* \brief Returns a JSON object for the current instance.
|
||||||
*/
|
*/
|
||||||
|
@ -690,6 +730,8 @@ QJsonObject Dependency::toJson() const
|
||||||
case ALPM_DEP_MOD_LT:
|
case ALPM_DEP_MOD_LT:
|
||||||
obj.insert(QStringLiteral("mod"), QStringLiteral("lt"));
|
obj.insert(QStringLiteral("mod"), QStringLiteral("lt"));
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
if(!description.isEmpty()) {
|
if(!description.isEmpty()) {
|
||||||
obj.insert(QStringLiteral("desc"), description);
|
obj.insert(QStringLiteral("desc"), description);
|
||||||
|
|
|
@ -81,6 +81,9 @@ public:
|
||||||
explicit Dependency(const QString &name, const QString &version, _alpm_depmod_t mode = ALPM_DEP_MOD_ANY, const QString &description = QString());
|
explicit Dependency(const QString &name, const QString &version, _alpm_depmod_t mode = ALPM_DEP_MOD_ANY, const QString &description = QString());
|
||||||
explicit Dependency(const QString &dependency);
|
explicit Dependency(const QString &dependency);
|
||||||
|
|
||||||
|
bool operator ==(const Dependency &other) const;
|
||||||
|
|
||||||
|
QString toString() const;
|
||||||
QJsonObject toJson() const;
|
QJsonObject toJson() const;
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
|
@ -96,6 +99,16 @@ inline Dependency::Dependency(const QString &name, const QString &version, _alpm
|
||||||
description(description)
|
description(description)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
inline bool Dependency::operator ==(const Dependency &other) const
|
||||||
|
{
|
||||||
|
return other.name == name && other.description == description && other.mode == mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint qHash(const Dependency &dependency, uint seed)
|
||||||
|
{
|
||||||
|
return qHash(dependency.name, seed) ^ qHash(dependency.version, seed) ^ qHash(dependency.mode, seed) ^ qHash(dependency.description, seed);
|
||||||
|
}
|
||||||
|
|
||||||
class Manager;
|
class Manager;
|
||||||
|
|
||||||
class Package
|
class Package
|
||||||
|
@ -160,6 +173,7 @@ public:
|
||||||
ChronoUtilities::DateTime lastModified() const;
|
ChronoUtilities::DateTime lastModified() const;
|
||||||
const QString &tarUrl() const;
|
const QString &tarUrl() const;
|
||||||
const std::map<QString, QByteArray> &sourceFiles() const;
|
const std::map<QString, QByteArray> &sourceFiles() const;
|
||||||
|
QList<const QList<Dependency> *> allDependencies() const;
|
||||||
|
|
||||||
// version comparsion
|
// version comparsion
|
||||||
PackageVersionComparsion compareVersion(const Package *syncPackage) const;
|
PackageVersionComparsion compareVersion(const Package *syncPackage) const;
|
||||||
|
@ -651,6 +665,14 @@ inline const std::map<QString, QByteArray> &Package::sourceFiles() const
|
||||||
return m_sourceFiles;
|
return m_sourceFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns all dependencies.
|
||||||
|
*/
|
||||||
|
inline QList<const QList<Dependency> *> Package::allDependencies() const
|
||||||
|
{
|
||||||
|
return {&dependencies(), &makeDependencies(), &checkDependencies()};
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Compares the version of the package with the specified sync package.
|
* \brief Compares the version of the package with the specified sync package.
|
||||||
*/
|
*/
|
||||||
|
@ -667,14 +689,6 @@ inline PackageVersionComparsion Package::compareVersion(const Dependency &depend
|
||||||
return PackageVersion(version()).compare(PackageVersion(dependency.version));
|
return PackageVersion(version()).compare(PackageVersion(dependency.version));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Checks whether the package matches the specified \a dependency.
|
|
||||||
*/
|
|
||||||
inline bool Package::matches(const Dependency &dependency)
|
|
||||||
{
|
|
||||||
return matches(name(), version(), dependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ALPM_PACKAGE_H
|
#endif // ALPM_PACKAGE_H
|
||||||
|
|
|
@ -160,13 +160,6 @@ const Package *Repository::packageProviding(const Dependency &dependency) const
|
||||||
if(entry.second->matches(dependency)) {
|
if(entry.second->matches(dependency)) {
|
||||||
// check whether package matches "directly"
|
// check whether package matches "directly"
|
||||||
return entry.second.get();
|
return entry.second.get();
|
||||||
} else {
|
|
||||||
// check whether at least one of the provides matches
|
|
||||||
for(const auto &provide : entry.second->provides()) {
|
|
||||||
if(Package::matches(provide.name, provide.version, dependency)) {
|
|
||||||
return entry.second.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -182,13 +175,6 @@ Package *Repository::packageProviding(const Dependency &dependency)
|
||||||
if(entry.second->matches(dependency)) {
|
if(entry.second->matches(dependency)) {
|
||||||
// check whether package matches "directly"
|
// check whether package matches "directly"
|
||||||
return entry.second.get();
|
return entry.second.get();
|
||||||
} else {
|
|
||||||
// check whether at least one of the provides matches
|
|
||||||
for(auto &provide : entry.second->provides()) {
|
|
||||||
if(Package::matches(provide.name, provide.version, dependency)) {
|
|
||||||
return entry.second.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -202,16 +188,7 @@ QList<const Package *> Repository::packagesProviding(const Dependency &dependenc
|
||||||
QList<const Package *> res;
|
QList<const Package *> res;
|
||||||
for(const auto &entry : m_packages) {
|
for(const auto &entry : m_packages) {
|
||||||
if(entry.second->matches(dependency)) {
|
if(entry.second->matches(dependency)) {
|
||||||
// check whether package matches "directly"
|
|
||||||
res << entry.second.get();
|
res << entry.second.get();
|
||||||
} else {
|
|
||||||
// check whether at least one of the provides matches
|
|
||||||
for(const auto &provide : entry.second->provides()) {
|
|
||||||
if(Package::matches(provide.name, provide.version, dependency)) {
|
|
||||||
res << entry.second.get();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <c++utilities/misc/memory.h>
|
#include <c++utilities/misc/memory.h>
|
||||||
|
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
|
#include <QEventLoop>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -18,14 +19,17 @@ using namespace ApplicationUtilities;
|
||||||
|
|
||||||
namespace RepoIndex {
|
namespace RepoIndex {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief The TaskInfo class defines a build task and provides the topo-sort required to resolve the build order.
|
||||||
|
*/
|
||||||
class TaskInfo
|
class TaskInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TaskInfo(QString name, bool onlyDependency = false, const QList<TaskInfo *> &deps = QList<TaskInfo *>());
|
TaskInfo(const QString &name, bool onlyDependency = false, const QSet<TaskInfo *> &deps = QSet<TaskInfo *>());
|
||||||
|
|
||||||
const QString &name() const;
|
const QString &name() const;
|
||||||
void setName(const QString &name);
|
void setName(const QString &name);
|
||||||
const QList<TaskInfo *> deps() const;
|
const QSet<TaskInfo *> deps() const;
|
||||||
void addDep(TaskInfo *dep);
|
void addDep(TaskInfo *dep);
|
||||||
bool isDone() const;
|
bool isDone() const;
|
||||||
bool isVisited() const;
|
bool isVisited() const;
|
||||||
|
@ -33,23 +37,29 @@ public:
|
||||||
void setIsOnlyDependency(bool isOnlyDependency);
|
void setIsOnlyDependency(bool isOnlyDependency);
|
||||||
bool isPackageRequested() const;
|
bool isPackageRequested() const;
|
||||||
void setPackageRequested();
|
void setPackageRequested();
|
||||||
|
QSet<Dependency> requiredFor() const;
|
||||||
|
void addRequiredFor(const Dependency &dependency);
|
||||||
void add(QList<TaskInfo *> &results);
|
void add(QList<TaskInfo *> &results);
|
||||||
Package *associatedPackage() const;
|
Package *associatedPackage() const;
|
||||||
void associatePackage(Package *package);
|
bool associatePackage(Package *package);
|
||||||
static void addAll(const QList<TaskInfo *> &tasks, QList<TaskInfo *> &results);
|
static void addAll(const QList<TaskInfo *> &tasks, QList<TaskInfo *> &results);
|
||||||
static TaskInfo *find(const QList<TaskInfo *> &tasks, const QString &name);
|
static TaskInfo *find(const QList<TaskInfo *> &tasks, const QString &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QList<TaskInfo *> m_deps;
|
QSet<TaskInfo *> m_deps;
|
||||||
bool m_done;
|
bool m_done;
|
||||||
bool m_visited;
|
bool m_visited;
|
||||||
bool m_onlyDep;
|
bool m_onlyDep;
|
||||||
bool m_pkgRequested;
|
bool m_pkgRequested;
|
||||||
|
QSet<Dependency> m_requiredFor;
|
||||||
Package *m_associatedPackage;
|
Package *m_associatedPackage;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline TaskInfo::TaskInfo(QString name, bool onlyDependency, const QList<TaskInfo *> &deps) :
|
/*!
|
||||||
|
* \brief Constructs a new task.
|
||||||
|
*/
|
||||||
|
inline TaskInfo::TaskInfo(const QString &name, bool onlyDependency, const QSet<TaskInfo *> &deps) :
|
||||||
m_name(name),
|
m_name(name),
|
||||||
m_deps(deps),
|
m_deps(deps),
|
||||||
m_done(false),
|
m_done(false),
|
||||||
|
@ -59,6 +69,13 @@ inline TaskInfo::TaskInfo(QString name, bool onlyDependency, const QList<TaskInf
|
||||||
m_associatedPackage(nullptr)
|
m_associatedPackage(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the name of the task.
|
||||||
|
*
|
||||||
|
* This is usually the name which has been specified when constructing
|
||||||
|
* the task. However, the name might be adjusted to the package name
|
||||||
|
* when a package is associated.
|
||||||
|
*/
|
||||||
inline const QString &TaskInfo::name() const
|
inline const QString &TaskInfo::name() const
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
|
@ -69,46 +86,105 @@ inline void TaskInfo::setName(const QString &name)
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const QList<TaskInfo *> TaskInfo::deps() const
|
/*!
|
||||||
|
* \brief Returns the dependencies added via addDep().
|
||||||
|
*/
|
||||||
|
inline const QSet<TaskInfo *> TaskInfo::deps() const
|
||||||
{
|
{
|
||||||
return m_deps;
|
return m_deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Adds another task as dependency.
|
||||||
|
*/
|
||||||
inline void TaskInfo::addDep(TaskInfo *dep)
|
inline void TaskInfo::addDep(TaskInfo *dep)
|
||||||
{
|
{
|
||||||
m_deps << dep;
|
m_deps << dep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the task already has been added to the resulting list of tasks.
|
||||||
|
* \sa add()
|
||||||
|
*/
|
||||||
inline bool TaskInfo::isDone() const
|
inline bool TaskInfo::isDone() const
|
||||||
{
|
{
|
||||||
return m_done;
|
return m_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the task has been visited.
|
||||||
|
* \remarks Used to track circular dependencies (within add()).
|
||||||
|
*/
|
||||||
inline bool TaskInfo::isVisited() const
|
inline bool TaskInfo::isVisited() const
|
||||||
{
|
{
|
||||||
return m_visited;
|
return m_visited;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the task is only a dependency and none of the packages to be build.
|
||||||
|
* \remarks Circular dependencies between packages which are only dependencies can be ignored.
|
||||||
|
*/
|
||||||
inline bool TaskInfo::isOnlyDependency() const
|
inline bool TaskInfo::isOnlyDependency() const
|
||||||
{
|
{
|
||||||
return m_onlyDep;
|
return m_onlyDep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Sets whether the package is only a dependency.
|
||||||
|
* \sa isOnlyDependency()
|
||||||
|
*/
|
||||||
inline void TaskInfo::setIsOnlyDependency(bool isOnlyDependency)
|
inline void TaskInfo::setIsOnlyDependency(bool isOnlyDependency)
|
||||||
{
|
{
|
||||||
m_onlyDep = isOnlyDependency;
|
m_onlyDep = isOnlyDependency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the package for this task has been requested yet.
|
||||||
|
*
|
||||||
|
* Used to avoid requesting the same package twice after the package
|
||||||
|
* couldn't be found when requesting it the first time.
|
||||||
|
*/
|
||||||
inline bool TaskInfo::isPackageRequested() const
|
inline bool TaskInfo::isPackageRequested() const
|
||||||
{
|
{
|
||||||
return m_pkgRequested;
|
return m_pkgRequested;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Sets whether the package has been requested.
|
||||||
|
*
|
||||||
|
* This is set just before a package for this task is requrested.
|
||||||
|
*/
|
||||||
inline void TaskInfo::setPackageRequested()
|
inline void TaskInfo::setPackageRequested()
|
||||||
{
|
{
|
||||||
m_pkgRequested = true;
|
m_pkgRequested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the dependencies the task has been added for.
|
||||||
|
* \remarks
|
||||||
|
* - The same task can be added for multiple dependencies, eg.
|
||||||
|
* mingw-w64-extra-cmake-modules and mingw-w64-extra-cmake-modules=5.15.0.
|
||||||
|
* - The dependencies must be set explicitely using addRequiredFor().
|
||||||
|
*/
|
||||||
|
inline QSet<Dependency> TaskInfo::requiredFor() const
|
||||||
|
{
|
||||||
|
return m_requiredFor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Adds the specified \a dependency to the list of dependencies the task has been added for.
|
||||||
|
* \sa requiredFor()
|
||||||
|
*/
|
||||||
|
inline void TaskInfo::addRequiredFor(const Dependency &dependency)
|
||||||
|
{
|
||||||
|
m_requiredFor << dependency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Adds the task to the specified list of results. Ensures that all dependencies are added before.
|
||||||
|
* \throws If a circular dependency between the build tasks has been detected, the causing task is thrown.
|
||||||
|
* \remarks Dependencies must be added via addDep() before calling this method.
|
||||||
|
*/
|
||||||
void TaskInfo::add(QList<TaskInfo *> &results)
|
void TaskInfo::add(QList<TaskInfo *> &results)
|
||||||
{
|
{
|
||||||
if(!isDone()) {
|
if(!isDone()) {
|
||||||
|
@ -133,18 +209,57 @@ void TaskInfo::add(QList<TaskInfo *> &results)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the package associated via associatePackage().
|
||||||
|
*/
|
||||||
inline Package *TaskInfo::associatedPackage() const
|
inline Package *TaskInfo::associatedPackage() const
|
||||||
{
|
{
|
||||||
return m_associatedPackage;
|
return m_associatedPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskInfo::associatePackage(Package *package)
|
/*!
|
||||||
|
* \brief Associates the specified \a package with this build task.
|
||||||
|
*
|
||||||
|
* Does nothing if there is already a package assigned which matches all
|
||||||
|
* dependencies the task has been added for. Returns true in this case.
|
||||||
|
*
|
||||||
|
* Fails if the specified \a package does not match all dependencies the task
|
||||||
|
* has been added for.
|
||||||
|
*
|
||||||
|
* \return Returns whether either the currenlty assigned package or the specified
|
||||||
|
* \a package matches all dependencies the task has been added for.
|
||||||
|
*/
|
||||||
|
bool TaskInfo::associatePackage(Package *package)
|
||||||
{
|
{
|
||||||
|
// check whether an appropriate package is already assigned
|
||||||
|
// and whether the package matches all dependencies this task is required for
|
||||||
|
bool assignmentRequired = !m_associatedPackage, assignmentPossible = true;
|
||||||
|
for(const Dependency &dep : m_requiredFor) {
|
||||||
|
if(!assignmentRequired && !m_associatedPackage->matches(dep)) {
|
||||||
|
assignmentRequired = true;
|
||||||
|
}
|
||||||
|
if(!package->matches(dep)) {
|
||||||
|
assignmentPossible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!assignmentRequired) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(!assignmentPossible) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
m_associatedPackage = package;
|
m_associatedPackage = package;
|
||||||
// update the name to ensure we have the acutal package name and not just a "provides" name
|
// update the name to ensure we have the acutal package name and not just a "provides" name
|
||||||
m_name = package->name();
|
m_name = package->name();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Adds the specified \a tasks and their dependencies to the specified list of results. Ensures that all
|
||||||
|
* tasks are added in the right order.
|
||||||
|
* \throws If a circular dependency between the build tasks has been detected, the causing task is thrown.
|
||||||
|
* \remarks Dependencies must be added to the \a tasks via addDep() before calling this method.
|
||||||
|
*/
|
||||||
void TaskInfo::addAll(const QList<TaskInfo *> &tasks, QList<TaskInfo *> &results)
|
void TaskInfo::addAll(const QList<TaskInfo *> &tasks, QList<TaskInfo *> &results)
|
||||||
{
|
{
|
||||||
for(auto *task : tasks) {
|
for(auto *task : tasks) {
|
||||||
|
@ -152,6 +267,10 @@ void TaskInfo::addAll(const QList<TaskInfo *> &tasks, QList<TaskInfo *> &results
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Finds the task with the specified \a name in the specified list of \a tasks.
|
||||||
|
* \remarks Does not search dependencies the list does not contain.
|
||||||
|
*/
|
||||||
TaskInfo *TaskInfo::find(const QList<TaskInfo *> &tasks, const QString &name)
|
TaskInfo *TaskInfo::find(const QList<TaskInfo *> &tasks, const QString &name)
|
||||||
{
|
{
|
||||||
for(auto *task : tasks) {
|
for(auto *task : tasks) {
|
||||||
|
@ -162,104 +281,53 @@ TaskInfo *TaskInfo::find(const QList<TaskInfo *> &tasks, const QString &name)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ListType>
|
/*!
|
||||||
class DestroyList
|
* \class BuildOrderResolver
|
||||||
{
|
* \brief The BuildOrderResolver class resolves the build order for a specified array of packages.
|
||||||
public:
|
*
|
||||||
DestroyList(ListType &list) :
|
* Resolving the build order is done in the following steps:
|
||||||
m_list(list)
|
* 1. instantiation: initial tasks are added
|
||||||
{}
|
* 2. findDependencies(): dependencies for each task are added, some packages might have to be requested first
|
||||||
|
* 3. if some packages must be requested: wait for requested packages, if requested packages are available, go to 2.
|
||||||
|
* 4. all dependencies are added: signal ready() is emitted
|
||||||
|
* 5. resolve(): build order is resolved, either resolvingFinished() or resolvingFailed() is emitted
|
||||||
|
*/
|
||||||
|
|
||||||
~DestroyList()
|
/*!
|
||||||
{
|
* \brief Creates a new BuildOrderResolver using the specified \a manager.
|
||||||
qDeleteAll(m_list);
|
*/
|
||||||
}
|
BuildOrderResolver::BuildOrderResolver(Manager &manager, bool addSourceOnlyDeps) :
|
||||||
|
|
||||||
private:
|
|
||||||
ListType &m_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
BuildOrderResolver::BuildOrderResolver(Manager &manager, const StringVector &packages, bool addSourceOnlyDeps) :
|
|
||||||
m_manager(manager),
|
m_manager(manager),
|
||||||
m_finder(nullptr),
|
m_finder(nullptr),
|
||||||
m_addSourceOnlyDeps(addSourceOnlyDeps)
|
m_addSourceOnlyDeps(addSourceOnlyDeps),
|
||||||
|
m_hasFinished(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Adds the specified \a errorMessage.
|
||||||
|
*/
|
||||||
|
void BuildOrderResolver::addError(const QString &errorMessage)
|
||||||
{
|
{
|
||||||
cerr << shchar << "Getting package information ..." << endl;
|
if(!m_errorMessage.isEmpty()) {
|
||||||
m_tasks.clear();
|
m_errorMessage.append(QStringLiteral(" \u2192 "));
|
||||||
m_tasks.reserve(packages.size() * 2);
|
|
||||||
// add a task for each specified package
|
|
||||||
for(const auto &pkgName : packages) {
|
|
||||||
m_tasks << new TaskInfo(QString::fromLocal8Bit(pkgName.data()));
|
|
||||||
}
|
}
|
||||||
|
m_errorMessage.append(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Destroys the object.
|
||||||
|
*/
|
||||||
BuildOrderResolver::~BuildOrderResolver()
|
BuildOrderResolver::~BuildOrderResolver()
|
||||||
{
|
{
|
||||||
qDeleteAll(m_tasks);
|
qDeleteAll(m_tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildOrderResolver::cli()
|
/*!
|
||||||
{
|
* \brief Finds the dependencies of all packages.
|
||||||
if(m_manager.config().isVerbose()) {
|
*
|
||||||
connect(this, &BuildOrderResolver::ready, this, &BuildOrderResolver::printRelevantPackages);
|
* Also internally called after requested packages are available.
|
||||||
}
|
*/
|
||||||
connect(this, &BuildOrderResolver::ready, this, &BuildOrderResolver::resolve);
|
|
||||||
connect(this, &BuildOrderResolver::resolvingFinished, this, &BuildOrderResolver::printResults);
|
|
||||||
connect(this, &BuildOrderResolver::resolvingFailed, static_cast<void(*)(const QString &)>(Utilities::printError));
|
|
||||||
findDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildOrderResolver::findDependencies()
|
void BuildOrderResolver::findDependencies()
|
||||||
{
|
|
||||||
// find specified packages and their dependencies
|
|
||||||
for(int i = 0, size = m_tasks.size(); i != size; ++i) {
|
|
||||||
addDependenciesToTask(m_tasks.at(i));
|
|
||||||
}
|
|
||||||
// request dependencies to be requested
|
|
||||||
requestDependenciesToBeRequested();
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList BuildOrderResolver::resultNames()
|
|
||||||
{
|
|
||||||
QStringList names;
|
|
||||||
names.reserve(m_results.size());
|
|
||||||
for(const auto *res : m_results) {
|
|
||||||
names << res->name();
|
|
||||||
}
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildOrderResolver::printRelevantPackages()
|
|
||||||
{
|
|
||||||
cerr << shchar << "Relevant packages:";
|
|
||||||
for(const auto *task : m_tasks) {
|
|
||||||
cerr << ' ' << task->name().toLocal8Bit().data();
|
|
||||||
}
|
|
||||||
cerr << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildOrderResolver::printResults()
|
|
||||||
{
|
|
||||||
if(useShSyntax) {
|
|
||||||
Utilities::printBashArray(cout, "REPOINDEX_RESULTS", resultNames());
|
|
||||||
} else {
|
|
||||||
Utilities::printValues(cout, "Results", resultNames());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildOrderResolver::resolve()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
m_results.clear();
|
|
||||||
m_results.reserve(m_tasks.size());
|
|
||||||
TaskInfo::addAll(m_tasks, m_results);
|
|
||||||
emit resolvingFinished();
|
|
||||||
} catch(const TaskInfo &cyclic) {
|
|
||||||
emit resolvingFailed(QStringLiteral("Can't resolve build order; the package ") % cyclic.name() % QStringLiteral(" is a cyclic dependency."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildOrderResolver::addRequestedPackages()
|
|
||||||
{
|
{
|
||||||
// find specified packages and their dependencies
|
// find specified packages and their dependencies
|
||||||
for(int i = 0, size = m_tasks.size(); i != size; ++i) {
|
for(int i = 0, size = m_tasks.size(); i != size; ++i) {
|
||||||
|
@ -271,6 +339,71 @@ void BuildOrderResolver::addRequestedPackages()
|
||||||
requestDependenciesToBeRequested();
|
requestDependenciesToBeRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the resulting build order.
|
||||||
|
* \remarks Build order must have been resolved yet.
|
||||||
|
*/
|
||||||
|
QStringList BuildOrderResolver::resultNames()
|
||||||
|
{
|
||||||
|
QStringList names;
|
||||||
|
names.reserve(m_results.size());
|
||||||
|
for(const auto *res : m_results) {
|
||||||
|
names << res->name();
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Prints relevant packages.
|
||||||
|
* \remarks All dependencies must have been found yet.
|
||||||
|
*/
|
||||||
|
void BuildOrderResolver::printRelevantPackages()
|
||||||
|
{
|
||||||
|
cerr << shchar << "Relevant packages:";
|
||||||
|
for(const auto *task : m_tasks) {
|
||||||
|
cerr << ' ' << task->name().toLocal8Bit().data();
|
||||||
|
}
|
||||||
|
cerr << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Prints the resulting build order.
|
||||||
|
* \remarks Build order must have been resolved yet.
|
||||||
|
*/
|
||||||
|
void BuildOrderResolver::printResults()
|
||||||
|
{
|
||||||
|
if(useShSyntax) {
|
||||||
|
Utilities::printBashArray(cout, "REPOINDEX_RESULTS", resultNames());
|
||||||
|
} else {
|
||||||
|
Utilities::printValues(cout, "Results", resultNames());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Resolves the build order.
|
||||||
|
* \remarks All dependencies must have been found yet.
|
||||||
|
*
|
||||||
|
* Emits either resolvingFinished() or resolvingFailed() depending on whether
|
||||||
|
* the operation succeeded.
|
||||||
|
*/
|
||||||
|
void BuildOrderResolver::resolve()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
m_results.clear();
|
||||||
|
m_results.reserve(m_tasks.size());
|
||||||
|
TaskInfo::addAll(m_tasks, m_results);
|
||||||
|
m_hasFinished = true;
|
||||||
|
emit resolvingFinished();
|
||||||
|
} catch(const TaskInfo &cyclic) {
|
||||||
|
addError(QStringLiteral("Can't resolve build order; the package ") % cyclic.name() % QStringLiteral(" is a cyclic dependency."));
|
||||||
|
m_hasFinished = true;
|
||||||
|
emit resolvingFailed(m_errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the package for the specified \a dependency or nullptr if no package could be found.
|
||||||
|
*/
|
||||||
Package *BuildOrderResolver::findPackageForDependency(const Dependency &dependency)
|
Package *BuildOrderResolver::findPackageForDependency(const Dependency &dependency)
|
||||||
{
|
{
|
||||||
Package *pkg;
|
Package *pkg;
|
||||||
|
@ -283,7 +416,7 @@ Package *BuildOrderResolver::findPackageForDependency(const Dependency &dependen
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Finds the package for the specified \a task and then adds dependencies.
|
* \brief Finds the package for the specified \a task and then adds dependencies recursively.
|
||||||
*/
|
*/
|
||||||
bool BuildOrderResolver::addDependenciesToTask(TaskInfo *task)
|
bool BuildOrderResolver::addDependenciesToTask(TaskInfo *task)
|
||||||
{
|
{
|
||||||
|
@ -294,17 +427,31 @@ bool BuildOrderResolver::addDependenciesToTask(TaskInfo *task)
|
||||||
}
|
}
|
||||||
Dependency dep(task->name(), QString());
|
Dependency dep(task->name(), QString());
|
||||||
if(const auto pkg = findPackageForDependency(dep)) {
|
if(const auto pkg = findPackageForDependency(dep)) {
|
||||||
task->associatePackage(pkg);
|
task->addRequiredFor(dep);
|
||||||
if(m_addSourceOnlyDeps && pkg->repository()->isSourceOnly()) {
|
if(task->associatePackage(pkg)) {
|
||||||
task->setIsOnlyDependency(false);
|
if(m_addSourceOnlyDeps && pkg->repository()->isSourceOnly()) {
|
||||||
|
task->setIsOnlyDependency(false);
|
||||||
|
}
|
||||||
|
// add dependencies to task
|
||||||
|
if(!addDependenciesToTask(task, pkg->allDependencies())) {
|
||||||
|
addError(QStringLiteral("Can not add dependencies of the dependency \"") % dep.toString() % QStringLiteral("\"."));
|
||||||
|
m_hasFinished = true;
|
||||||
|
emit resolvingFailed(errorMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addError(QStringLiteral("Can not associate the task \"") % task->name() % QStringLiteral("\" with the package required by dependency \"") % dep.toString() % QStringLiteral("\"."));
|
||||||
|
m_hasFinished = true;
|
||||||
|
emit resolvingFailed(errorMessage());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// add dependencies to task
|
|
||||||
addDependenciesToTask(task, pkg->dependencies());
|
|
||||||
} else if(!task->isPackageRequested()) {
|
} else if(!task->isPackageRequested()) {
|
||||||
task->setPackageRequested();
|
task->setPackageRequested();
|
||||||
m_dependenciesToBeRequested << dep;
|
m_dependenciesToBeRequested << dep;
|
||||||
} else {
|
} else {
|
||||||
emit resolvingFailed(QStringLiteral("The specified package \"") % task->name() % QStringLiteral("\" could not be found."));
|
addError(QStringLiteral("The specified package \"") % task->name() % QStringLiteral("\" could not be found."));
|
||||||
|
m_hasFinished = true;
|
||||||
|
emit resolvingFailed(errorMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -312,38 +459,53 @@ bool BuildOrderResolver::addDependenciesToTask(TaskInfo *task)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Finds packages for the the specified \a dependencies and adds them to the specified \a task.
|
* \brief Finds packages for the the specified \a dependencies and adds them to the specified \a task.
|
||||||
|
* \remarks Adds dependencies of the dependencies recursively.
|
||||||
*/
|
*/
|
||||||
bool BuildOrderResolver::addDependenciesToTask(TaskInfo *task, const QList<Dependency> &dependencies)
|
bool BuildOrderResolver::addDependenciesToTask(TaskInfo *task, const QList<const QList<Dependency> *> &dependencies)
|
||||||
{
|
{
|
||||||
for(auto &dep : dependencies) {
|
for(auto *deps : dependencies) {
|
||||||
const auto depPkg = findPackageForDependency(dep);
|
for(auto &dep : *deps) {
|
||||||
const QString taskName = depPkg ? depPkg->name() : dep.name;
|
auto *depPkg = findPackageForDependency(dep);
|
||||||
auto *depTask = TaskInfo::find(m_tasks, taskName);
|
const QString taskName = depPkg ? depPkg->name() : dep.name;
|
||||||
if(depTask) {
|
auto *depTask = TaskInfo::find(m_tasks, dep.name);
|
||||||
// we've already added a task for this dependency
|
bool newTask;
|
||||||
// -> add dependency task to the dependencies of "parent" task
|
if(depTask) {
|
||||||
task->addDep(depTask);
|
// we've already added a task for this dependency
|
||||||
} else {
|
newTask = false;
|
||||||
// create new task
|
|
||||||
m_tasks << (depTask = new TaskInfo(taskName, true));
|
|
||||||
// adds dependency task to the dependencies of "parent" task
|
|
||||||
task->addDep(depTask);
|
|
||||||
if(depPkg) {
|
|
||||||
depTask->associatePackage(depPkg);
|
|
||||||
if(m_addSourceOnlyDeps && depPkg->repository()->isSourceOnly()) {
|
|
||||||
depTask->setIsOnlyDependency(false);
|
|
||||||
}
|
|
||||||
// add dependencies of the dependency
|
|
||||||
addDependenciesToTask(depTask, depPkg->dependencies());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!depPkg) {
|
|
||||||
if(!depTask->isPackageRequested()) {
|
|
||||||
depTask->setPackageRequested();
|
|
||||||
m_dependenciesToBeRequested << dep;
|
|
||||||
} else {
|
} else {
|
||||||
emit resolvingFailed(QStringLiteral("The specified package \"") % task->name() % QStringLiteral("\" could not be found."));
|
// create new task
|
||||||
return false;
|
m_tasks << (depTask = new TaskInfo(taskName, true));
|
||||||
|
newTask = true;
|
||||||
|
}
|
||||||
|
// add dependency task to the dependencies of "parent" task
|
||||||
|
task->addDep(depTask);
|
||||||
|
depTask->addRequiredFor(dep);
|
||||||
|
if(depPkg) {
|
||||||
|
if(depTask->associatePackage(depPkg)) {
|
||||||
|
if(m_addSourceOnlyDeps && depPkg->repository() && depPkg->repository()->isSourceOnly()) {
|
||||||
|
depTask->setIsOnlyDependency(false);
|
||||||
|
}
|
||||||
|
if(newTask) {
|
||||||
|
// add dependencies of the dependency
|
||||||
|
if(!addDependenciesToTask(depTask, depPkg->allDependencies())) {
|
||||||
|
addError(QStringLiteral("Can not add dependencies of the dependency \"") % dep.toString() % QStringLiteral("\"."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addError(QStringLiteral("Can not associate the task \"") % depTask->name() % QStringLiteral("\" with the package required by dependency \"") % dep.toString() % QStringLiteral("\"."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!m_dependenciesToBeRequested.contains(dep)) {
|
||||||
|
if(!depTask->isPackageRequested()) {
|
||||||
|
depTask->setPackageRequested();
|
||||||
|
m_dependenciesToBeRequested << dep;
|
||||||
|
} else {
|
||||||
|
addError(QStringLiteral("The specified package \"") % dep.toString() % QStringLiteral("\" could not be found."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,10 +537,10 @@ void BuildOrderResolver::requestDependenciesToBeRequested()
|
||||||
// add results
|
// add results
|
||||||
if(m_finder->areAllResultsAvailable()) {
|
if(m_finder->areAllResultsAvailable()) {
|
||||||
// results are immediately available (already cached)
|
// results are immediately available (already cached)
|
||||||
addRequestedPackages();
|
findDependencies();
|
||||||
} else {
|
} else {
|
||||||
// need to request actually
|
// need to request actually
|
||||||
connect(m_finder.get(), &PackageFinder::resultsAvailable, this, &BuildOrderResolver::addRequestedPackages);
|
connect(m_finder.get(), &PackageFinder::resultsAvailable, this, &BuildOrderResolver::findDependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -387,5 +549,50 @@ void BuildOrderResolver::requestDependenciesToBeRequested()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class BuildOrderResolverCli
|
||||||
|
* \brief The BuildOrderResolverCli class resolves the build order of the specified packages and prints the results stdout.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Creates a new BuildOrderResolverCli for the specified \a packages using the specified \a manager.
|
||||||
|
*/
|
||||||
|
BuildOrderResolverCli::BuildOrderResolverCli(Manager &manager, const StringVector &packages, bool addSourceOnlyDeps) :
|
||||||
|
BuildOrderResolver(manager, addSourceOnlyDeps)
|
||||||
|
{
|
||||||
|
cerr << shchar << "Getting package information ..." << endl;
|
||||||
|
tasks().clear();
|
||||||
|
tasks().reserve(packages.size() * 2);
|
||||||
|
// add a task for each specified package
|
||||||
|
for(const auto &pkgName : packages) {
|
||||||
|
tasks() << new TaskInfo(QString::fromLocal8Bit(pkgName.data()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Determines dependencies, prints relevant packages, resolves build order, prints results/errors.
|
||||||
|
* \remarks Does not return until everything is done.
|
||||||
|
*/
|
||||||
|
int BuildOrderResolverCli::exec()
|
||||||
|
{
|
||||||
|
if(manager().config().isVerbose()) {
|
||||||
|
connect(this, &BuildOrderResolver::ready, this, &BuildOrderResolver::printRelevantPackages);
|
||||||
|
}
|
||||||
|
connect(this, &BuildOrderResolver::ready, this, &BuildOrderResolver::resolve);
|
||||||
|
connect(this, &BuildOrderResolver::resolvingFinished, this, &BuildOrderResolver::printResults);
|
||||||
|
connect(this, &BuildOrderResolver::resolvingFailed, static_cast<void(*)(const QString &)>(Utilities::printError));
|
||||||
|
QEventLoop loop;
|
||||||
|
connect(this, &BuildOrderResolver::resolvingFinished, &loop, &QEventLoop::quit);
|
||||||
|
connect(this, &BuildOrderResolver::resolvingFailed, &loop, &QEventLoop::quit);
|
||||||
|
findDependencies();
|
||||||
|
if(hasFinished()) {
|
||||||
|
// resolving might have been finished immidiately
|
||||||
|
return errorMessage().isEmpty();
|
||||||
|
} else {
|
||||||
|
// resolving not finished yet (deps must be requested)
|
||||||
|
return loop.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace PackageManagement
|
} // namespace PackageManagement
|
||||||
|
|
||||||
|
|
|
@ -21,15 +21,14 @@ class BuildOrderResolver : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
BuildOrderResolver(Manager &manager, const ApplicationUtilities::StringVector &packages, bool addSourceOnlyDeps = false);
|
|
||||||
~BuildOrderResolver();
|
~BuildOrderResolver();
|
||||||
|
|
||||||
void cli();
|
|
||||||
|
|
||||||
void findDependencies();
|
|
||||||
QStringList resultNames();
|
QStringList resultNames();
|
||||||
|
bool hasFinished() const;
|
||||||
|
const QString &errorMessage() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void findDependencies();
|
||||||
void printRelevantPackages();
|
void printRelevantPackages();
|
||||||
void printResults();
|
void printResults();
|
||||||
void resolve();
|
void resolve();
|
||||||
|
@ -39,13 +38,16 @@ signals:
|
||||||
void resolvingFinished();
|
void resolvingFinished();
|
||||||
void resolvingFailed(const QString &message);
|
void resolvingFailed(const QString &message);
|
||||||
|
|
||||||
private slots:
|
protected:
|
||||||
void addRequestedPackages();
|
BuildOrderResolver(Manager &manager, bool addSourceOnlyDeps = false);
|
||||||
|
Manager &manager();
|
||||||
|
QList<TaskInfo *> &tasks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void addError(const QString &errorMessage);
|
||||||
Package *findPackageForDependency(const Dependency &dependency);
|
Package *findPackageForDependency(const Dependency &dependency);
|
||||||
bool addDependenciesToTask(TaskInfo *task);
|
bool addDependenciesToTask(TaskInfo *task);
|
||||||
bool addDependenciesToTask(TaskInfo *task, const QList<Dependency> &dependencies);
|
bool addDependenciesToTask(TaskInfo *task, const QList<const QList<Dependency> *> &dependencies);
|
||||||
void requestDependenciesToBeRequested();
|
void requestDependenciesToBeRequested();
|
||||||
|
|
||||||
Manager &m_manager;
|
Manager &m_manager;
|
||||||
|
@ -54,6 +56,49 @@ private:
|
||||||
std::unique_ptr<PackageFinder> m_finder;
|
std::unique_ptr<PackageFinder> m_finder;
|
||||||
QList<TaskInfo *> m_results;
|
QList<TaskInfo *> m_results;
|
||||||
bool m_addSourceOnlyDeps;
|
bool m_addSourceOnlyDeps;
|
||||||
|
bool m_hasFinished;
|
||||||
|
QString m_errorMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether adding dependencies/resolving the build order has been finished.
|
||||||
|
* \remarks Also true when an error occured. In this case errorMessage() is not empty.
|
||||||
|
*/
|
||||||
|
inline bool BuildOrderResolver::hasFinished() const
|
||||||
|
{
|
||||||
|
return m_hasFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the error message if an error occured.
|
||||||
|
*/
|
||||||
|
inline const QString &BuildOrderResolver::errorMessage() const
|
||||||
|
{
|
||||||
|
return m_errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the manager used to find packages.
|
||||||
|
*/
|
||||||
|
inline Manager &BuildOrderResolver::manager()
|
||||||
|
{
|
||||||
|
return m_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the tasks.
|
||||||
|
*/
|
||||||
|
inline QList<TaskInfo *> &BuildOrderResolver::tasks()
|
||||||
|
{
|
||||||
|
return m_tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BuildOrderResolverCli : public BuildOrderResolver
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
BuildOrderResolverCli(Manager &manager, const ApplicationUtilities::StringVector &packages, bool addSourceOnlyDeps = false);
|
||||||
|
int exec();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace PackageManagement
|
} // namespace PackageManagement
|
||||||
|
|
8
main.cpp
8
main.cpp
|
@ -77,12 +77,8 @@ int main(int argc, char *argv[])
|
||||||
// run Qt loop
|
// run Qt loop
|
||||||
return application.exec();
|
return application.exec();
|
||||||
} else if(configArgs.buildOrderArg.isPresent()) {
|
} else if(configArgs.buildOrderArg.isPresent()) {
|
||||||
BuildOrderResolver resolver(manager, configArgs.buildOrderArg.values(), configArgs.addSourceOnlyDeps.isPresent());
|
BuildOrderResolverCli resolver(manager, configArgs.buildOrderArg.values(), configArgs.addSourceOnlyDeps.isPresent());
|
||||||
resolver.cli();
|
return resolver.exec();
|
||||||
QObject::connect(&resolver, &BuildOrderResolver::resolvingFinished, &application, &QCoreApplication::quit);
|
|
||||||
QObject::connect(&resolver, &BuildOrderResolver::resolvingFailed, &application, &QCoreApplication::quit);
|
|
||||||
// run Qt loop
|
|
||||||
return application.exec();
|
|
||||||
//BuildOrderResolver::printResults(resolver.resolve(configArgs.buildOrderArg.values()));
|
//BuildOrderResolver::printResults(resolver.resolve(configArgs.buildOrderArg.values()));
|
||||||
} else if(configArgs.mingwBundleArg.isPresent()) {
|
} else if(configArgs.mingwBundleArg.isPresent()) {
|
||||||
MingwBundle bundle(manager, configArgs.mingwBundleArg.values(), configArgs.iconThemesArg.values(), configArgs.extraPackagesArg.values());
|
MingwBundle bundle(manager, configArgs.mingwBundleArg.values(), configArgs.iconThemesArg.values(), configArgs.extraPackagesArg.values());
|
||||||
|
|
|
@ -4,7 +4,7 @@ appname = "Repository Index"
|
||||||
appauthor = Martchus
|
appauthor = Martchus
|
||||||
appurl = "https://github.com/$${appauthor}/$${projectname}"
|
appurl = "https://github.com/$${appauthor}/$${projectname}"
|
||||||
QMAKE_TARGET_DESCRIPTION = "Provides a web interface to browse Arch Linux package repositories."
|
QMAKE_TARGET_DESCRIPTION = "Provides a web interface to browse Arch Linux package repositories."
|
||||||
VERSION = 1.0.0
|
VERSION = 0.0.1
|
||||||
|
|
||||||
# include ../../common.pri when building as part of a subdirs project; otherwise include general.pri
|
# include ../../common.pri when building as part of a subdirs project; otherwise include general.pri
|
||||||
!include(../../common.pri) {
|
!include(../../common.pri) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ span.glyphicon {
|
||||||
background-color: #f9f9db!important;
|
background-color: #f9f9db!important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
#info_container th, #info_container td {
|
.info-container th, .info-container td {
|
||||||
border: none!important;
|
border: none!important;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
@ -95,10 +95,10 @@ span.glyphicon {
|
||||||
/*
|
/*
|
||||||
* Package info
|
* Package info
|
||||||
*/
|
*/
|
||||||
#info_container {
|
.info-container {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
#info_container {
|
.info-container {
|
||||||
float: none;
|
float: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,13 @@ span.glyphicon {
|
||||||
.file-tree ul ul {
|
.file-tree ul ul {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
#multi_package_info_container > div {
|
||||||
|
float: left;
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
#packages_info {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tree
|
* Tree
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
<li id="nav_packages" class="active"><a href="#packages">Packages <span class="sr-only">(current)</span></a></li>
|
<li id="nav_packages" class="active"><a href="#packages">Packages <span class="sr-only">(current)</span></a></li>
|
||||||
<li id="nav_groups"><a href="#groups">Groups</a></li>
|
<li id="nav_groups"><a href="#groups">Groups</a></li>
|
||||||
<li id="nav_repositories"><a href="#repositories">Repositories</a></li>
|
<li id="nav_repositories"><a href="#repositories">Repositories</a></li>
|
||||||
<li id="nav_settings"><a id="link_settings" href="#" aria-label="Settings" data-toggle="popover" data-placement="bottom" title="Settings" data-content="TODO"><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span></a></li>
|
<li id="nav_settings"><a id="link_settings" href="#" onclick="return false;" aria-label="Settings" data-toggle="popover" data-placement="bottom" title="Settings" data-content="TODO"><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span></a></li>
|
||||||
<li id="nav_about"><a id="link_settings" href="#" onclick="$('#dlg_about').modal('show'); return false;"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></a></li>
|
<li id="nav_about"><a id="link_settings" href="#" onclick="$('#dlg_about').modal('show'); return false;"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<form class="navbar-form navbar-left" target="#" onsubmit="repoindex.pageManager.applySearchTerm(this.searchtermInput.value, this.searchtermExact.checked, true); return false;">
|
<form class="navbar-form navbar-left" target="#" onsubmit="repoindex.pageManager.applySearchTerm(this.searchtermInput.value, this.searchtermExact.checked, true); return false;">
|
||||||
|
@ -112,6 +112,7 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- begin of packages page -->
|
<!-- begin of packages page -->
|
||||||
<div id="page_packages" class="row">
|
<div id="page_packages" class="row">
|
||||||
|
<div id="multi_package_info_container"><!-- package info panel generated by JavaScript --></div>
|
||||||
<!-- left column -->
|
<!-- left column -->
|
||||||
<div id="left_column_container_packages">
|
<div id="left_column_container_packages">
|
||||||
<!-- package list -->
|
<!-- package list -->
|
||||||
|
@ -138,25 +139,8 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- right column -->
|
<!-- right column -->
|
||||||
<div id="right_column_container_packages">
|
<div id="right_column_container_packages">
|
||||||
<!-- package info -->
|
<!-- package info container (right column) -->
|
||||||
<div id="info_container" class="panel panel-default">
|
<div id="single_package_info_container"><!-- package info panel generated by JavaScript --></div>
|
||||||
<div class="panel-heading">
|
|
||||||
Package info
|
|
||||||
<button type="button" class="close" onclick="repoindex.pageManager.hidePackageInfo();" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<!-- package info table (stub) -->
|
|
||||||
<table class="table">
|
|
||||||
<colgroup>
|
|
||||||
<col style="width:30%">
|
|
||||||
<col style="width:70%">
|
|
||||||
</colgroup>
|
|
||||||
<tbody id="pkg_tbody"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- begin of groups page -->
|
<!-- begin of groups page -->
|
||||||
|
@ -195,24 +179,8 @@
|
||||||
<nav class="pagination-nav"><ul class="pagination pagination-sm" id="repos_pagination"><!-- generated by JavaScript --></ul></nav>
|
<nav class="pagination-nav"><ul class="pagination pagination-sm" id="repos_pagination"><!-- generated by JavaScript --></ul></nav>
|
||||||
</div>
|
</div>
|
||||||
<div id="right_column_container_repos">
|
<div id="right_column_container_repos">
|
||||||
<div id="info_container" class="panel panel-default">
|
<!-- repo info container (right column) -->
|
||||||
<div class="panel-heading">
|
<div id="single_repo_info_container"><!-- repo info panel generated by JavaScript --></div>
|
||||||
Repository info
|
|
||||||
<button type="button" class="close" onclick="repoindex.pageManager.hideRepoInfo();" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<!-- repo info table (stub) -->
|
|
||||||
<table class="table">
|
|
||||||
<colgroup>
|
|
||||||
<col style="width:30%">
|
|
||||||
<col style="width:70%">
|
|
||||||
</colgroup>
|
|
||||||
<tbody id="repo_tbody"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -261,7 +229,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" style="text-align: center;">
|
<div class="modal-body" style="text-align: center;">
|
||||||
<h2>Repository Index</h2>
|
<h2>Repository Index</h2>
|
||||||
<p>1.0.0</p>
|
<p>@META_APP_VERSION_STR@</p>
|
||||||
<p style="margin: 25px 0px;">
|
<p style="margin: 25px 0px;">
|
||||||
<em>Tool to browse Arch Linux repositories.</em><br>
|
<em>Tool to browse Arch Linux repositories.</em><br>
|
||||||
<a href="https://github.com/Martchus/" onclick="window.open(this.href); return false;">Project website</a>
|
<a href="https://github.com/Martchus/" onclick="window.open(this.href); return false;">Project website</a>
|
||||||
|
|
|
@ -120,12 +120,16 @@
|
||||||
// check whether specified entry index is valid
|
// check whether specified entry index is valid
|
||||||
var entry = this.entryByIndex(entryIndex);
|
var entry = this.entryByIndex(entryIndex);
|
||||||
if(entry) {
|
if(entry) {
|
||||||
// show properties in "Package info" box
|
// show properties
|
||||||
var setProperties = function() {
|
var setProperties = function() {
|
||||||
|
// -> find info container and make info table
|
||||||
|
var infoContainer = document.getElementById("single_package_info_container");
|
||||||
|
infoContainer.wipeChildren();
|
||||||
|
var infoTable = repoindex.makeInfoTable();
|
||||||
|
var tb = infoTable.tbodyElement;
|
||||||
|
|
||||||
// -> basic package info
|
// -> basic package info
|
||||||
var basics = entry.info.basics ? entry.info.basics : {};
|
var basics = entry.info.basics ? entry.info.basics : {};
|
||||||
var tb = document.getElementById("pkg_tbody");
|
|
||||||
tb.wipeChildren();
|
|
||||||
repoindex.addPackageNames(tb, "Name", [entry.name]);
|
repoindex.addPackageNames(tb, "Name", [entry.name]);
|
||||||
switch(entry.info.repo) {
|
switch(entry.info.repo) {
|
||||||
case "AUR":
|
case "AUR":
|
||||||
|
@ -197,6 +201,11 @@
|
||||||
downloadElement.appendChild(spanElement);
|
downloadElement.appendChild(spanElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -> make info panel
|
||||||
|
var infoPanel = repoindex.makeInfoPanel("Package info", repoindex.bind(repoindex.pageManager, repoindex.pageManager.hidePackageInfo));
|
||||||
|
infoPanel.bodyElement.appendChild(infoTable.tableElement);
|
||||||
|
infoContainer.appendChild(infoPanel.element);
|
||||||
};
|
};
|
||||||
setProperties();
|
setProperties();
|
||||||
if(!entry.info.basics || !entry.info.details) {
|
if(!entry.info.basics || !entry.info.details) {
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
this.rightColumnContainerPackages = document.getElementById("right_column_container_packages");
|
this.rightColumnContainerPackages = document.getElementById("right_column_container_packages");
|
||||||
this.leftColumnContainerRepos = document.getElementById("left_column_container_repos");
|
this.leftColumnContainerRepos = document.getElementById("left_column_container_repos");
|
||||||
this.rightColumnContainerRepos = document.getElementById("right_column_container_repos");
|
this.rightColumnContainerRepos = document.getElementById("right_column_container_repos");
|
||||||
|
this.packageInfoContainer = document.getElementById("container_package_info");
|
||||||
|
|
||||||
// provide a function to add an error message (shown in red box)
|
// provide a function to add an error message (shown in red box)
|
||||||
this.addError = function(msg) {
|
this.addError = function(msg) {
|
||||||
|
@ -281,14 +282,14 @@
|
||||||
this.setPage(repoindex.Pages.Packages);
|
this.setPage(repoindex.Pages.Packages);
|
||||||
// ensure right column is visible
|
// ensure right column is visible
|
||||||
this.showRightColumn(this.leftColumnContainerPackages, this.rightColumnContainerPackages);
|
this.showRightColumn(this.leftColumnContainerPackages, this.rightColumnContainerPackages);
|
||||||
var tb = document.getElementById("pkg_tbody");
|
//var tb = document.getElementById("pkg_tbody");
|
||||||
if(tb.lastChild) {
|
//if(tb.lastChild) {
|
||||||
if(scroll && !checkVisibility(tb.lastChild)) {
|
// if(scroll && !checkVisibility(tb.lastChild)) {
|
||||||
$('html, body').animate({
|
// $('html, body').animate({
|
||||||
scrollTop: $("#" + this.rightColumnContainerPackages.id).offset().top
|
// scrollTop: $("#" + this.rightColumnContainerPackages.id).offset().top
|
||||||
}, 500);
|
// }, 500);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.hideRepoInfo = function() {
|
this.hideRepoInfo = function() {
|
||||||
|
|
|
@ -180,9 +180,13 @@
|
||||||
this.showRepoInfoForIndex = function(entryIndex) {
|
this.showRepoInfoForIndex = function(entryIndex) {
|
||||||
var entry = this.entryByIndex(entryIndex);
|
var entry = this.entryByIndex(entryIndex);
|
||||||
if(entry) {
|
if(entry) {
|
||||||
|
// -> find info container and make info table
|
||||||
|
var infoContainer = document.getElementById("single_repo_info_container");
|
||||||
|
infoContainer.wipeChildren();
|
||||||
|
var infoTable = repoindex.makeInfoTable();
|
||||||
|
var tb = infoTable.tbodyElement;
|
||||||
|
|
||||||
var info = entry.info;
|
var info = entry.info;
|
||||||
var tb = document.getElementById("repo_tbody");
|
|
||||||
tb.wipeChildren();
|
|
||||||
repoindex.addField(tb, "Name", repoindex.makeStr(entry.name));
|
repoindex.addField(tb, "Name", repoindex.makeStr(entry.name));
|
||||||
repoindex.addField(tb, "Description", repoindex.makeStr(info.desc));
|
repoindex.addField(tb, "Description", repoindex.makeStr(info.desc));
|
||||||
repoindex.addField(tb, "Package count", repoindex.makeStr(info.packageCount));
|
repoindex.addField(tb, "Package count", repoindex.makeStr(info.packageCount));
|
||||||
|
@ -199,6 +203,11 @@
|
||||||
this.currentInfo = info;
|
this.currentInfo = info;
|
||||||
// ensures, that the "Package Info" box (with the properties just set) is shown
|
// ensures, that the "Package Info" box (with the properties just set) is shown
|
||||||
repoindex.pageManager.showRepoInfo();
|
repoindex.pageManager.showRepoInfo();
|
||||||
|
|
||||||
|
// -> make info panel
|
||||||
|
var infoPanel = repoindex.makeInfoPanel("Repository info", repoindex.bind(repoindex.pageManager, repoindex.pageManager.hideRepoInfo));
|
||||||
|
infoPanel.bodyElement.appendChild(infoTable.tableElement);
|
||||||
|
infoContainer.appendChild(infoPanel.element);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -301,6 +301,67 @@
|
||||||
repoindex.setPackageNames(repoindex.addField(element, fieldName), packageNames, pageName);
|
repoindex.setPackageNames(repoindex.addField(element, fieldName), packageNames, pageName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
repoindex.makeInfoPanel = function(headingText, closeFunc) {
|
||||||
|
var panelElement = document.createElement("div");
|
||||||
|
panelElement.className = "panel panel-default info-container";
|
||||||
|
var panelHeadingElement = document.createElement("div");
|
||||||
|
panelHeadingElement.className = "panel-heading";
|
||||||
|
panelHeadingElement.appendChild(document.createTextNode(headingText));
|
||||||
|
var closeButton = document.createElement("button");
|
||||||
|
closeButton.setAttribute("type", "button");
|
||||||
|
closeButton.setAttribute("class", "close");
|
||||||
|
closeButton.setAttribute("aria-label", "Close");
|
||||||
|
closeButton.onclick = function() {
|
||||||
|
if(panelElement.parentNode) {
|
||||||
|
panelElement.parentNode.removeChild(panelElement);
|
||||||
|
if(closeFunc) {
|
||||||
|
closeFunc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var closeButtonSpan = document.createElement("span");
|
||||||
|
closeButtonSpan.setAttribute("aria-hidden", "true");
|
||||||
|
closeButtonSpan.appendChild(document.createTextNode("\u00D7"));
|
||||||
|
closeButton.appendChild(closeButtonSpan);
|
||||||
|
panelHeadingElement.appendChild(closeButton);
|
||||||
|
panelElement.appendChild(panelHeadingElement);
|
||||||
|
var panelBodyElement = document.createElement("div");
|
||||||
|
panelBodyElement.className = "panel-body";
|
||||||
|
panelElement.appendChild(panelBodyElement);
|
||||||
|
return {
|
||||||
|
element: panelElement,
|
||||||
|
headingElement: panelHeadingElement,
|
||||||
|
bodyElement: panelBodyElement
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
repoindex.makeColumnGroup = function(columnWidths) {
|
||||||
|
var colgroupElement = document.createElement("colgroup");
|
||||||
|
for(var i = 0; i < columnWidths.length; ++i) {
|
||||||
|
var colElement = document.createElement("col");
|
||||||
|
colElement.setAttribute("style", "width:" + columnWidths[i]);
|
||||||
|
colgroupElement.appendChild(colElement);
|
||||||
|
}
|
||||||
|
return colgroupElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
repoindex.makeInfoTable = function() {
|
||||||
|
var tableElement = document.createElement("table");
|
||||||
|
tableElement.appendChild(repoindex.makeColumnGroup(["30%", "70%"]));
|
||||||
|
var tbodyElement = document.createElement("tbody");
|
||||||
|
tableElement.appendChild(tbodyElement);
|
||||||
|
return {
|
||||||
|
tableElement: tableElement,
|
||||||
|
tbodyElement: tbodyElement
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
repoindex.bind = function(obj, func, args) {
|
||||||
|
return function() {
|
||||||
|
func.call(obj, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return repoindex;
|
return repoindex;
|
||||||
|
|
||||||
})(repoindex || {});
|
})(repoindex || {});
|
||||||
|
|
Loading…
Reference in New Issue