summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/metadatajob.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/installer/metadatajob.cpp')
-rw-r--r--src/libs/installer/metadatajob.cpp275
1 files changed, 221 insertions, 54 deletions
diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp
index b88f71137..0c674e313 100644
--- a/src/libs/installer/metadatajob.cpp
+++ b/src/libs/installer/metadatajob.cpp
@@ -34,6 +34,7 @@
#include "proxycredentialsdialog.h"
#include "serverauthenticationdialog.h"
#include "settings.h"
+#include "testrepository.h"
#include <QTemporaryDir>
@@ -48,17 +49,19 @@ static QUrl resolveUrl(const FileTaskResult &result, const QString &url)
}
MetadataJob::MetadataJob(QObject *parent)
- : KDJob(parent)
+ : Job(parent)
, m_core(0)
+ , m_addCompressedPackages(false)
{
setCapabilities(Cancelable);
- connect(&m_xmlTask, SIGNAL(finished()), this, SLOT(xmlTaskFinished()));
- connect(&m_metadataTask, SIGNAL(finished()), this, SLOT(metadataTaskFinished()));
- connect(&m_metadataTask, SIGNAL(progressValueChanged(int)), this, SLOT(progressChanged(int)));
+ connect(&m_xmlTask, &QFutureWatcherBase::finished, this, &MetadataJob::xmlTaskFinished);
+ connect(&m_metadataTask, &QFutureWatcherBase::finished, this, &MetadataJob::metadataTaskFinished);
+ connect(&m_metadataTask, &QFutureWatcherBase::progressValueChanged, this, &MetadataJob::progressChanged);
}
MetadataJob::~MetadataJob()
{
+ resetCompressedFetch();
reset();
}
@@ -72,46 +75,183 @@ Repository MetadataJob::repositoryForDirectory(const QString &directory) const
void MetadataJob::doStart()
{
- reset();
if (!m_core) {
- emitFinishedWithError(KDJob::Canceled, tr("Missing package manager core engine."));
+ emitFinishedWithError(Job::Canceled, tr("Missing package manager core engine."));
return; // We can't do anything here without core, so avoid tons of !m_core checks.
}
-
- emit infoMessage(this, tr("Preparing meta information download..."));
- const bool onlineInstaller = m_core->isInstaller() && !m_core->isOfflineOnly();
- if (onlineInstaller || (m_core->isUpdater() || m_core->isPackageManager())) {
- QList<FileTaskItem> items;
- const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance();
- foreach (const Repository &repo, m_core->settings().repositories()) {
- if (repo.isEnabled() && productKeyCheck->isValidRepository(repo)) {
- QAuthenticator authenticator;
- authenticator.setUser(repo.username());
- authenticator.setPassword(repo.password());
-
- QString url = repo.url().toString() + QLatin1String("/Updates.xml?");
- if (!m_core->value(QLatin1String("UrlQueryString")).isEmpty())
- url += m_core->value(QLatin1String("UrlQueryString")) + QLatin1Char('&');
-
- // also append a random string to avoid proxy caches
- FileTaskItem item(url.append(QString::number(qrand() * qrand())));
- item.insert(TaskRole::UserRole, QVariant::fromValue(repo));
- item.insert(TaskRole::Authenticator, QVariant::fromValue(authenticator));
- items.append(item);
+ const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance();
+ if (!m_addCompressedPackages) {
+ reset();
+ emit infoMessage(this, tr("Preparing meta information download..."));
+ const bool onlineInstaller = m_core->isInstaller() && !m_core->isOfflineOnly();
+
+ if (onlineInstaller || m_core->isMaintainer()) {
+ QList<FileTaskItem> items;
+ foreach (const Repository &repo, m_core->settings().repositories()) {
+ if (repo.isEnabled() &&
+ productKeyCheck->isValidRepository(repo)) {
+ QAuthenticator authenticator;
+ authenticator.setUser(repo.username());
+ authenticator.setPassword(repo.password());
+
+ if (!repo.isCompressed()) {
+ QString url = repo.url().toString() + QLatin1String("/Updates.xml?");
+ if (!m_core->value(scUrlQueryString).isEmpty())
+ url += m_core->value(scUrlQueryString) + QLatin1Char('&');
+
+ // also append a random string to avoid proxy caches
+ FileTaskItem item(url.append(QString::number(qrand() * qrand())));
+ item.insert(TaskRole::UserRole, QVariant::fromValue(repo));
+ item.insert(TaskRole::Authenticator, QVariant::fromValue(authenticator));
+ items.append(item);
+ }
+ else {
+ qDebug() << "Trying to parse compressed repo as normal repository."\
+ "Check repository syntax.";
+ }
+ }
}
+ if (items.count() > 0) {
+ startXMLTask(items);
+ } else {
+ emitFinished();
+ }
+ } else {
+ emitFinished();
}
- DownloadFileTask *const xmlTask = new DownloadFileTask(items);
- xmlTask->setProxyFactory(m_core->proxyFactory());
- m_xmlTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, xmlTask));
} else {
- emitFinished();
+ resetCompressedFetch();
+
+ bool repositoriesFound = false;
+ foreach (const Repository &repo, m_core->settings().temporaryRepositories()) {
+ if (repo.isCompressed() && repo.isEnabled() &&
+ productKeyCheck->isValidRepository(repo)) {
+ repositoriesFound = true;
+ startUnzipRepositoryTask(repo);
+
+ //Set the repository disabled so we don't handle it many times
+ Repository replacement = repo;
+ replacement.setEnabled(false);
+ Settings &s = m_core->settings();
+ QSet<Repository> temporaries = s.temporaryRepositories();
+ if (temporaries.contains(repo)) {
+ temporaries.remove(repo);
+ temporaries.insert(replacement);
+ s.setTemporaryRepositories(temporaries, true);
+ }
+ }
+ }
+ if (!repositoriesFound) {
+ emitFinished();
+ }
+ else {
+ setProgressTotalAmount(0);
+ emit infoMessage(this, tr("Unpacking compressed repositories. This may take a while..."));
+ }
}
}
+void MetadataJob::startXMLTask(const QList<FileTaskItem> items)
+{
+ DownloadFileTask *const xmlTask = new DownloadFileTask(items);
+ xmlTask->setProxyFactory(m_core->proxyFactory());
+ m_xmlTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, xmlTask));
+}
+
void MetadataJob::doCancel()
{
reset();
- emitFinishedWithError(KDJob::Canceled, tr("Meta data download canceled."));
+ emitFinishedWithError(Job::Canceled, tr("Meta data download canceled."));
+}
+
+void MetadataJob::startUnzipRepositoryTask(const Repository &repo)
+{
+ QTemporaryDir tempRepoDir(QDir::tempPath() + QLatin1String("/compressedRepo-XXXXXX"));
+ if (!tempRepoDir.isValid()) {
+ qDebug() << "Cannot create unique temporary directory.";
+ return;
+ }
+ tempRepoDir.setAutoRemove(false);
+ m_tempDirDeleter.add(tempRepoDir.path());
+ QString url = repo.url().toLocalFile();
+ UnzipArchiveTask *task = new UnzipArchiveTask(url, tempRepoDir.path());
+ QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
+ m_unzipRepositoryTasks.insert(watcher, qobject_cast<QObject*> (task));
+ connect(watcher, &QFutureWatcherBase::finished, this,
+ &MetadataJob::unzipRepositoryTaskFinished);
+ connect(watcher, &QFutureWatcherBase::progressValueChanged, this,
+ &MetadataJob::progressChanged);
+ watcher->setFuture(QtConcurrent::run(&UnzipArchiveTask::doTask, task));
+}
+
+void MetadataJob::unzipRepositoryTaskFinished()
+{
+ QFutureWatcher<void> *watcher = static_cast<QFutureWatcher<void> *>(sender());
+ int error = Job::NoError;
+ QString errorString;
+ try {
+ watcher->waitForFinished(); // trigger possible exceptions
+
+ QHashIterator<QFutureWatcher<void> *, QObject*> i(m_unzipRepositoryTasks);
+ while (i.hasNext()) {
+
+ i.next();
+ if (i.key() == watcher) {
+ UnzipArchiveTask *task = qobject_cast<UnzipArchiveTask*> (i.value());
+ QString url = task->target();
+
+ QUrl targetUrl = targetUrl.fromLocalFile(url);
+ Repository repo(targetUrl, false, true);
+ url = repo.url().toString() + QLatin1String("/Updates.xml");
+ TestRepository testJob(m_core);
+ testJob.setRepository(repo);
+ testJob.start();
+ testJob.waitForFinished();
+ error = testJob.error();
+ errorString = testJob.errorString();
+ if (error == Job::NoError) {
+ FileTaskItem item(url);
+ item.insert(TaskRole::UserRole, QVariant::fromValue(repo));
+ m_unzipRepositoryitems.append(item);
+ } else {
+ //Repository is not valid, remove it
+ Repository repository;
+ repository.setUrl(QUrl(task->archive()));
+ Settings &s = m_core->settings();
+ QSet<Repository> temporaries = s.temporaryRepositories();
+ foreach (Repository repository, temporaries) {
+ if (repository.url().toLocalFile() == task->archive()) {
+ temporaries.remove(repository);
+ }
+ }
+ s.setTemporaryRepositories(temporaries, false);
+ }
+ }
+ }
+ delete m_unzipRepositoryTasks.value(watcher);
+ m_unzipRepositoryTasks.remove(watcher);
+ delete watcher;
+
+ //One can specify many zipped repository items at once. As the repositories are
+ //unzipped one by one, we collect here all items before parsing xml files from those.
+ if (m_unzipRepositoryitems.count() > 0 && m_unzipRepositoryTasks.isEmpty()) {
+ startXMLTask(m_unzipRepositoryitems);
+ } else {
+ if (error != Job::NoError) {
+ emitFinishedWithError(QInstaller::DownloadError, errorString);
+ }
+ }
+
+ } catch (const UnzipArchiveException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::ExtractionError, e.message());
+ } catch (const QUnhandledException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what()));
+ } catch (...) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during extracting."));
+ }
}
void MetadataJob::xmlTaskFinished()
@@ -124,7 +264,7 @@ void MetadataJob::xmlTaskFinished()
if (e.type() == AuthenticationRequiredException::Type::Proxy) {
const QNetworkProxy proxy = e.proxy();
ProxyCredentialsDialog proxyCredentials(proxy);
- qDebug() << e.message();
+ qDebug().noquote() << e.message();
if (proxyCredentials.exec() == QDialog::Accepted) {
qDebug() << "Retrying with new credentials ...";
@@ -139,7 +279,7 @@ void MetadataJob::xmlTaskFinished()
emitFinishedWithError(QInstaller::DownloadError, tr("Missing proxy credentials."));
}
} else if (e.type() == AuthenticationRequiredException::Type::Server) {
- qDebug() << e.message();
+ qDebug().noquote() << e.message();
ServerAuthenticationDialog dlg(e.message(), e.taskItem());
if (dlg.exec() == QDialog::Accepted) {
Repository original = e.taskItem().value(TaskRole::UserRole)
@@ -160,7 +300,7 @@ void MetadataJob::xmlTaskFinished()
if (s.updateDefaultRepositories(update) == Settings::UpdatesApplied
|| s.updateUserRepositories(update) == Settings::UpdatesApplied) {
- if (m_core->isUpdater() || m_core->isPackageManager())
+ if (m_core->isMaintainer())
m_core->writeMaintenanceConfigFiles();
}
}
@@ -181,7 +321,7 @@ void MetadataJob::xmlTaskFinished()
emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during download."));
}
- if (error() != KDJob::NoError)
+ if (error() != Job::NoError)
return;
if (status == XmlDownloadSuccess) {
@@ -189,6 +329,7 @@ void MetadataJob::xmlTaskFinished()
DownloadFileTask *const metadataTask = new DownloadFileTask(m_packages);
metadataTask->setProxyFactory(m_core->proxyFactory());
m_metadataTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, metadataTask));
+ setProgressTotalAmount(100);
emit infoMessage(this, tr("Retrieving meta information from remote repository..."));
} else if (status == XmlDownloadRetry) {
QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
@@ -204,17 +345,14 @@ void MetadataJob::unzipTaskFinished()
try {
watcher->waitForFinished(); // trigger possible exceptions
} catch (const UnzipArchiveException &e) {
- reset();
emitFinishedWithError(QInstaller::ExtractionError, e.message());
} catch (const QUnhandledException &e) {
- reset();
emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what()));
} catch (...) {
- reset();
emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during extracting."));
}
- if (error() != KDJob::NoError)
+ if (error() != Job::NoError)
return;
delete m_unzipTasks.value(watcher);
@@ -232,6 +370,11 @@ void MetadataJob::progressChanged(int progress)
setProcessedAmount(progress);
}
+void MetadataJob::setProgressTotalAmount(int maximum)
+{
+ setTotalAmount(maximum);
+}
+
void MetadataJob::metadataTaskFinished()
{
try {
@@ -246,7 +389,7 @@ void MetadataJob::metadataTaskFinished()
QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
m_unzipTasks.insert(watcher, qobject_cast<QObject*> (task));
- connect(watcher, SIGNAL(finished()), this, SLOT(unzipTaskFinished()));
+ connect(watcher, &QFutureWatcherBase::finished, this, &MetadataJob::unzipTaskFinished);
watcher->setFuture(QtConcurrent::run(&UnzipArchiveTask::doTask, task));
}
} else {
@@ -272,13 +415,24 @@ void MetadataJob::reset()
m_packages.clear();
m_metadata.clear();
- setError(KDJob::NoError);
+ setError(Job::NoError);
setErrorString(QString());
setCapabilities(Cancelable);
try {
m_xmlTask.cancel();
m_metadataTask.cancel();
+ } catch (...) {}
+ m_tempDirDeleter.releaseAndDeleteAll();
+}
+
+void MetadataJob::resetCompressedFetch()
+{
+ setError(Job::NoError);
+ setErrorString(QString());
+ m_unzipRepositoryitems.clear();
+
+ try {
foreach (QFutureWatcher<void> *const watcher, m_unzipTasks.keys()) {
watcher->cancel();
watcher->deleteLater();
@@ -286,20 +440,32 @@ void MetadataJob::reset()
foreach (QObject *const object, m_unzipTasks)
object->deleteLater();
m_unzipTasks.clear();
+
+ foreach (QFutureWatcher<void> *const watcher, m_unzipRepositoryTasks.keys()) {
+ watcher->cancel();
+ watcher->deleteLater();
+ }
+ foreach (QObject *const object, m_unzipRepositoryTasks)
+ object->deleteLater();
+ m_unzipRepositoryTasks.clear();
} catch (...) {}
- m_tempDirDeleter.releaseAndDeleteAll();
}
MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &results)
{
foreach (const FileTaskResult &result, results) {
- if (error() != KDJob::NoError)
+ if (error() != Job::NoError)
return XmlDownloadFailure;
+ //If repository is not found, target might be empty. Do not continue parsing the
+ //repository and do not prevent further repositories usage.
+ if (result.target().isEmpty()) {
+ continue;
+ }
Metadata metadata;
QTemporaryDir tmp(QDir::tempPath() + QLatin1String("/remoterepo-XXXXXX"));
if (!tmp.isValid()) {
- qDebug() << "Could not create unique temporary directory.";
+ qDebug() << "Cannot create unique temporary directory.";
return XmlDownloadFailure;
}
@@ -309,21 +475,22 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
QFile file(result.target());
if (!file.rename(metadata.directory + QLatin1String("/Updates.xml"))) {
- qDebug() << "Could not rename target to Updates.xml. Error:" << file.errorString();
+ qDebug() << "Cannot rename target to Updates.xml:" << file.errorString();
return XmlDownloadFailure;
}
if (!file.open(QIODevice::ReadOnly)) {
- qDebug() << "Could not open Updates.xml for reading. Error:" << file.errorString();
+ qDebug() << "Cannot open Updates.xml for reading:" << file.errorString();
return XmlDownloadFailure;
}
QString error;
QDomDocument doc;
if (!doc.setContent(&file, &error)) {
- qDebug() << QString::fromLatin1("Could not fetch a valid version of Updates.xml from "
- "repository: %1. Error: %2").arg(metadata.repository.displayname(), error);
- return XmlDownloadFailure;
+ qDebug().nospace() << "Cannot fetch a valid version of Updates.xml from repository "
+ << metadata.repository.displayname() << ": " << error;
+ //If there are other repositories, try to use those
+ continue;
}
file.close();
@@ -346,7 +513,7 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
for (int j = 0; j < c2.count(); ++j) {
if (c2.at(j).toElement().tagName() == scName)
packageName = c2.at(j).toElement().text();
- else if (c2.at(j).toElement().tagName() == scRemoteVersion)
+ else if (c2.at(j).toElement().tagName() == scVersion)
packageVersion = (online ? c2.at(j).toElement().text() : QString());
else if ((c2.at(j).toElement().tagName() == QLatin1String("SHA1")) && testCheckSum)
packageHash = c2.at(j).toElement().text();
@@ -408,12 +575,12 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
if (ProductKeyCheck::instance()->isValidRepository(newRepository)) {
// store the new repository and the one old it replaces
repositoryUpdates.insertMulti(action, qMakePair(newRepository, oldRepository));
- qDebug() << "Replace repository:" << oldRepository.displayname() << "with:"
+ qDebug() << "Replace repository" << oldRepository.displayname() << "with"
<< newRepository.displayname();
}
} else {
qDebug() << "Invalid additional repositories action set in Updates.xml fetched "
- "from:" << metadata.repository.displayname() << "Line:" << el.lineNumber();
+ "from" << metadata.repository.displayname() << "line:" << el.lineNumber();
}
}
}
@@ -441,7 +608,7 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
return XmlDownloadRetry;
}
} else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) {
- if (m_core->isUpdater() || m_core->isPackageManager())
+ if (m_core->isMaintainer())
m_core->writeMaintenanceConfigFiles();
QFile::remove(result.target());
return XmlDownloadRetry;