diff options
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp')
-rw-r--r-- | src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp new file mode 100644 index 0000000000..4c3e5f5f1e --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp @@ -0,0 +1,193 @@ +/* + Copyright (C) 2016 Volker Krause <vkrause@kde.org> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "definitiondownloader.h" +#include "definition.h" +#include "repository.h" +#include "ksyntaxhighlighting_logging.h" +#include "ksyntaxhighlighting_version.h" + +#include <QDebug> +#include <QDir> +#include <QFile> +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QStandardPaths> +#include <QTimer> +#include <QXmlStreamReader> + +using namespace KSyntaxHighlighting; + +class KSyntaxHighlighting::DefinitionDownloaderPrivate +{ +public: + DefinitionDownloader *q; + Repository *repo; + QNetworkAccessManager *nam; + QString downloadLocation; + int pendingDownloads; + bool needsReload; + + void definitionListDownloadFinished(QNetworkReply *reply); + void updateDefinition(QXmlStreamReader &parser); + void downloadDefinition(const QUrl &url); + void downloadDefinitionFinished(QNetworkReply *reply); + void checkDone(); +}; + +void DefinitionDownloaderPrivate::definitionListDownloadFinished(QNetworkReply *reply) +{ + if (reply->error() != QNetworkReply::NoError) { + qCWarning(Log) << reply->error(); + emit q->done(); // TODO return error + return; + } + + QXmlStreamReader parser(reply); + while (!parser.atEnd()) { + switch (parser.readNext()) { + case QXmlStreamReader::StartElement: + if (parser.name() == QLatin1String("Definition")) + updateDefinition(parser); + break; + default: + break; + } + } + + if (pendingDownloads == 0) + emit q->informationMessage(QObject::tr("All syntax definitions are up-to-date.")); + checkDone(); +} + +void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser) +{ + const auto name = parser.attributes().value(QLatin1String("name")); + if (name.isEmpty()) + return; + + auto localDef = repo->definitionForName(name.toString()); + if (!localDef.isValid()) { + emit q->informationMessage(QObject::tr("Downloading new syntax definition for '%1'...").arg(name.toString())); + downloadDefinition(QUrl(parser.attributes().value(QLatin1String("url")).toString())); + return; + } + + const auto version = parser.attributes().value(QLatin1String("version")); + if (localDef.version() < version.toFloat()) { + emit q->informationMessage(QObject::tr("Updating syntax definition for '%1' to version %2...").arg(name.toString(), version.toString())); + downloadDefinition(QUrl(parser.attributes().value(QLatin1String("url")).toString())); + } +} + +void DefinitionDownloaderPrivate::downloadDefinition(const QUrl& downloadUrl) +{ + if (!downloadUrl.isValid()) + return; + auto url = downloadUrl; + if (url.scheme() == QLatin1String("http")) + url.setScheme(QStringLiteral("https")); + + QNetworkRequest req(url); + auto reply = nam->get(req); + QObject::connect(reply, &QNetworkReply::finished, q, [this, reply]() { + downloadDefinitionFinished(reply); + }); + ++pendingDownloads; + needsReload = true; +} + +void DefinitionDownloaderPrivate::downloadDefinitionFinished(QNetworkReply *reply) +{ + --pendingDownloads; + if (reply->error() != QNetworkReply::NoError) { + qCWarning(Log) << "Failed to download definition file" << reply->url() << reply->error(); + checkDone(); + return; + } + + // handle redirects + // needs to be done manually, download server redirects to unsafe http links + const auto redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + if (!redirectUrl.isEmpty()) { + downloadDefinition(reply->url().resolved(redirectUrl)); + checkDone(); + return; + } + + QFile file(downloadLocation + QLatin1Char('/') + reply->url().fileName()); + if (!file.open(QFile::WriteOnly)) { + qCWarning(Log) << "Failed to open" << file.fileName() << file.error(); + } else { + file.write(reply->readAll()); + } + checkDone(); +} + +void DefinitionDownloaderPrivate::checkDone() +{ + if (pendingDownloads == 0) { + if (needsReload) + repo->reload(); + + emit QTimer::singleShot(0, q, &DefinitionDownloader::done); + } +} + + +DefinitionDownloader::DefinitionDownloader(Repository *repo, QObject *parent) + : QObject(parent) + , d(new DefinitionDownloaderPrivate()) +{ + Q_ASSERT(repo); + + d->q = this; + d->repo = repo; + d->nam = new QNetworkAccessManager(this); + d->pendingDownloads = 0; + d->needsReload = false; + + d->downloadLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/org.kde.syntax-highlighting/syntax"); + QDir().mkpath(d->downloadLocation); + Q_ASSERT(QFile::exists(d->downloadLocation)); +} + +DefinitionDownloader::~DefinitionDownloader() +{ +} + +void DefinitionDownloader::start() +{ + const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + + QString::number(SyntaxHighlighting_VERSION_MAJOR) + + QLatin1Char('.') + + QString::number(SyntaxHighlighting_VERSION_MINOR) + + QLatin1String(".xml"); + auto req = QNetworkRequest(QUrl(url)); + req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + auto reply = d->nam->get(req); + QObject::connect(reply, &QNetworkReply::finished, this, [=]() { + d->definitionListDownloadFinished(reply); + }); +} |