diff options
-rw-r--r-- | src/libs/installer/metadatajob.cpp | 155 | ||||
-rw-r--r-- | src/libs/installer/metadatajob.h | 7 | ||||
-rw-r--r-- | src/libs/installer/metadatajob_p.h | 2 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 45 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.h | 7 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 94 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.h | 7 | ||||
-rw-r--r-- | src/libs/installer/packagemanagergui.cpp | 112 | ||||
-rw-r--r-- | src/libs/installer/packagemanagergui.h | 1 | ||||
-rw-r--r-- | src/libs/installer/repository.cpp | 35 | ||||
-rw-r--r-- | src/libs/installer/repository.h | 7 | ||||
-rw-r--r-- | src/libs/kdtools/task.cpp | 2 | ||||
-rw-r--r-- | src/libs/kdtools/updatefinder.cpp | 11 | ||||
-rw-r--r-- | src/libs/kdtools/updatefinder.h | 4 | ||||
-rw-r--r-- | src/sdk/commandlineparser.cpp | 5 | ||||
-rw-r--r-- | src/sdk/constants.h | 1 | ||||
-rw-r--r-- | src/sdk/installerbase.cpp | 8 |
17 files changed, 438 insertions, 65 deletions
diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp index b010209c3..b3301c761 100644 --- a/src/libs/installer/metadatajob.cpp +++ b/src/libs/installer/metadatajob.cpp @@ -55,6 +55,7 @@ static QUrl resolveUrl(const FileTaskResult &result, const QString &url) MetadataJob::MetadataJob(QObject *parent) : Job(parent) , m_core(0) + , m_addCompressedPackages(false) { setCapabilities(Cancelable); connect(&m_xmlTask, &QFutureWatcherBase::finished, this, &MetadataJob::xmlTaskFinished); @@ -77,48 +78,142 @@ Repository MetadataJob::repositoryForDirectory(const QString &directory) const void MetadataJob::doStart() { - reset(); if (!m_core) { 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->isMaintainer()) { - 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(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); + 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(); + m_packages.clear(); + bool repositoriesFound = false; + foreach (const Repository &repo, m_core->settings().repositories()) { + if (repo.isCompressed() && repo.isEnabled() && + productKeyCheck->isValidRepository(repo)) { + repositoriesFound = true; + startUnzipRepositoryTask(repo); + } + } + if (!repositoriesFound) + emitFinished(); + else + emit infoMessage(this, tr("Unpacking compressed repositories...")); } } +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(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()); + 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.")); + } + + 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"); + FileTaskItem item(url); + item.insert(TaskRole::UserRole, QVariant::fromValue(repo)); + m_unzipRepositoryitems.append(item); + } + } + + //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. + delete m_unzipRepositoryTasks.value(watcher); + m_unzipRepositoryTasks.remove(watcher); + delete watcher; + + if (m_unzipRepositoryitems.count() > 0 && m_unzipRepositoryTasks.isEmpty()) + startXMLTask(m_unzipRepositoryitems); +} + void MetadataJob::xmlTaskFinished() { Status status = XmlDownloadFailure; @@ -291,6 +386,14 @@ 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(); } diff --git a/src/libs/installer/metadatajob.h b/src/libs/installer/metadatajob.h index 10fffe172..e59029940 100644 --- a/src/libs/installer/metadatajob.h +++ b/src/libs/installer/metadatajob.h @@ -69,6 +69,7 @@ public: QList<Metadata> metadata() const { return m_metadata.values(); } Repository repositoryForDirectory(const QString &directory) const; void setPackageManagerCore(PackageManagerCore *core) { m_core = core; } + void addCompressedPackages(bool addCompressPackage) { m_addCompressedPackages = addCompressPackage;} private slots: void doStart(); @@ -78,8 +79,11 @@ private slots: void unzipTaskFinished(); void metadataTaskFinished(); void progressChanged(int progress); + void unzipRepositoryTaskFinished(); + void startXMLTask(const QList<FileTaskItem> items); private: + void startUnzipRepositoryTask(const Repository &repo); void reset(); Status parseUpdatesXml(const QList<FileTaskResult> &results); @@ -92,6 +96,9 @@ private: QFutureWatcher<FileTaskResult> m_xmlTask; QFutureWatcher<FileTaskResult> m_metadataTask; QHash<QFutureWatcher<void> *, QObject*> m_unzipTasks; + QHash<QFutureWatcher<void> *, QObject*> m_unzipRepositoryTasks; + bool m_addCompressedPackages; + QList<FileTaskItem> m_unzipRepositoryitems; }; } // namespace QInstaller diff --git a/src/libs/installer/metadatajob_p.h b/src/libs/installer/metadatajob_p.h index a07c7a80f..7839eacb5 100644 --- a/src/libs/installer/metadatajob_p.h +++ b/src/libs/installer/metadatajob_p.h @@ -69,7 +69,7 @@ public: UnzipArchiveTask(const QString &arcive, const QString &target) : m_archive(arcive), m_targetDir(target) {} - + QString target() { return m_targetDir; } void doTask(QFutureInterface<void> &fi) { fi.reportStarted(); diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 731171f61..971ca694d 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -1153,8 +1153,37 @@ PackagesList PackageManagerCore::remotePackages() } /*! + Checks for compressed packages to install. Returns \c true if newer versions exist + and they can be installed. +*/ +bool PackageManagerCore::fetchCompressedPackagesTree() +{ + const LocalPackagesHash installedPackages = d->localInstalledPackages(); + if (!isInstaller() && status() == Failure) + return false; + + if (!d->fetchMetaInformationFromCompressedRepositories()) + return false; + + if (!d->addUpdateResourcesFromRepositories(true, true)) { + return false; + } + + PackagesList packages; + const PackagesList &compPackages = d->compressedPackages(); + if (compPackages.isEmpty()) + return false; + packages.append(compPackages); + const PackagesList &rPackages = d->remotePackages(); + packages.append(rPackages); + + return fetchPackagesTree(packages, installedPackages); +} + + +/*! Checks for packages to install. Returns \c true if newer versions exist - and they can be installed and sets the status of the update to \c Success. + and they can be installed. */ bool PackageManagerCore::fetchRemotePackagesTree() { @@ -1177,6 +1206,9 @@ bool PackageManagerCore::fetchRemotePackagesTree() if (!d->fetchMetaInformationFromRepositories()) return false; + if (!d->fetchMetaInformationFromCompressedRepositories()) + return false; + if (!d->addUpdateResourcesFromRepositories(true)) return false; @@ -1184,6 +1216,11 @@ bool PackageManagerCore::fetchRemotePackagesTree() if (packages.isEmpty()) return false; + return fetchPackagesTree(packages, installedPackages); +} + +bool PackageManagerCore::fetchPackagesTree(const PackagesList &packages, const LocalPackagesHash installedPackages) { + bool success = false; if (!isUpdater()) { success = fetchAllPackages(packages, installedPackages); @@ -1366,12 +1403,12 @@ void PackageManagerCore::addUserRepositories(const QStringList &repositories) \sa {installer::setTemporaryRepositories}{installer.setTemporaryRepositories} \sa addUserRepositories() */ -void PackageManagerCore::setTemporaryRepositories(const QStringList &repositories, bool replace) +void PackageManagerCore::setTemporaryRepositories(const QStringList &repositories, bool replace, + bool compressed) { QSet<Repository> repositorySet; foreach (const QString &repository, repositories) - repositorySet.insert(Repository::fromUserInput(repository)); - + repositorySet.insert(Repository::fromUserInput(repository, compressed)); settings().setTemporaryRepositories(repositorySet, replace); } diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index eebc33c4b..6b2a42ace 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -127,6 +127,7 @@ public: PackagesList remotePackages(); bool fetchRemotePackagesTree(); + bool fetchCompressedPackagesTree(); bool run(); void reset(const QHash<QString, QString> ¶ms); @@ -181,8 +182,8 @@ public: void setTestChecksum(bool test); Q_INVOKABLE void addUserRepositories(const QStringList &repositories); - Q_INVOKABLE void setTemporaryRepositories(const QStringList &repositories, bool replace = false); - + Q_INVOKABLE void setTemporaryRepositories(const QStringList &repositories, + bool replace = false, bool compressed = false); Q_INVOKABLE void autoAcceptMessageBoxes(); Q_INVOKABLE void autoRejectMessageBoxes(); Q_INVOKABLE void setMessageBoxAutomaticAnswer(const QString &identifier, int button); @@ -340,6 +341,8 @@ private: ComponentModel *componentModel(PackageManagerCore *core, const QString &objectName) const; QList<Component *> componentsMarkedForInstallation() const; + bool fetchPackagesTree(const PackagesList &packages, const LocalPackagesHash installedPackages); + private: PackageManagerCorePrivate *const d; friend class PackageManagerCorePrivate; diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index b972545ce..58847dfec 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -185,6 +185,7 @@ static void deferredRename(const QString &oldName, const QString &newName, bool PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core) : m_updateFinder(0) + , m_compressedFinder(0) , m_localPackageHub(std::make_shared<LocalPackageHub>()) , m_core(core) , m_updates(false) @@ -206,6 +207,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core) PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker, const QList<OperationBlob> &performedOperations) : m_updateFinder(0) + , m_compressedFinder(0) , m_localPackageHub(std::make_shared<LocalPackageHub>()) , m_status(PackageManagerCore::Unfinished) , m_needsHardRestart(false) @@ -2131,6 +2133,29 @@ PackagesList PackageManagerCorePrivate::remotePackages() return m_updateFinder->updates(); } +PackagesList PackageManagerCorePrivate::compressedPackages() +{ + if (m_compressedUpdates && m_compressedFinder) + return m_compressedFinder->updates(); + m_compressedUpdates = false; + delete m_compressedFinder; + + m_compressedFinder = new KDUpdater::UpdateFinder; + m_compressedFinder->setAutoDelete(false); + m_compressedFinder->addCompressedPackage(true); + m_compressedFinder->setPackageSources(m_compressedPackageSources); + + m_compressedFinder->setLocalPackageHub(m_localPackageHub); + m_compressedFinder->run(); + if (m_compressedFinder->updates().isEmpty()) { + setStatus(PackageManagerCore::Failure, tr("Cannot retrieve remote tree %1.") + .arg(m_compressedFinder->errorString())); + return PackagesList(); + } + m_compressedUpdates = true; + return m_compressedFinder->updates(); +} + /*! Returns a hash containing the installed package name and it's associated package information. If the application is running in installer mode or the local components file could not be parsed, the @@ -2200,9 +2225,44 @@ bool PackageManagerCorePrivate::fetchMetaInformationFromRepositories() return m_repoFetched; } -bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChecksum) +bool PackageManagerCorePrivate::fetchMetaInformationFromCompressedRepositories() +{ + bool compressedRepoFetched = false; + + m_compressedUpdates = false; + m_updateSourcesAdded = false; + + try { + //Tell MetadataJob that only compressed packages needed to be fetched and not all. + //We cannot do this in general fetch meta method as the compressed packages might be + //installed after components tree is generated + m_metadataJob.addCompressedPackages(true); + m_metadataJob.start(); + m_metadataJob.waitForFinished(); + m_metadataJob.addCompressedPackages(false); + } catch (Error &error) { + setStatus(PackageManagerCore::Failure, tr("Cannot retrieve meta information: %1") + .arg(error.message())); + return compressedRepoFetched; + } + + if (m_metadataJob.error() != Job::NoError) { + switch (m_metadataJob.error()) { + case QInstaller::UserIgnoreError: + break; // we can simply ignore this error, the user knows about it + default: + setStatus(PackageManagerCore::Failure, m_metadataJob.errorString()); + return compressedRepoFetched; + } + } + + compressedRepoFetched = true; + return compressedRepoFetched; +} + +bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChecksum, bool compressedRepository) { - if (m_updateSourcesAdded) + if (!compressedRepository && m_updateSourcesAdded) return m_updateSourcesAdded; const QList<Metadata> metadata = m_metadataJob.metadata(); @@ -2210,15 +2270,21 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe m_updateSourcesAdded = true; return m_updateSourcesAdded; } - - m_packageSources.clear(); - if (isInstaller()) - m_packageSources.insert(PackageSource(QUrl(QLatin1String("resource://metadata/")), 0)); - - m_updates = false; - m_updateSourcesAdded = false; + if (compressedRepository) { + m_compressedPackageSources.clear(); + } + else { + m_packageSources.clear(); + m_updates = false; + m_updateSourcesAdded = false; + if (isInstaller()) + m_packageSources.insert(PackageSource(QUrl(QLatin1String("resource://metadata/")), 0)); + } foreach (const Metadata &data, metadata) { + if (compressedRepository && !data.repository.isCompressed()) { + continue; + } if (statusCanceledOrFailed()) return false; @@ -2251,11 +2317,15 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe if (!checksum.isNull()) m_core->setTestChecksum(checksum.toElement().text().toLower() == scTrue); } - m_packageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 1)); + if (compressedRepository) + m_compressedPackageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 1)); + else + m_packageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 1)); + ProductKeyCheck::instance()->addPackagesFromXml(data.directory + QLatin1String("/Updates.xml")); } - - if (m_packageSources.count() == 0) { + if ((compressedRepository && m_compressedPackageSources.count() == 0 ) || + (!compressedRepository && m_packageSources.count() == 0)) { setStatus(PackageManagerCore::Failure, tr("Cannot find any update source information.")); return false; } diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index d78bd3e69..7377feff4 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -175,7 +175,9 @@ signals: public: UpdateFinder *m_updateFinder; + UpdateFinder *m_compressedFinder; QSet<PackageSource> m_packageSources; + QSet<PackageSource> m_compressedPackageSources; std::shared_ptr<LocalPackageHub> m_localPackageHub; QStringList m_filesForDelayedDeletion; @@ -227,9 +229,11 @@ private: bool adminRightsGained, bool deleteOperation); PackagesList remotePackages(); + PackagesList compressedPackages(); LocalPackagesHash localInstalledPackages(); bool fetchMetaInformationFromRepositories(); - bool addUpdateResourcesFromRepositories(bool parseChecksum); + bool fetchMetaInformationFromCompressedRepositories(); + bool addUpdateResourcesFromRepositories(bool parseChecksum, bool compressedRepository = false); void processFilesForDelayedDeletion(); private: @@ -237,6 +241,7 @@ private: MetadataJob m_metadataJob; bool m_updates; + bool m_compressedUpdates; bool m_repoFetched; bool m_updateSourcesAdded; qint64 m_magicBinaryMarker; diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index ec558a7ab..18f8849f9 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -75,6 +75,7 @@ #include <QTreeView> #include <QVBoxLayout> #include <QShowEvent> +#include <QFileDialog> #ifdef Q_OS_WIN # include <qt_windows.h> @@ -1858,6 +1859,7 @@ public: , m_allModel(m_core->defaultComponentModel()) , m_updaterModel(m_core->updaterComponentModel()) , m_currentModel(m_allModel) + , m_compressedButtonVisible(false) { m_treeView->setObjectName(QLatin1String("ComponentsTreeView")); @@ -1873,17 +1875,21 @@ public: m_descriptionLabel->setWordWrap(true); m_descriptionLabel->setObjectName(QLatin1String("ComponentDescriptionLabel")); - QVBoxLayout *vlayout = new QVBoxLayout; - vlayout->addWidget(m_descriptionLabel); + m_vlayout = new QVBoxLayout; + m_vlayout->setObjectName(QLatin1String("VerticalLayout")); + m_vlayout->addWidget(m_descriptionLabel); m_sizeLabel = new QLabel(q); m_sizeLabel->setWordWrap(true); - vlayout->addWidget(m_sizeLabel); + m_vlayout->addWidget(m_sizeLabel); m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel")); - vlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding, +#ifdef INSTALLCOMPRESSED + allowCompressedRepositoryInstall(); +#endif + m_vlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); - hlayout->addLayout(vlayout, 2); + hlayout->addLayout(m_vlayout, 2); QVBoxLayout *layout = new QVBoxLayout(q); layout->addLayout(hlayout, 1); @@ -1929,6 +1935,40 @@ public: layout->addLayout(hlayout); } + void allowCompressedRepositoryInstall() + { + if (m_compressedButtonVisible) { + return; + } + + connect(m_core, SIGNAL(metaJobProgress(int)), this, SLOT(onProgressChanged(int))); + connect(m_core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString))); + + m_bspLabel = new QLabel(ComponentSelectionPage::tr("To install new "\ + "compressed repository, browse the repositories from your computer"),q); + m_bspLabel->setWordWrap(true); + m_bspLabel->setObjectName(QLatin1String("CompressedButtonLabel")); + + m_vlayout->addSpacing(50); + m_vlayout->addWidget(m_bspLabel); + + + m_progressBar = new QProgressBar(); + m_progressBar->setRange(0, 0); + m_progressBar->hide(); + m_vlayout->addWidget(m_progressBar); + m_progressBar->setObjectName(QLatin1String("CompressedInstallProgressBar")); + + + m_installCompressButton = new QPushButton; + connect(m_installCompressButton, &QAbstractButton::clicked, + this, &ComponentSelectionPage::Private::selectCompressedPackage); + m_installCompressButton->setObjectName(QLatin1String("InstallCompressedPackageButton")); + m_installCompressButton->setText(ComponentSelectionPage::tr("&Browse BSP or 7z files...")); + m_vlayout->addWidget(m_installCompressButton); + m_compressedButtonVisible = true; + } + void updateTreeView() { m_checkDefault->setVisible(m_core->isInstaller() || m_core->isPackageManager()); @@ -2012,6 +2052,58 @@ public slots: m_currentModel->setCheckedState(ComponentModel::AllUnchecked); } + void selectCompressedPackage() + { + QString defaultDownloadDirectory = + QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); + QStringList fileNames = QFileDialog::getOpenFileNames(NULL, + ComponentSelectionPage::tr("Open File"),defaultDownloadDirectory, + QLatin1String("QtBSP or 7z Files (*.qtbsp *.7z)")); + + QSet<Repository> set; + foreach (QString fileName, fileNames) { + Repository repository = Repository::fromUserInput(fileName, true); + set.insert(repository); + } + if (set.count() > 0) { + m_progressBar->show(); + m_installCompressButton->setEnabled(false); + QPushButton *const b = qobject_cast<QPushButton *>(q->gui()->button(QWizard::NextButton)); + b->setEnabled(false); + m_core->settings().addTemporaryRepositories(set, false); + m_core->fetchCompressedPackagesTree(); + updateTreeView(); + + m_progressBar->hide(); + m_bspLabel->setText(ComponentSelectionPage::tr("To install new "\ + "compressed repository, browse the repositories from your computer")); + m_installCompressButton->setEnabled(true); + b->setEnabled(true); + } + } + + /*! + Updates the value of \a progress on the progress bar. + */ + void onProgressChanged(int progress) + { + m_progressBar->setValue(progress); + } + + /*! + Displays the message \a msg on the page. + */ + void setMessage(const QString &msg) + { + if (m_progressBar->isVisible()) { + m_bspLabel->setText(msg); + } + else { + m_bspLabel->setText(ComponentSelectionPage::tr("To install new "\ + "compressed repository, browse the repositories from your computer")); + } + } + void selectDefault() { m_currentModel->setCheckedState(ComponentModel::DefaultChecked); @@ -2049,6 +2141,11 @@ public: QPushButton *m_checkAll; QPushButton *m_uncheckAll; QPushButton *m_checkDefault; + QPushButton *m_installCompressButton; + QLabel *m_bspLabel; + QProgressBar *m_progressBar; + QVBoxLayout *m_vlayout; + bool m_compressedButtonVisible; }; @@ -2167,6 +2264,11 @@ void ComponentSelectionPage::deselectComponent(const QString &id) d->m_currentModel->setData(idx, Qt::Unchecked, Qt::CheckStateRole); } +void ComponentSelectionPage::allowCompressedRepositoryInstall() +{ + d->allowCompressedRepositoryInstall(); +} + void ComponentSelectionPage::setModified(bool modified) { setComplete(modified); diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h index 2940df052..63d00b941 100644 --- a/src/libs/installer/packagemanagergui.h +++ b/src/libs/installer/packagemanagergui.h @@ -314,6 +314,7 @@ public: Q_INVOKABLE void selectDefault(); Q_INVOKABLE void selectComponent(const QString &id); Q_INVOKABLE void deselectComponent(const QString &id); + Q_INVOKABLE void allowCompressedRepositoryInstall(); protected: void entering(); diff --git a/src/libs/installer/repository.cpp b/src/libs/installer/repository.cpp index 9a501fdfe..280ff1c75 100644 --- a/src/libs/installer/repository.cpp +++ b/src/libs/installer/repository.cpp @@ -46,6 +46,7 @@ namespace QInstaller { Repository::Repository() : m_default(false) , m_enabled(false) + , m_compressed(false) { registerMetaType(); } @@ -60,28 +61,31 @@ Repository::Repository(const Repository &other) , m_username(other.m_username) , m_password(other.m_password) , m_displayname(other.m_displayname) + , m_compressed(other.m_compressed) { registerMetaType(); } /*! - Constructs a new repository by setting its address to \a url and its default state. + Constructs a new repository by setting its address to \a url + and its default and \a compressed states. */ -Repository::Repository(const QUrl &url, bool isDefault) +Repository::Repository(const QUrl &url, bool isDefault, bool compressed) : m_url(url) , m_default(isDefault) , m_enabled(true) + , m_compressed(compressed) { registerMetaType(); } /*! - Constructs a new repository by setting its address to \a repositoryUrl as string and its - default state. + Constructs a new repository by setting its address to \a repositoryUrl as + string and its \a compressed state. Note: user and password can be inside the \a repositoryUrl string: http://user:password@repository.url */ -Repository Repository::fromUserInput(const QString &repositoryUrl) +Repository Repository::fromUserInput(const QString &repositoryUrl, bool compressed) { QUrl url = QUrl::fromUserInput(repositoryUrl); const QStringList supportedSchemes = KDUpdater::FileDownloaderFactory::supportedSchemes(); @@ -93,7 +97,7 @@ Repository Repository::fromUserInput(const QString &repositoryUrl) url.setUserName(QString()); url.setPassword(QString()); - Repository repository(url, false); + Repository repository(url, false, compressed); repository.setUsername(userName); repository.setPassword(password); return repository; @@ -200,6 +204,22 @@ void Repository::setDisplayName(const QString &displayname) } /*! + Returns true if repository is compressed +*/ +bool Repository::isCompressed() const +{ + return m_compressed; +} + +/*! + Sets this repository to \a compressed state to know weather the repository + needs to be uncompressed before use. +*/ +void Repository::setCompressed(bool compressed) +{ + m_compressed = compressed; +} +/*! Compares the values of this repository to \a other and returns true if they are equal (same server, default state, enabled state as well as username and password). \sa operator!=() */ @@ -232,6 +252,7 @@ const Repository &Repository::operator=(const Repository &other) m_username = other.m_username; m_password = other.m_password; m_displayname = other.m_displayname; + m_compressed = other.m_compressed; return *this; } @@ -244,7 +265,7 @@ void Repository::registerMetaType() QDataStream &operator>>(QDataStream &istream, Repository &repository) { - QByteArray url, username, password, displayname; + QByteArray url, username, password, displayname, compressed; istream >> url >> repository.m_default >> repository.m_enabled >> username >> password >> displayname; repository.setUrl(QUrl::fromEncoded(QByteArray::fromBase64(url))); repository.setUsername(QString::fromUtf8(QByteArray::fromBase64(username))); diff --git a/src/libs/installer/repository.h b/src/libs/installer/repository.h index 96e41d311..785b452fb 100644 --- a/src/libs/installer/repository.h +++ b/src/libs/installer/repository.h @@ -46,10 +46,10 @@ class INSTALLER_EXPORT Repository public: explicit Repository(); Repository(const Repository &other); - explicit Repository(const QUrl &url, bool isDefault); + explicit Repository(const QUrl &url, bool isDefault, bool compressed = false); static void registerMetaType(); - static Repository fromUserInput(const QString &repositoryUrl); + static Repository fromUserInput(const QString &repositoryUrl, bool compressed = false); bool isValid() const; bool isDefault() const; @@ -69,6 +69,8 @@ public: QString displayname() const; void setDisplayName(const QString &displayname); + bool isCompressed() const; + void setCompressed(bool compressed); bool operator==(const Repository &other) const; bool operator!=(const Repository &other) const; @@ -85,6 +87,7 @@ private: QString m_username; QString m_password; QString m_displayname; + bool m_compressed; }; inline uint qHash(const Repository &repository) diff --git a/src/libs/kdtools/task.cpp b/src/libs/kdtools/task.cpp index 14b774ea9..64e999ba2 100644 --- a/src/libs/kdtools/task.cpp +++ b/src/libs/kdtools/task.cpp @@ -183,7 +183,7 @@ void Task::run() return; } - if (m_finished || m_stopped) { + if (m_stopped) { qDebug("Trying to start a finished or canceled task"); return; } diff --git a/src/libs/kdtools/updatefinder.cpp b/src/libs/kdtools/updatefinder.cpp index 25e587b17..8553fea2c 100644 --- a/src/libs/kdtools/updatefinder.cpp +++ b/src/libs/kdtools/updatefinder.cpp @@ -173,7 +173,8 @@ void UpdateFinder::Private::computeUpdates() // 1. Downloading Update XML files from all the update sources // 2. Matching updates with Package XML and figuring out available updates - clear(); + if (!q->isCompressedPackage()) + clear(); cancel = false; // First do some quick sanity checks on the packages info @@ -399,7 +400,8 @@ void UpdateFinder::Private::createUpdateObjects(const PackageSource &source, delete updates.take(name); // Create and register the update - updates.insert(name, new Update(source, info)); + if (!q->isCompressedPackage() || value == Resolution::AddPackage) + updates.insert(name, new Update(source, info)); } } @@ -439,6 +441,10 @@ UpdateFinder::Private::Resolution UpdateFinder::Private::checkPriorityAndVersion << ", Source: " << QFileInfo(source.url.toLocalFile()).fileName() << "'"; return Resolution::RemoveExisting; } + if (q->isCompressedPackage() && match == 0 && source.priority == existingPackage->packageSource().priority) { + //Same package with the same priority and version already exists + return Resolution::RemoveExisting; + } return Resolution::KeepExisting; // otherwise keep existing } return Resolution::AddPackage; @@ -453,6 +459,7 @@ UpdateFinder::Private::Resolution UpdateFinder::Private::checkPriorityAndVersion */ UpdateFinder::UpdateFinder() : Task(QLatin1String("UpdateFinder"), Stoppable), + m_compressedPackage(false), d(new Private(this)) { } diff --git a/src/libs/kdtools/updatefinder.h b/src/libs/kdtools/updatefinder.h index 1fbebdd9a..ed943789f 100644 --- a/src/libs/kdtools/updatefinder.h +++ b/src/libs/kdtools/updatefinder.h @@ -58,7 +58,8 @@ public: void setLocalPackageHub(std::weak_ptr<LocalPackageHub> hub); void setPackageSources(const QSet<QInstaller::PackageSource> &sources); - + void addCompressedPackage(bool add) { m_compressedPackage = add; } + bool isCompressedPackage() { return m_compressedPackage; } private: void doRun(); bool doStop(); @@ -66,6 +67,7 @@ private: bool doResume(); private: + bool m_compressedPackage; Private *d; Q_PRIVATE_SLOT(d, void slotDownloadDone()) }; diff --git a/src/sdk/commandlineparser.cpp b/src/sdk/commandlineparser.cpp index 6da318806..1dc7ca168 100644 --- a/src/sdk/commandlineparser.cpp +++ b/src/sdk/commandlineparser.cpp @@ -114,7 +114,10 @@ CommandLineParser::CommandLineParser() "a value is omitted, the client will use a default instead. Note: The server process is " "not started by the client application in that case, you need to start it on your own."), QLatin1String("socketname,key"))); - + m_parser.addOption(QCommandLineOption(QLatin1String(CommandLineOptions::InstallCompressedRepository), + QLatin1String("Installs QtBSP or 7z file. The QtBSP (Board Support Package) file must be a .7z " + "file which contains a valid repository."), + QLatin1String("URI,..."))); m_parser.addPositionalArgument(QLatin1String(CommandLineOptions::KeyValue), QLatin1String("Key Value pair to be set.")); } diff --git a/src/sdk/constants.h b/src/sdk/constants.h index a322df09b..763377a08 100644 --- a/src/sdk/constants.h +++ b/src/sdk/constants.h @@ -56,6 +56,7 @@ const char AddTmpRepository[] = "addTempRepository"; const char SetTmpRepository[] = "setTempRepository"; const char StartServer[] = "startserver"; const char StartClient[] = "startclient"; +const char InstallCompressedRepository[] = "installCompressedRepository"; } // namespace CommandLineOptions diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp index c99a48aa8..ec3a87a8d 100644 --- a/src/sdk/installerbase.cpp +++ b/src/sdk/installerbase.cpp @@ -217,6 +217,14 @@ int InstallerBase::run() m_core->setTemporaryRepositories(repoList, true); } + if (parser.isSet(QLatin1String(CommandLineOptions::InstallCompressedRepository))) { + const QStringList repoList = repositories(parser + .value(QLatin1String(CommandLineOptions::InstallCompressedRepository))); + if (repoList.isEmpty()) + throw QInstaller::Error(QLatin1String("Empty repository list for option 'installCompressedRepository'.")); + m_core->setTemporaryRepositories(repoList, false, true); + } + QInstaller::PackageManagerCore::setNoForceInstallation(parser .isSet(QLatin1String(CommandLineOptions::NoForceInstallation))); QInstaller::PackageManagerCore::setCreateLocalRepositoryFromBinary(parser |