summaryrefslogtreecommitdiffstats
path: root/tools/common/repositorygen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/common/repositorygen.cpp')
-rw-r--r--tools/common/repositorygen.cpp965
1 files changed, 0 insertions, 965 deletions
diff --git a/tools/common/repositorygen.cpp b/tools/common/repositorygen.cpp
deleted file mode 100644
index 45ea0a541..000000000
--- a/tools/common/repositorygen.cpp
+++ /dev/null
@@ -1,965 +0,0 @@
-/**************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Installer Framework.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-**************************************************************************/
-#include "repositorygen.h"
-
-#include <constants.h>
-#include <fileio.h>
-#include <fileutils.h>
-#include <errors.h>
-#include <globals.h>
-#include <lib7z_create.h>
-#include <lib7z_extract.h>
-#include <lib7z_facade.h>
-#include <lib7z_list.h>
-#include <settings.h>
-#include <qinstallerglobal.h>
-#include <utils.h>
-#include <scriptengine.h>
-
-#include <updater.h>
-
-#include <QtCore/QDirIterator>
-#include <QtCore/QRegExp>
-
-#include <QtXml/QDomDocument>
-#include <QTemporaryDir>
-
-#include <iostream>
-
-using namespace QInstaller;
-using namespace QInstallerTools;
-
-void QInstallerTools::printRepositoryGenOptions()
-{
- std::cout << " -p|--packages dir The directory containing the available packages." << std::endl;
- std::cout << " This entry can be given multiple times." << std::endl;
- std::cout << " --repository dir The directory containing the available repository." << std::endl;
- std::cout << " This entry can be given multiple times." << std::endl;
-
- std::cout << " -e|--exclude p1,...,pn Exclude the given packages." << std::endl;
- std::cout << " -i|--include p1,...,pn Include the given packages and their dependencies" << std::endl;
- std::cout << " from the repository." << std::endl;
-
- std::cout << " --ignore-translations Do not use any translation" << std::endl;
- std::cout << " --ignore-invalid-packages Ignore all invalid packages instead of aborting." << std::endl;
- std::cout << " --ignore-invalid-repositories Ignore all invalid repositories instead of aborting." << std::endl;
-}
-
-QString QInstallerTools::makePathAbsolute(const QString &path)
-{
- if (QFileInfo(path).isRelative())
- return QDir::current().absoluteFilePath(path);
- return path;
-}
-
-void QInstallerTools::copyWithException(const QString &source, const QString &target, const QString &kind)
-{
- qDebug() << "Copying associated" << kind << "file" << source;
-
- const QFileInfo targetFileInfo(target);
- if (!targetFileInfo.dir().exists())
- QInstaller::mkpath(targetFileInfo.absolutePath());
-
- QFile sourceFile(source);
- if (!sourceFile.copy(target)) {
- qDebug() << "failed!\n";
- throw QInstaller::Error(QString::fromLatin1("Cannot copy the %1 file from \"%2\" to \"%3\": "
- "%4").arg(kind, QDir::toNativeSeparators(source), QDir::toNativeSeparators(target),
- /* in case of an existing target the error String does not show the file */
- (targetFileInfo.exists() ? QLatin1String("Target already exist.") : sourceFile.errorString())));
- }
-
- qDebug() << "done.";
-}
-
-static QStringList copyFilesFromNode(const QString &parentNode, const QString &childNode, const QString &attr,
- const QString &kind, const QDomNode &package, const PackageInfo &info, const QString &targetDir)
-{
- QStringList copiedFiles;
- const QDomNodeList nodes = package.firstChildElement(parentNode).childNodes();
- for (int i = 0; i < nodes.count(); ++i) {
- const QDomNode node = nodes.at(i);
- if (node.nodeName() != childNode)
- continue;
-
- const QDir dir(QString::fromLatin1("%1/meta").arg(info.directory));
- const QString filter = attr.isEmpty() ? node.toElement().text() : node.toElement().attribute(attr);
- const QStringList files = dir.entryList(QStringList(filter), QDir::Files);
- if (files.isEmpty()) {
- throw QInstaller::Error(QString::fromLatin1("Cannot find any %1 matching \"%2\" "
- "while copying %1 of \"%3\".").arg(kind, filter, info.name));
- }
-
- foreach (const QString &file, files) {
- const QString source(QString::fromLatin1("%1/meta/%2").arg(info.directory, file));
- const QString target(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, file));
- copyWithException(source, target, kind);
- copiedFiles.append(file);
- }
- }
- return copiedFiles;
-}
-
-void QInstallerTools::copyMetaData(const QString &_targetDir, const QString &metaDataDir,
- const PackageInfoVector &packages, const QString &appName, const QString &appVersion,
- const QStringList &uniteMetadatas)
-{
- const QString targetDir = makePathAbsolute(_targetDir);
- if (!QFile::exists(targetDir))
- QInstaller::mkpath(targetDir);
-
- bool componentMetaExtracted = false;
- QDomDocument doc;
- QDomElement root;
- QFile existingUpdatesXml(QFileInfo(metaDataDir, QLatin1String("Updates.xml")).absoluteFilePath());
- if (existingUpdatesXml.open(QIODevice::ReadOnly) && doc.setContent(&existingUpdatesXml)) {
- root = doc.documentElement();
- // remove entry for this component from existing Updates.xml, if found
- foreach (const PackageInfo &info, packages) {
- const QDomNodeList packageNodes = root.childNodes();
- for (int i = packageNodes.count() - 1; i >= 0; --i) {
- const QDomNode node = packageNodes.at(i);
- if (node.nodeName() != QLatin1String("PackageUpdate"))
- continue;
- if (node.firstChildElement(QLatin1String("Name")).text() != info.name)
- continue;
- root.removeChild(node);
- }
- }
- existingUpdatesXml.close();
- } else {
- root = doc.createElement(QLatin1String("Updates"));
- root.appendChild(doc.createElement(QLatin1String("ApplicationName"))).appendChild(doc
- .createTextNode(appName));
- root.appendChild(doc.createElement(QLatin1String("ApplicationVersion"))).appendChild(doc
- .createTextNode(appVersion));
- root.appendChild(doc.createElement(QLatin1String("Checksum"))).appendChild(doc
- .createTextNode(QLatin1String("true")));
- }
-
- foreach (const PackageInfo &info, packages) {
- if (info.metaFile.isEmpty() && info.metaNode.isEmpty()) {
- if (!QDir(targetDir).mkpath(info.name))
- throw QInstaller::Error(QString::fromLatin1("Cannot create directory \"%1\".").arg(info.name));
-
- const QString packageXmlPath = QString::fromLatin1("%1/meta/package.xml").arg(info.directory);
- qDebug() << "Copy meta data for package" << info.name << "using" << packageXmlPath;
-
- QFile file(packageXmlPath);
- QInstaller::openForRead(&file);
-
- QString errMsg;
- int line = 0;
- int column = 0;
- QDomDocument packageXml;
- if (!packageXml.setContent(&file, &errMsg, &line, &column)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot parse \"%1\": line: %2, column: %3: %4 (%5)")
- .arg(QDir::toNativeSeparators(packageXmlPath)).arg(line).arg(column).arg(errMsg, info.name));
- }
-
- QDomElement update = doc.createElement(QLatin1String("PackageUpdate"));
- QDomNode nameElement = update.appendChild(doc.createElement(QLatin1String("Name")));
- nameElement.appendChild(doc.createTextNode(info.name));
-
- // list of current unused or later transformed tags
- QStringList blackList;
- blackList << QLatin1String("UserInterfaces") << QLatin1String("Translations") <<
- QLatin1String("Licenses") << QLatin1String("Name");
-
- bool foundDefault = false;
- bool foundVirtual = false;
- bool foundDisplayName = false;
- bool foundDownloadableArchives = false;
- bool foundCheckable = false;
- const QDomNode package = packageXml.firstChildElement(QLatin1String("Package"));
- const QDomNodeList childNodes = package.childNodes();
- for (int i = 0; i < childNodes.count(); ++i) {
- const QDomNode node = childNodes.at(i);
- const QString key = node.nodeName();
-
- if (key == QLatin1String("Default"))
- foundDefault = true;
- if (key == QLatin1String("Virtual"))
- foundVirtual = true;
- if (key == QLatin1String("DisplayName"))
- foundDisplayName = true;
- if (key == QLatin1String("DownloadableArchives"))
- foundDownloadableArchives = true;
- if (key == QLatin1String("Checkable"))
- foundCheckable = true;
- if (node.isComment() || blackList.contains(key))
- continue; // just skip comments and some tags...
-
- QDomElement element = doc.createElement(key);
- for (int j = 0; j < node.attributes().size(); ++j) {
- element.setAttribute(node.attributes().item(j).toAttr().name(),
- node.attributes().item(j).toAttr().value());
- }
- update.appendChild(element).appendChild(doc.createTextNode(node.toElement().text()));
- }
-
- if (foundDefault && foundVirtual) {
- throw QInstaller::Error(QString::fromLatin1("Error: <Default> and <Virtual> elements are "
- "mutually exclusive in file \"%1\".").arg(QDir::toNativeSeparators(packageXmlPath)));
- }
-
- if (foundDefault && foundCheckable) {
- throw QInstaller::Error(QString::fromLatin1("Error: <Default> and <Checkable>"
- "elements are mutually exclusive in file \"%1\".")
- .arg(QDir::toNativeSeparators(packageXmlPath)));
- }
-
- if (!foundDisplayName) {
- qWarning() << "No DisplayName tag found at" << info.name << ", using component Name instead.";
- QDomElement displayNameElement = doc.createElement(QLatin1String("DisplayName"));
- update.appendChild(displayNameElement).appendChild(doc.createTextNode(info.name));
- }
-
- // get the size of the data
- quint64 componentSize = 0;
- quint64 compressedComponentSize = 0;
-
- const QDir::Filters filters = QDir::Files | QDir::NoDotAndDotDot;
- const QDir dataDir = QString::fromLatin1("%1/%2/data").arg(metaDataDir, info.name);
- const QFileInfoList entries = dataDir.exists() ? dataDir.entryInfoList(filters | QDir::Dirs)
- : QDir(QString::fromLatin1("%1/%2").arg(metaDataDir, info.name)).entryInfoList(filters);
- qDebug() << "calculate size of directory" << dataDir.absolutePath();
- foreach (const QFileInfo &fi, entries) {
- try {
- if (fi.isDir()) {
- QDirIterator recursDirIt(fi.filePath(), QDirIterator::Subdirectories);
- while (recursDirIt.hasNext()) {
- recursDirIt.next();
- const quint64 size = QInstaller::fileSize(recursDirIt.fileInfo());
- componentSize += size;
- compressedComponentSize += size;
- }
- } else if (Lib7z::isSupportedArchive(fi.filePath())) {
- // if it's an archive already, list its files and sum the uncompressed sizes
- QFile archive(fi.filePath());
- compressedComponentSize += archive.size();
- QInstaller::openForRead(&archive);
-
- QVector<Lib7z::File>::const_iterator fileIt;
- const QVector<Lib7z::File> files = Lib7z::listArchive(&archive);
- for (fileIt = files.begin(); fileIt != files.end(); ++fileIt)
- componentSize += fileIt->uncompressedSize;
- } else {
- // otherwise just add its size
- const quint64 size = QInstaller::fileSize(fi);
- componentSize += size;
- compressedComponentSize += size;
- }
- } catch (const QInstaller::Error &error) {
- qDebug().noquote() << error.message();
- } catch(...) {
- // ignore, that's just about the sizes - and size doesn't matter, you know?
- }
- }
-
- QDomElement fileElement = doc.createElement(QLatin1String("UpdateFile"));
- fileElement.setAttribute(QLatin1String("UncompressedSize"), componentSize);
- fileElement.setAttribute(QLatin1String("CompressedSize"), compressedComponentSize);
- // adding the OS attribute to be compatible with old sdks
- fileElement.setAttribute(QLatin1String("OS"), QLatin1String("Any"));
- update.appendChild(fileElement);
-
- root.appendChild(update);
-
- // copy script file
- const QString script = package.firstChildElement(QLatin1String("Script")).text();
- if (!script.isEmpty()) {
- QFile scriptFile(QString::fromLatin1("%1/meta/%2").arg(info.directory, script));
- if (!scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot open component script at \"%1\".")
- .arg(QDir::toNativeSeparators(scriptFile.fileName())));
- }
-
- const QString scriptContent = QLatin1String("(function() {")
- + QString::fromUtf8(scriptFile.readAll())
- + QLatin1String(";"
- " if (typeof Component == \"undefined\")"
- " throw \"Missing Component constructor. Please check your script.\";"
- "})();");
-
- // if the user isn't aware of the downloadable archives value we will add it automatically later
- foundDownloadableArchives |= scriptContent.contains(QLatin1String("addDownloadableArchive"))
- || scriptContent.contains(QLatin1String("removeDownloadableArchive"));
-
- static QInstaller::ScriptEngine testScriptEngine;
- const QJSValue value = testScriptEngine.evaluate(scriptContent, scriptFile.fileName());
- if (value.isError()) {
- throw QInstaller::Error(QString::fromLatin1("Exception while loading component "
- "script at \"%1\": %2").arg(QDir::toNativeSeparators(scriptFile.fileName()),
- value.toString().isEmpty() ? QString::fromLatin1("Unknown error.") :
- value.toString() + QStringLiteral(" on line number: ") +
- value.property(QStringLiteral("lineNumber")).toString()));
- }
-
- const QString toLocation(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, script));
- copyWithException(scriptFile.fileName(), toLocation, QInstaller::scScript);
- }
-
- // write DownloadableArchives tag if that is missed by the user
- if (!foundDownloadableArchives && !info.copiedFiles.isEmpty()) {
- QStringList realContentFiles;
- foreach (const QString &filePath, info.copiedFiles) {
- if (!filePath.endsWith(QLatin1String(".sha1"), Qt::CaseInsensitive)) {
- const QString fileName = QFileInfo(filePath).fileName();
- // remove unnecessary version string from filename and add it to the list
- realContentFiles.append(fileName.mid(info.version.count()));
- }
- }
-
- update.appendChild(doc.createElement(QLatin1String("DownloadableArchives"))).appendChild(doc
- .createTextNode(realContentFiles.join(QChar::fromLatin1(','))));
- }
-
- // copy user interfaces
- const QStringList uiFiles = copyFilesFromNode(QLatin1String("UserInterfaces"),
- QLatin1String("UserInterface"), QString(), QLatin1String("user interface"), package, info,
- targetDir);
- if (!uiFiles.isEmpty()) {
- update.appendChild(doc.createElement(QLatin1String("UserInterfaces"))).appendChild(doc
- .createTextNode(uiFiles.join(QChar::fromLatin1(','))));
- }
-
- // copy translations
- QStringList trFiles;
- if (!qApp->arguments().contains(QString::fromLatin1("--ignore-translations"))) {
- trFiles = copyFilesFromNode(QLatin1String("Translations"), QLatin1String("Translation"),
- QString(), QLatin1String("translation"), package, info, targetDir);
- if (!trFiles.isEmpty()) {
- update.appendChild(doc.createElement(QLatin1String("Translations"))).appendChild(doc
- .createTextNode(trFiles.join(QChar::fromLatin1(','))));
- }
- }
-
- // copy license files
- const QStringList licenses = copyFilesFromNode(QLatin1String("Licenses"), QLatin1String("License"),
- QLatin1String("file"), QLatin1String("license"), package, info, targetDir);
- if (!licenses.isEmpty()) {
- foreach (const QString &trFile, trFiles) {
- // Copy translated license file based on the assumption that it will have the same base name
- // as the original license plus the file name of an existing translation file without suffix.
- foreach (const QString &license, licenses) {
- const QFileInfo untranslated(license);
- const QString translatedLicense = QString::fromLatin1("%2_%3.%4").arg(untranslated
- .baseName(), QFileInfo(trFile).baseName(), untranslated.completeSuffix());
- // ignore copy failure, that's just about the translations
- QFile::copy(QString::fromLatin1("%1/meta/%2").arg(info.directory).arg(translatedLicense),
- QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, translatedLicense));
- }
- }
- update.appendChild(package.firstChildElement(QLatin1String("Licenses")).cloneNode());
- }
- } else {
- // Extract metadata from archive
- if (!info.metaFile.isEmpty()){
- QFile metaFile(info.metaFile);
- QInstaller::openForRead(&metaFile);
- Lib7z::extractArchive(&metaFile, targetDir);
- componentMetaExtracted = true;
- }
-
- // Restore "PackageUpdate" node;
- QDomDocument update;
- if (!update.setContent(info.metaNode)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot restore \"PackageUpdate\" description for node %1").arg(info.name));
- }
-
- root.appendChild(update.documentElement());
- }
- }
-
- if (!componentMetaExtracted) {
- foreach (const QString uniteMetadata, uniteMetadatas) {
- QFile metaFile(QFileInfo(metaDataDir, uniteMetadata).absoluteFilePath());
- QInstaller::openForRead(&metaFile);
- Lib7z::extractArchive(&metaFile, targetDir);
- }
- }
-
- doc.appendChild(root);
-
- QFile targetUpdatesXml(targetDir + QLatin1String("/Updates.xml"));
- QInstaller::openForWrite(&targetUpdatesXml);
- QInstaller::blockingWrite(&targetUpdatesXml, doc.toByteArray());
-}
-
-PackageInfoVector QInstallerTools::createListOfPackages(const QStringList &packagesDirectories,
- QStringList *packagesToFilter, FilterType filterType)
-{
- qDebug() << "Collecting information about available packages...";
-
- bool ignoreInvalidPackages = qApp->arguments().contains(QString::fromLatin1("--ignore-invalid-packages"));
-
- PackageInfoVector dict;
- QFileInfoList entries;
- foreach (const QString &packagesDirectory, packagesDirectories)
- entries.append(QDir(packagesDirectory).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot));
- for (QFileInfoList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it) {
- if (filterType == Exclude) {
- // Check for current file in exclude list, if found, skip it and remove it from exclude list
- if (packagesToFilter->contains(it->fileName())) {
- packagesToFilter->removeAll(it->fileName());
- continue;
- }
- } else {
- // Check for current file in include list, if not found, skip it; if found, remove it from include list
- if (!packagesToFilter->contains(it->fileName()))
- continue;
- packagesToFilter->removeAll(it->fileName());
- }
- qDebug() << "Found subdirectory" << it->fileName();
- // because the filter is QDir::Dirs - filename means the name of the subdirectory
- if (it->fileName().contains(QLatin1Char('-'))) {
- qDebug("When using the component \"%s\" as a dependency, "
- "to ensure backward compatibility, you must add a colon symbol at the end, "
- "even if you do not specify a version.",
- qUtf8Printable(it->fileName()));
- }
-
- QFile file(QString::fromLatin1("%1/meta/package.xml").arg(it->filePath()));
- QFileInfo fileInfo(file);
- if (!fileInfo.exists()) {
- if (ignoreInvalidPackages)
- continue;
- throw QInstaller::Error(QString::fromLatin1("Component \"%1\" does not contain a package "
- "description (meta/package.xml is missing).").arg(QDir::toNativeSeparators(it->fileName())));
- }
-
- file.open(QIODevice::ReadOnly);
-
- QDomDocument doc;
- QString error;
- int errorLine = 0;
- int errorColumn = 0;
- if (!doc.setContent(&file, &error, &errorLine, &errorColumn)) {
- if (ignoreInvalidPackages)
- continue;
- throw QInstaller::Error(QString::fromLatin1("Component package description in \"%1\" is invalid. "
- "Error at line: %2, column: %3 -> %4").arg(QDir::toNativeSeparators(fileInfo.absoluteFilePath()),
- QString::number(errorLine),
- QString::number(errorColumn), error));
- }
-
- const QDomElement packageElement = doc.firstChildElement(QLatin1String("Package"));
- const QString name = packageElement.firstChildElement(QLatin1String("Name")).text();
- if (!name.isEmpty() && name != it->fileName()) {
- qWarning().nospace() << "The <Name> tag in the file " << fileInfo.absoluteFilePath()
- << " is ignored - the installer uses the path element right before the 'meta'"
- << " (" << it->fileName() << ")";
- }
-
- QString releaseDate = packageElement.firstChildElement(QLatin1String("ReleaseDate")).text();
- if (releaseDate.isEmpty()) {
- qWarning("Release date for \"%s\" is empty! Using the current date instead.",
- qPrintable(fileInfo.absoluteFilePath()));
- releaseDate = QDate::currentDate().toString(Qt::ISODate);
- }
-
- if (!QDate::fromString(releaseDate, Qt::ISODate).isValid()) {
- if (ignoreInvalidPackages)
- continue;
- throw QInstaller::Error(QString::fromLatin1("Release date for \"%1\" is invalid! <ReleaseDate>%2"
- "</ReleaseDate>. Supported format: YYYY-MM-DD").arg(QDir::toNativeSeparators(fileInfo.absoluteFilePath()),
- releaseDate));
- }
-
- PackageInfo info;
- info.name = it->fileName();
- info.version = packageElement.firstChildElement(QLatin1String("Version")).text();
- // Version cannot start with comparison characters, be an empty string
- // or have whitespaces at the beginning or at the end
- if (!QRegExp(QLatin1String("(?![<=>\\s]+)(.+)")).exactMatch(info.version) ||
- (info.version != info.version.trimmed())) {
- if (ignoreInvalidPackages)
- continue;
- throw QInstaller::Error(QString::fromLatin1("Component version for \"%1\" is invalid! <Version>%2</Version>")
- .arg(QDir::toNativeSeparators(fileInfo.absoluteFilePath()), info.version));
- }
- info.dependencies = packageElement.firstChildElement(QLatin1String("Dependencies")).text()
- .split(QInstaller::commaRegExp(), QString::SkipEmptyParts);
- info.directory = it->filePath();
- dict.push_back(info);
-
- qDebug() << "- it provides the package" << info.name << " - " << info.version;
- }
-
- if (!packagesToFilter->isEmpty() && packagesToFilter->at(0) != QString::fromLatin1(
- "X_fake_filter_component_for_online_only_installer_X")) {
- qWarning() << "The following explicitly given packages could not be found\n in package directory:" << *packagesToFilter;
- }
-
- if (dict.isEmpty())
- qDebug() << "No available packages found at the specified location.";
-
- return dict;
-}
-
-PackageInfoVector QInstallerTools::createListOfRepositoryPackages(const QStringList &repositoryDirectories,
- QStringList *packagesToFilter, FilterType filterType)
-{
- qDebug() << "Collecting information about available repository packages...";
-
- bool ignoreInvalidRepositories = qApp->arguments().contains(QString::fromLatin1("--ignore-invalid-repositories"));
-
- PackageInfoVector dict;
- QFileInfoList entries;
- foreach (const QString &repositoryDirectory, repositoryDirectories)
- entries.append(QFileInfo(repositoryDirectory));
- for (QFileInfoList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it) {
-
- qDebug() << "Process repository" << it->fileName();
-
- QFile file(QString::fromLatin1("%1/Updates.xml").arg(it->filePath()));
-
- QFileInfo fileInfo(file);
- if (!fileInfo.exists()) {
- if (ignoreInvalidRepositories) {
- qDebug() << "- skip invalid repository";
- continue;
- }
- throw QInstaller::Error(QString::fromLatin1("Repository \"%1\" does not contain a update "
- "description (Updates.xml is missing).").arg(QDir::toNativeSeparators(it->fileName())));
- }
- if (!file.open(QIODevice::ReadOnly)) {
- qDebug() << "Cannot open Updates.xml for reading:" << file.errorString();
- continue;
- }
-
- QString error;
- QDomDocument doc;
- if (!doc.setContent(&file, &error)) {
- qDebug().nospace() << "Cannot fetch a valid version of Updates.xml from repository "
- << it->fileName() << ": " << error;
- continue;
- }
- file.close();
-
- const QDomElement root = doc.documentElement();
- if (root.tagName() != QLatin1String("Updates")) {
- throw QInstaller::Error(QCoreApplication::translate("QInstaller",
- "Invalid content in \"%1\".").arg(QDir::toNativeSeparators(file.fileName())));
- }
-
- const QDomNodeList children = root.childNodes();
- for (int i = 0; i < children.count(); ++i) {
- const QDomElement el = children.at(i).toElement();
- if ((!el.isNull()) && (el.tagName() == QLatin1String("PackageUpdate"))) {
- QInstallerTools::PackageInfo info;
-
- QDomElement c1 = el.firstChildElement(QInstaller::scName);
- if (!c1.isNull())
- info.name = c1.text();
- else
- continue;
- if (filterType == Exclude) {
- // Check for current package in exclude list, if found, skip it
- if (packagesToFilter->contains(info.name)) {
- continue;
- }
- } else {
- // Check for current package in include list, if not found, skip it
- if (!packagesToFilter->contains(info.name))
- continue;
- }
- c1 = el.firstChildElement(QInstaller::scVersion);
- if (!c1.isNull())
- info.version = c1.text();
- else
- continue;
-
- info.directory = QString::fromLatin1("%1/%2").arg(it->filePath(), info.name);
- const QDomElement sha1 = el.firstChildElement(QInstaller::scSHA1);
- if (!sha1.isNull()) {
- info.metaFile = QString::fromLatin1("%1/%3%2").arg(info.directory,
- QString::fromLatin1("meta.7z"), info.version);
- }
-
- const QDomNodeList c2 = el.childNodes();
- for (int j = 0; j < c2.count(); ++j) {
- const QDomElement c2Element = c2.at(j).toElement();
- if (c2Element.tagName() == QInstaller::scDependencies)
- info.dependencies = c2Element.text()
- .split(QInstaller::commaRegExp(), QString::SkipEmptyParts);
- else if (c2Element.tagName() == QInstaller::scDownloadableArchives) {
- QStringList names = c2Element.text()
- .split(QInstaller::commaRegExp(), QString::SkipEmptyParts);
- foreach (const QString &name, names) {
- info.copiedFiles.append(QString::fromLatin1("%1/%3%2").arg(info.directory,
- name, info.version));
- info.copiedFiles.append(QString::fromLatin1("%1/%3%2.sha1").arg(info.directory,
- name, info.version));
- }
- }
- }
- QString metaString;
- {
- QTextStream metaStream(&metaString);
- el.save(metaStream, 0);
- }
- info.metaNode = metaString;
- dict.push_back(info);
- qDebug() << "- it provides the package" << info.name << " - " << info.version;
- }
- }
- }
-
- return dict;
-}
-
-QHash<QString, QString> QInstallerTools::buildPathToVersionMapping(const PackageInfoVector &info)
-{
- QHash<QString, QString> map;
- foreach (const PackageInfo &inf, info)
- map[inf.name] = inf.version;
- return map;
-}
-
-static void writeSHA1ToNodeWithName(QDomDocument &doc, QDomNodeList &list, const QByteArray &sha1sum,
- const QString &nodename = QString())
-{
- if (nodename.isEmpty())
- qDebug() << "Writing sha1sum node.";
- else
- qDebug() << "Searching sha1sum node for" << nodename;
- QString sha1Value = QString::fromLatin1(sha1sum.toHex().constData());
- for (int i = 0; i < list.size(); ++i) {
- QDomNode curNode = list.at(i);
- QDomNode nameTag = curNode.firstChildElement(scName);
- if ((!nameTag.isNull() && nameTag.toElement().text() == nodename) || nodename.isEmpty()) {
- QDomNode sha1Node = curNode.firstChildElement(scSHA1);
- QDomNode newSha1Node = doc.createElement(scSHA1);
- newSha1Node.appendChild(doc.createTextNode(sha1Value));
-
- if (!sha1Node.isNull() && sha1Node.hasChildNodes()) {
- QDomNode sha1NodeChild = sha1Node.firstChild();
- QString sha1OldValue = sha1NodeChild.nodeValue();
- if (sha1Value == sha1OldValue) {
- qDebug() << "- keeping the existing sha1sum" << sha1OldValue;
- continue;
- } else {
- qDebug() << "- clearing the old sha1sum" << sha1OldValue;
- sha1Node.removeChild(sha1NodeChild);
- }
- }
- if (sha1Node.isNull())
- curNode.appendChild(newSha1Node);
- else
- curNode.replaceChild(newSha1Node, sha1Node);
- qDebug() << "- writing the sha1sum" << sha1Value;
- }
- }
-}
-
-void QInstallerTools::compressMetaDirectories(const QString &repoDir, const QString &existingUnite7zUrl,
- const QHash<QString, QString> &versionMapping, bool createSplitMetadata, bool createUnifiedMetadata)
-{
- QDomDocument doc;
- // use existing Updates.xml, if any
- QFile existingUpdatesXml(QFileInfo(QDir(repoDir), QLatin1String("Updates.xml")).absoluteFilePath());
- if (!existingUpdatesXml.open(QIODevice::ReadOnly) || !doc.setContent(&existingUpdatesXml)) {
- qDebug() << "Cannot find Updates.xml";
- }
- existingUpdatesXml.close();
-
- QDir dir(repoDir);
- const QStringList entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
-
- QStringList absPaths;
- if (createUnifiedMetadata) {
- absPaths = unifyMetadata(repoDir, existingUnite7zUrl, doc);
- }
-
- if (createSplitMetadata) {
- splitMetadata(entryList, repoDir, doc, versionMapping);
- } else {
- // remove the files that got compressed
- foreach (const QString path, absPaths)
- QInstaller::removeFiles(path, true);
- }
-
- QInstaller::openForWrite(&existingUpdatesXml);
- QInstaller::blockingWrite(&existingUpdatesXml, doc.toByteArray());
- existingUpdatesXml.close();
-}
-
-QStringList QInstallerTools::unifyMetadata(const QString &repoDir, const QString &existingRepoDir, QDomDocument doc)
-{
- QStringList absPaths;
- QDir dir(repoDir);
- const QStringList entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
-
- foreach (const QString &i, entryList) {
- dir.cd(i);
- const QString absPath = dir.absolutePath();
- absPaths.append(absPath);
- dir.cdUp();
- }
-
- QTemporaryDir existingRepoTempDir;
- QString existingRepoTemp = existingRepoTempDir.path();
- if (!existingRepoDir.isEmpty()) {
- existingRepoTempDir.setAutoRemove(false);
- QFile archiveFile(existingRepoDir);
- QInstaller::openForRead(&archiveFile);
- Lib7z::extractArchive(&archiveFile, existingRepoTemp);
- QDir dir(existingRepoTemp);
- QStringList existingRepoEntries = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- foreach (const QString existingRepoEntry, existingRepoEntries) {
- if (entryList.contains(existingRepoEntry)) {
- continue;
- } else {
- dir.cd(existingRepoEntry);
- const QString absPath = dir.absolutePath();
- absPaths.append(absPath);
- }
- }
- }
-
- // Compress all metadata from repository to one single 7z
- const QString metadataFilename = QDateTime::currentDateTime().
- toString(QLatin1String("yyyy-MM-dd-hhmm")) + QLatin1String("_meta.7z");
- const QString tmpTarget = repoDir + QDir::separator() + metadataFilename;
- Lib7z::createArchive(tmpTarget, absPaths, Lib7z::TmpFile::No);
-
- QFile tmp(tmpTarget);
- tmp.open(QFile::ReadOnly);
- const QByteArray sha1Sum = QInstaller::calculateHash(&tmp, QCryptographicHash::Sha1);
- QDomNodeList elements = doc.elementsByTagName(QLatin1String("Updates"));
- writeSHA1ToNodeWithName(doc, elements, sha1Sum, QString());
-
- qDebug() << "Updating the metadata node with name " << metadataFilename;
- if (elements.count() > 0) {
- QDomNode node = elements.at(0);
- QDomNode nameTag = node.firstChildElement(QLatin1String("MetadataName"));
-
- QDomNode newNodeTag = doc.createElement(QLatin1String("MetadataName"));
- newNodeTag.appendChild(doc.createTextNode(metadataFilename));
-
- if (nameTag.isNull())
- node.appendChild(newNodeTag);
- else
- node.replaceChild(newNodeTag, nameTag);
- }
- QInstaller::removeDirectory(existingRepoTemp, true);
- return absPaths;
-}
-
-void QInstallerTools::splitMetadata(const QStringList &entryList, const QString &repoDir,
- QDomDocument doc, const QHash<QString, QString> &versionMapping)
-{
- QStringList absPaths;
- QDomNodeList elements = doc.elementsByTagName(QLatin1String("PackageUpdate"));
- QDir dir(repoDir);
- foreach (const QString &i, entryList) {
- dir.cd(i);
- const QString absPath = dir.absolutePath();
- const QString path = QString(i).remove(repoDir);
- if (path.isNull())
- continue;
- const QString versionPrefix = versionMapping[path];
- const QString fn = QLatin1String(versionPrefix.toLatin1() + "meta.7z");
- const QString tmpTarget = repoDir + QLatin1String("/") + fn;
- Lib7z::createArchive(tmpTarget, QStringList() << absPath, Lib7z::TmpFile::No);
- // remove the files that got compressed
- QInstaller::removeFiles(absPath, true);
- QFile tmp(tmpTarget);
- tmp.open(QFile::ReadOnly);
- const QByteArray sha1Sum = QInstaller::calculateHash(&tmp, QCryptographicHash::Sha1);
- writeSHA1ToNodeWithName(doc, elements, sha1Sum, path);
- const QString finalTarget = absPath + QLatin1String("/") + fn;
- if (!tmp.rename(finalTarget)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot move file \"%1\" to \"%2\".").arg(
- QDir::toNativeSeparators(tmpTarget), QDir::toNativeSeparators(finalTarget)));
- }
- dir.cdUp();
- }
-}
-
-void QInstallerTools::copyComponentData(const QStringList &packageDirs, const QString &repoDir,
- PackageInfoVector *const infos)
-{
- for (int i = 0; i < infos->count(); ++i) {
- const PackageInfo info = infos->at(i);
- const QString name = info.name;
- qDebug() << "Copying component data for" << name;
-
- const QString namedRepoDir = QString::fromLatin1("%1/%2").arg(repoDir, name);
- if (!QDir().mkpath(namedRepoDir)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot create repository directory for component \"%1\".")
- .arg(name));
- }
-
- if (info.copiedFiles.isEmpty()) {
- QStringList compressedFiles;
- QStringList filesToCompress;
- foreach (const QString &packageDir, packageDirs) {
- const QDir dataDir(QString::fromLatin1("%1/%2/data").arg(packageDir, name));
- foreach (const QString &entry, dataDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files)) {
- QFileInfo fileInfo(dataDir.absoluteFilePath(entry));
- if (fileInfo.isFile() && !fileInfo.isSymLink()) {
- const QString absoluteEntryFilePath = dataDir.absoluteFilePath(entry);
- if (Lib7z::isSupportedArchive(absoluteEntryFilePath)) {
- QFile tmp(absoluteEntryFilePath);
- QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, entry, info.version);
- qDebug() << "Copying archive from" << tmp.fileName() << "to" << target;
- if (!tmp.copy(target)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot copy file \"%1\" to \"%2\": %3")
- .arg(QDir::toNativeSeparators(tmp.fileName()), QDir::toNativeSeparators(target), tmp.errorString()));
- }
- compressedFiles.append(target);
- } else {
- filesToCompress.append(absoluteEntryFilePath);
- }
- } else if (fileInfo.isDir()) {
- qDebug() << "Compressing data directory" << entry;
- QString target = QString::fromLatin1("%1/%3%2.7z").arg(namedRepoDir, entry, info.version);
- Lib7z::createArchive(target, QStringList() << dataDir.absoluteFilePath(entry),
- Lib7z::TmpFile::No);
- compressedFiles.append(target);
- } else if (fileInfo.isSymLink()) {
- filesToCompress.append(dataDir.absoluteFilePath(entry));
- }
- }
- }
-
- if (!filesToCompress.isEmpty()) {
- qDebug() << "Compressing files found in data directory:" << filesToCompress;
- QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, QLatin1String("content.7z"),
- info.version);
- Lib7z::createArchive(target, filesToCompress, Lib7z::TmpFile::No);
- compressedFiles.append(target);
- }
-
- foreach (const QString &target, compressedFiles) {
- (*infos)[i].copiedFiles.append(target);
-
- QFile archiveFile(target);
- QFile archiveHashFile(archiveFile.fileName() + QLatin1String(".sha1"));
-
- qDebug() << "Hash is stored in" << archiveHashFile.fileName();
- qDebug() << "Creating hash of archive" << archiveFile.fileName();
-
- try {
- QInstaller::openForRead(&archiveFile);
- const QByteArray hashOfArchiveData = QInstaller::calculateHash(&archiveFile,
- QCryptographicHash::Sha1).toHex();
- archiveFile.close();
-
- QInstaller::openForWrite(&archiveHashFile);
- archiveHashFile.write(hashOfArchiveData);
- qDebug() << "Generated sha1 hash:" << hashOfArchiveData;
- (*infos)[i].copiedFiles.append(archiveHashFile.fileName());
- archiveHashFile.close();
- } catch (const QInstaller::Error &/*e*/) {
- archiveFile.close();
- archiveHashFile.close();
- throw;
- }
- }
- } else {
- foreach (const QString &file, (*infos)[i].copiedFiles) {
- QFileInfo fromInfo(file);
- QFile from(file);
- QString target = QString::fromLatin1("%1/%2").arg(namedRepoDir, fromInfo.fileName());
- qDebug() << "Copying file from" << from.fileName() << "to" << target;
- if (!from.copy(target)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot copy file \"%1\" to \"%2\": %3")
- .arg(QDir::toNativeSeparators(from.fileName()), QDir::toNativeSeparators(target), from.errorString()));
- }
- }
- }
- }
-}
-
-void QInstallerTools::filterNewComponents(const QString &repositoryDir, QInstallerTools::PackageInfoVector &packages)
-{
- QDomDocument doc;
- QFile file(repositoryDir + QLatin1String("/Updates.xml"));
- if (file.open(QFile::ReadOnly) && doc.setContent(&file)) {
- const QDomElement root = doc.documentElement();
- if (root.tagName() != QLatin1String("Updates")) {
- throw QInstaller::Error(QCoreApplication::translate("QInstaller",
- "Invalid content in \"%1\".").arg(QDir::toNativeSeparators(file.fileName())));
- }
- file.close(); // close the file, we read the content already
-
- // read the already existing updates xml content
- const QDomNodeList children = root.childNodes();
- QHash <QString, QInstallerTools::PackageInfo> hash;
- for (int i = 0; i < children.count(); ++i) {
- const QDomElement el = children.at(i).toElement();
- if ((!el.isNull()) && (el.tagName() == QLatin1String("PackageUpdate"))) {
- QInstallerTools::PackageInfo info;
- const QDomNodeList c2 = el.childNodes();
- for (int j = 0; j < c2.count(); ++j) {
- const QDomElement c2Element = c2.at(j).toElement();
- if (c2Element.tagName() == scName)
- info.name = c2Element.text();
- else if (c2Element.tagName() == scVersion)
- info.version = c2Element.text();
- }
- hash.insert(info.name, info);
- }
- }
-
- // remove all components that have no update (decision based on the version tag)
- for (int i = packages.count() - 1; i >= 0; --i) {
- const QInstallerTools::PackageInfo info = packages.at(i);
-
- // check if component already exists & version did not change
- if (hash.contains(info.name) && KDUpdater::compareVersion(info.version, hash.value(info.name).version) < 1) {
- packages.remove(i); // the version did not change, no need to update the component
- continue;
- }
- qDebug() << "Update component" << info.name << "in"<< repositoryDir << ".";
- }
- }
-}
-
-QString QInstallerTools::existingUniteMeta7z(const QString &repositoryDir)
-{
- QString uniteMeta7z = QString();
- QFile file(repositoryDir + QLatin1String("/Updates.xml"));
- QDomDocument doc;
- if (file.open(QFile::ReadOnly) && doc.setContent(&file)) {
- QDomNodeList elements = doc.elementsByTagName(QLatin1String("MetadataName"));
- if (elements.count() > 0 && elements.at(0).isElement()) {
- uniteMeta7z = elements.at(0).toElement().text();
- QFile metaFile(repositoryDir + QDir::separator() + uniteMeta7z);
- if (!metaFile.exists()) {
- throw QInstaller::Error(QString::fromLatin1("Unite meta7z \"%1\" does not exist in repository \"%2\"")
- .arg(QDir::toNativeSeparators(metaFile.fileName()), repositoryDir));
- }
- }
- }
- return uniteMeta7z;
-}