Commit 9101a2d2 authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧
Browse files

appstream: support appstream uri alt ids

BUG: 416283
parent 2ff93844
......@@ -22,6 +22,7 @@
#include <QJsonArray>
#include <QJsonObject>
#include <QUrlQuery>
#include <QDebug>
#include "utils.h"
#include <KLocalizedString>
......@@ -104,7 +105,13 @@ QJsonArray AppStreamUtils::licenses(const AppStream::Component& appdata)
#endif
}
QString AppStreamUtils::appstreamId(const QUrl &appstreamUrl)
QStringList AppStreamUtils::appstreamIds(const QUrl &appstreamUrl)
{
return appstreamUrl.host().isEmpty() ? appstreamUrl.path() : appstreamUrl.host();
QStringList ret;
ret += appstreamUrl.host().isEmpty() ? appstreamUrl.path() : appstreamUrl.host();
if (appstreamUrl.hasQuery()) {
QUrlQuery query(appstreamUrl);
ret << query.queryItemValue(QStringLiteral("alt")).split(QLatin1Char(','), Qt::SkipEmptyParts);
}
return ret;
}
......@@ -36,7 +36,7 @@ Q_DECL_EXPORT QPair<QList<QUrl>, QList<QUrl>> fetchScreenshots(const AppStream::
Q_DECL_EXPORT QJsonArray licenses(const AppStream::Component &appdata);
Q_DECL_EXPORT QString appstreamId(const QUrl &appstreamUrl);
Q_DECL_EXPORT QStringList appstreamIds(const QUrl &appstreamUrl);
}
......
......@@ -1170,8 +1170,8 @@ ResultsStream * FlatpakBackend::search(const AbstractResourcesBackend::Filters &
auto stream = new ResultsStream(QStringLiteral("FlatpakStream"));
auto f = [this, stream, filter] () {
QVector<AbstractResource*> ret;
foreach(auto r, m_resources) {
const bool matchById = filter.search.compare(r->appstreamId(), Qt::CaseInsensitive) == 0;
for (auto r : qAsConst(m_resources)) {
const bool matchById = r->appstreamId().compare(filter.search, Qt::CaseInsensitive) == 0;
if (r->type() == AbstractResource::Technical && filter.state != AbstractResource::Upgradeable && !matchById) {
continue;
}
......@@ -1215,13 +1215,13 @@ QVector<AbstractResource *> FlatpakBackend::resourcesByAppstreamName(const QStri
ResultsStream * FlatpakBackend::findResourceByPackageName(const QUrl &url)
{
if (url.scheme() == QLatin1String("appstream")) {
const auto appstreamId = AppStreamUtils::appstreamId(url);
if (appstreamId.isEmpty())
const auto appstreamIds = AppStreamUtils::appstreamIds(url);
if (appstreamIds.isEmpty())
Q_EMIT passiveMessage(i18n("Malformed appstream url '%1'", url.toDisplayString()));
else {
auto stream = new ResultsStream(QStringLiteral("FlatpakStream"));
auto f = [this, stream, appstreamId] () {
const auto resources = resourcesByAppstreamName(appstreamId);
auto f = [this, stream, appstreamIds] () {
const auto resources = kAppend<QVector<AbstractResource*>>(appstreamIds, [this] (const QString appstreamId) { return resourcesByAppstreamName(appstreamId); });
if (!resources.isEmpty())
Q_EMIT stream->resourcesFound(resources);
stream->finish();
......
......@@ -527,18 +527,21 @@ ResultsStream * PackageKitBackend::findResourceByPackageName(const QUrl& url)
{ QStringLiteral("org.blender.blender.desktop"), QStringLiteral("blender.desktop") },
};
const auto appstreamId = AppStreamUtils::appstreamId(url);
if (appstreamId.isEmpty())
const auto appstreamIds = AppStreamUtils::appstreamIds(url);
if (appstreamIds.isEmpty())
Q_EMIT passiveMessage(i18n("Malformed appstream url '%1'", url.toDisplayString()));
else {
auto stream = new ResultsStream(QStringLiteral("PackageKitStream-appstream-url"));
const auto f = [this, appstreamId, stream] () {
const auto f = [this, appstreamIds, stream] () {
AbstractResource* pkg = nullptr;
const auto deprecatedHost = deprecatedAppstreamIds.value(appstreamId); //try this as fallback
const QStringList allAppStreamIds = appstreamIds + deprecatedAppstreamIds.values(appstreamIds.first());
for (auto it = m_packages.packages.constBegin(), itEnd = m_packages.packages.constEnd(); it != itEnd; ++it) {
if (it.key().compare(appstreamId, Qt::CaseInsensitive) == 0
|| it.key().compare(deprecatedHost, Qt::CaseInsensitive) == 0
|| (appstreamId.endsWith(QLatin1String(".desktop")) && appstreamId.compare(it.key()+QLatin1String(".desktop"), Qt::CaseInsensitive) == 0)) {
const bool matches = kContains(allAppStreamIds, [&it] (const QString& id) {
return it.key().compare(id, Qt::CaseInsensitive) == 0 ||
(id.endsWith(QLatin1String(".desktop")) && id.compare(it.key()+QLatin1String(".desktop"), Qt::CaseInsensitive) == 0);
});
if (matches) {
pkg = it.value();
break;
}
......
......@@ -109,63 +109,84 @@ ResultsStream * SnapBackend::search(const AbstractResourcesBackend::Filters& fil
ResultsStream * SnapBackend::findResourceByPackageName(const QUrl& search)
{
Q_ASSERT(!search.host().isEmpty() || !AppStreamUtils::appstreamId(search).isEmpty());
Q_ASSERT(!search.host().isEmpty() || !AppStreamUtils::appstreamIds(search).isEmpty());
return search.scheme() == QLatin1String("snap") ? populate(m_client.find(QSnapdClient::MatchName, search.host())) :
#ifdef SNAP_FIND_COMMON_ID
search.scheme() == QLatin1String("appstream") ? populate(m_client.find(QSnapdClient::MatchCommonId, AppStreamUtils::appstreamId(search))) :
search.scheme() == QLatin1String("appstream") ? populate(kTransform<QVector<QSnapdFindRequest*>>(AppStreamUtils::appstreamIds(search),
[this] (const QString &id) {return m_client.find(QSnapdClient::MatchCommonId, id); })) :
#endif
voidStream();
}
template <class T>
ResultsStream* SnapBackend::populate(T* snaps)
ResultsStream* SnapBackend::populate(T* job)
{
return populate<T>(QVector<T*>{job});
}
template <class T>
ResultsStream* SnapBackend::populate(const QVector<T*>& jobs)
{
std::function<bool(const QSharedPointer<QSnapdSnap>&)> acceptAll = [](const QSharedPointer<QSnapdSnap>&){ return true; };
return populateWithFilter(snaps, acceptAll);
return populateJobsWithFilter(jobs, acceptAll);
}
template <class T>
ResultsStream* SnapBackend::populateWithFilter(T* job, std::function<bool(const QSharedPointer<QSnapdSnap>& s)>& filter)
{
auto stream = new ResultsStream(QStringLiteral("Snap-populate"));
return populateJobsWithFilter<T>({job}, filter);
}
connect(job, &T::complete, stream, [stream, this, job, filter]() {
if (job->error()) {
qDebug() << "error:" << job->error() << job->errorString();
stream->finish();
return;
}
template <class T>
ResultsStream* SnapBackend::populateJobsWithFilter(const QVector<T*>& jobs, std::function<bool(const QSharedPointer<QSnapdSnap>& s)>& filter)
{
auto stream = new ResultsStream(QStringLiteral("Snap-populate"));
stream->setProperty("remaining", jobs.count());
for(auto job : jobs) {
connect(job, &T::complete, stream, [stream, this, job, filter]() {
const int remaining = stream->property("remaining").toInt() - 1;
stream->setProperty("remaining", remaining);
if (job->error()) {
qDebug() << "error:" << job->error() << job->errorString();
if (remaining == 0)
stream->finish();
return;
}
QVector<AbstractResource*> ret;
QVector<SnapResource*> resources;
ret.reserve(job->snapCount());
resources.reserve(job->snapCount());
for (int i=0, c=job->snapCount(); i<c; ++i) {
QSharedPointer<QSnapdSnap> snap(job->snap(i));
if (!filter(snap))
continue;
const auto snapname = snap->name();
SnapResource* res = m_resources.value(snapname);
if (!res) {
res = new SnapResource(snap, AbstractResource::None, this);
Q_ASSERT(res->packageName() == snapname);
resources += res;
} else {
res->setSnap(snap);
QVector<AbstractResource*> ret;
QVector<SnapResource*> resources;
ret.reserve(job->snapCount());
resources.reserve(job->snapCount());
for (int i=0, c=job->snapCount(); i<c; ++i) {
QSharedPointer<QSnapdSnap> snap(job->snap(i));
if (!filter(snap))
continue;
const auto snapname = snap->name();
SnapResource* res = m_resources.value(snapname);
if (!res) {
res = new SnapResource(snap, AbstractResource::None, this);
Q_ASSERT(res->packageName() == snapname);
resources += res;
} else {
res->setSnap(snap);
}
ret += res;
}
ret += res;
}
foreach(SnapResource* res, resources)
m_resources[res->packageName()] = res;
foreach(SnapResource* res, resources)
m_resources[res->packageName()] = res;
if (!ret.isEmpty())
Q_EMIT stream->resourcesFound(ret);
stream->finish();
});
job->runAsync();
if (!ret.isEmpty())
Q_EMIT stream->resourcesFound(ret);
if (remaining == 0)
stream->finish();
});
job->runAsync();
}
return stream;
}
......
......@@ -24,6 +24,7 @@
#include <resources/AbstractResource.h>
#include <resources/AbstractResourcesBackend.h>
#include <QVariantList>
#include <QVector>
#include <Snapd/Client>
#include <functional>
......@@ -61,9 +62,15 @@ private:
template <class T>
ResultsStream* populateWithFilter(T* snaps, std::function<bool(const QSharedPointer<QSnapdSnap>&)>& filter);
template <class T>
ResultsStream* populateJobsWithFilter(const QVector<T*>& snaps, std::function<bool(const QSharedPointer<QSnapdSnap>&)>& filter);
template <class T>
ResultsStream* populate(T* snaps);
template <class T>
ResultsStream* populate(const QVector<T*>& snaps);
QHash<QString, SnapResource*> m_resources;
StandardBackendUpdater* m_updater;
QSharedPointer<OdrsReviewsBackend> m_reviews;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment