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.cpp622
1 files changed, 622 insertions, 0 deletions
diff --git a/tools/common/repositorygen.cpp b/tools/common/repositorygen.cpp
new file mode 100644
index 000000000..84ed0e658
--- /dev/null
+++ b/tools/common/repositorygen.cpp
@@ -0,0 +1,622 @@
+/**************************************************************************
+**
+** This file is part of Installer Framework
+**
+** Copyright (c) 2011-2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+#include "repositorygen.h"
+
+#include <fileutils.h>
+#include <errors.h>
+#include <lib7z_facade.h>
+#include <settings.h>
+
+#include <kdupdater.h>
+
+#include <QtCore/QCryptographicHash>
+#include <QtCore/QDirIterator>
+
+#include <QtXml/QDomDocument>
+
+#include <iostream>
+
+using namespace QInstallerTools;
+
+void QInstallerTools::printRepositoryGenOptions()
+{
+ std::cout << " -c|--config dir The directory containing the installer configuration" << std::endl;
+
+ std::cout << " -p|--packages dir The directory containing the available packages." << std::endl;
+ std::cout << " Defaults to the current working directory." << 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 from the "
+ << "repository." << std::endl;
+ std::cout << " --ignore-translations Don't use any translation" << std::endl;
+ std::cout << " --ignore-invalid-packages Ignore all invalid packages instead of aborting." << std::endl;
+}
+
+void QInstallerTools::compressDirectory(const QStringList &paths, const QString &archivePath)
+{
+ foreach (const QString &path, paths) {
+ if (!QFileInfo(path).exists())
+ throw QInstaller::Error(QObject::tr("Folder %1 does not exist.").arg(path));
+ }
+
+ QFile archive(archivePath);
+ QInstaller::openForWrite(&archive, archivePath);
+ Lib7z::createArchive(&archive, paths);
+}
+
+void QInstallerTools::compressMetaDirectories(const QString &repoDir)
+{
+ QDir dir(repoDir);
+ const QStringList sub = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ foreach (const QString &i, sub) {
+ QDir sd(dir);
+ sd.cd(i);
+ const QString absPath = sd.absolutePath();
+ const QString fn = QLatin1String("meta.7z");
+ const QString tmpTarget = repoDir + QLatin1String("/") +fn;
+ compressDirectory(QStringList() << absPath, tmpTarget);
+ QFile tmp(tmpTarget);
+ const QString finalTarget = absPath + QLatin1String("/") + fn;
+ if (!tmp.rename(finalTarget)) {
+ throw QInstaller::Error(QObject::tr("Could not move %1 to %2").arg(tmpTarget,
+ finalTarget));
+ }
+ }
+}
+
+void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QString &dataDir,
+ const PackageInfoVector &packages, const QString &appName, const QString &appVersion,
+ const QString &redirectUpdateUrl)
+{
+ QString metapath = outDir;
+ if (QFileInfo(metapath).isRelative())
+ metapath = QDir::cleanPath(QDir::current().absoluteFilePath(metapath));
+ qDebug() << "Generating meta data...";
+
+ if (!QFile::exists(metapath))
+ QInstaller::mkpath(metapath);
+
+ QDomDocument doc;
+ QDomElement root;
+ // use existing Updates.xml, if any
+ QFile existingUpdatesXml(QFileInfo(dataDir, QLatin1String("Updates.xml")).absoluteFilePath());
+ if (!existingUpdatesXml.open(QIODevice::ReadOnly) || !doc.setContent(&existingUpdatesXml)) {
+ 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")));
+ if (!redirectUpdateUrl.isEmpty()) {
+ root.appendChild(doc.createElement(QLatin1String("RedirectUpdateUrl"))).appendChild(
+ doc.createTextNode(redirectUpdateUrl));
+ }
+ } else {
+ root = doc.documentElement();
+ }
+
+ for (PackageInfoVector::const_iterator it = packages.begin(); it != packages.end(); ++it) {
+ const QString packageXmlPath = QString::fromLatin1("%1/meta/package.xml").arg(it->directory);
+ qDebug() << QString::fromLatin1("\tGenerating meta data for package %1 using %2.").arg(
+ it->name, packageXmlPath);
+
+ // remove existing entry for this component from existing Updates.xml
+ const QDomNodeList packageNodes = root.childNodes();
+ for (int i = 0; i < packageNodes.count(); ++i) {
+ const QDomNode node = packageNodes.at(i);
+ if (node.nodeName() != QLatin1String("PackageUpdate"))
+ continue;
+ if (node.firstChildElement(QLatin1String("Name")).text() != it->name)
+ continue;
+ root.removeChild(node);
+ --i;
+ }
+
+ QDomDocument packageXml;
+ QFile file(packageXmlPath);
+ QInstaller::openForRead(&file, packageXmlPath);
+ QString errMsg;
+ int col = 0;
+ int line = 0;
+ if (!packageXml.setContent(&file, &errMsg, &line, &col)) {
+ throw QInstaller::Error(QObject::tr("Could not parse %1: line: %2, column: %3: %4 (%5)")
+ .arg(packageXmlPath, QString::number(line), QString::number(col), errMsg, it->name));
+ }
+ const QDomNode package = packageXml.firstChildElement(QLatin1String("Package"));
+
+ QDomElement update = doc.createElement(QLatin1String("PackageUpdate"));
+
+ const QDomNodeList childNodes = package.childNodes();
+ for (int i = 0; i < childNodes.count(); ++i) {
+ const QDomNode node = childNodes.at(i);
+ // just skip the comments...
+ if (node.isComment())
+ continue;
+ const QString key = node.nodeName();
+ if (key == QLatin1String("UserInterfaces"))
+ continue;
+ if (key == QLatin1String("Translations"))
+ continue;
+ if (key == QLatin1String("Licenses"))
+ continue;
+ const QString value = node.toElement().text();
+ QDomElement element = doc.createElement(key);
+ for (int i = 0; i < node.attributes().size(); i++) {
+ element.setAttribute(node.attributes().item(i).toAttr().name(),
+ node.attributes().item(i).toAttr().value());
+ }
+ update.appendChild(element).appendChild(doc.createTextNode(value));
+ }
+
+ // get the size of the data
+ quint64 componentSize = 0;
+ quint64 compressedComponentSize = 0;
+
+ const QString cmpDataDir = QString::fromLatin1("%1/%2").arg(dataDir, it->name);
+ const QFileInfoList entries = !QDir(cmpDataDir + QLatin1String("/data")).exists()
+ ? QDir(cmpDataDir).entryInfoList(QDir::Files | QDir::NoDotAndDotDot)
+ : QDir(cmpDataDir + QLatin1String("/data")).entryInfoList(QDir::Files
+ | QDir::Dirs | QDir::NoDotAndDotDot);
+
+ foreach (const QFileInfo &fi, entries) {
+ if (fi.isHidden())
+ continue;
+
+ try {
+ if (fi.isDir()) {
+ QDirIterator recursDirIt(fi.filePath(), QDirIterator::Subdirectories);
+ while (recursDirIt.hasNext()) {
+ componentSize += QFile(recursDirIt.next()).size();
+ compressedComponentSize += QFile(recursDirIt.next()).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();
+ archive.open(QIODevice::ReadOnly);
+ const QVector< Lib7z::File > files = Lib7z::listArchive(&archive);
+ for (QVector< Lib7z::File >::const_iterator fileIt = files.begin();
+ fileIt != files.end(); ++fileIt) {
+ componentSize += fileIt->uncompressedSize;
+ }
+ } else {
+ // otherwise just add its size
+ componentSize += fi.size();
+ compressedComponentSize += fi.size();
+ }
+ } catch(...) {
+ // ignore, that's just about the sizes - and size doesn't matter, you know?
+ }
+ }
+
+ // add fake update files
+ const QStringList platforms = QStringList() << QLatin1String("Windows") << QLatin1String("MacOSX")
+ << QLatin1String("Linux");
+ foreach (const QString &platform, platforms) {
+ QDomElement file = doc.createElement(QLatin1String("UpdateFile"));
+ file.setAttribute(QLatin1String("OS"), platform);
+ file.setAttribute(QLatin1String("UncompressedSize"), componentSize);
+ file.setAttribute(QLatin1String("CompressedSize"), compressedComponentSize);
+ file.appendChild(doc.createTextNode(QLatin1String("(null)")));
+ update.appendChild(file);
+ }
+
+ root.appendChild(update);
+
+ if (!QDir(metapath).mkpath(it->name))
+ throw QInstaller::Error(QObject::tr("Could not create directory %1.").arg(it->name));
+
+ // copy scripts
+ const QString script = package.firstChildElement(QLatin1String("Script")).text();
+ if (!script.isEmpty()) {
+
+ QFile scriptFile(script);
+ QString scriptContent;
+ if (scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream in(&scriptFile);
+ scriptContent = in.readAll();
+ }
+
+ // added the xml tag RequiresAdminRights to the xml if somewhere addElevatedOperation is used
+ if (scriptContent.contains(QLatin1String("addElevatedOperation"))) {
+ QDomElement requiresAdminRightsElement =
+ doc.createElement(QLatin1String("RequiresAdminRights"));
+ requiresAdminRightsElement.appendChild(doc.createTextNode(QLatin1String("true")));
+ }
+
+ qDebug() << "\tCopying associated script" << script << "into the meta package...";
+ QString fromLocation(QString::fromLatin1("%1/meta/%2").arg(it->directory, script));
+ QString toLocation(QString::fromLatin1("%1/%2/%3").arg(metapath, it->name, script));
+ if (!QFile::copy(fromLocation, toLocation)) {
+ qDebug() << "failed!";
+ throw QInstaller::Error(QObject::tr("Could not copy the script %1 to its target location %2.")
+ .arg(fromLocation, toLocation));
+ } else {
+ qDebug() << "\tdone.";
+ }
+ }
+
+ // copy user interfaces
+ const QDomNodeList uiNodes = package.firstChildElement(QLatin1String("UserInterfaces")).childNodes();
+ QStringList userinterfaces;
+ for (int i = 0; i < uiNodes.count(); ++i) {
+ const QDomNode node = uiNodes.at(i);
+ if (node.nodeName() != QLatin1String("UserInterface"))
+ continue;
+
+ const QDir dir(QString::fromLatin1("%1/meta").arg(it->directory));
+ const QStringList uis = dir.entryList(QStringList(node.toElement().text()), QDir::Files);
+ if (uis.isEmpty()) {
+ throw QInstaller::Error(QObject::tr("Couldn't find any user interface matching %1 while "
+ "copying user interfaces of %2.").arg(node.toElement().text(), it->name));
+ }
+
+ for (QStringList::const_iterator ui = uis.begin(); ui != uis.end(); ++ui) {
+ qDebug() << "\tCopying associated user interface " << *ui << " into the meta "
+ "package...";
+ userinterfaces.push_back(*ui);
+ if (!QFile::copy(QString::fromLatin1("%1/meta/%2").arg(it->directory, *ui),
+ QString::fromLatin1("%1/%2/%3").arg(metapath, it->name, *ui))) {
+ qDebug() << "failed!";
+ throw QInstaller::Error(QObject::tr("Could not copy the UI file %1 to its target "
+ "location %2.").arg(*ui, it->name));
+ } else {
+ qDebug() << "done";
+ }
+ }
+ }
+
+ if (!userinterfaces.isEmpty()) {
+ update.appendChild(doc.createElement(QLatin1String("UserInterfaces")))
+ .appendChild(doc.createTextNode(userinterfaces.join(QChar::fromLatin1(','))));
+ }
+
+ // copy translations
+ const QDomNodeList qmNodes = package.firstChildElement(QLatin1String("Translations")).childNodes();
+ QStringList translations;
+ if (!qApp->arguments().contains(QString::fromLatin1("--ignore-translations"))) {
+ for (int i = 0; i < qmNodes.count(); ++i) {
+ const QDomNode node = qmNodes.at(i);
+ if (node.nodeName() != QLatin1String("Translation"))
+ continue;
+
+ const QDir dir(QString::fromLatin1("%1/meta").arg(it->directory));
+ const QStringList qms = dir.entryList(QStringList(node.toElement().text()), QDir::Files);
+ if (qms.isEmpty()) {
+ throw QInstaller::Error(QObject::tr("Could not find any translation file matching %1 "
+ "while copying translations of %2.").arg(node.toElement().text(), it->name));
+ }
+
+ for (QStringList::const_iterator qm = qms.begin(); qm != qms.end(); ++qm) {
+ qDebug() << "\tCopying associated translation " << *qm << " into the meta "
+ "package...";
+ translations.push_back(*qm);
+ if (!QFile::copy(QString::fromLatin1("%1/meta/%2").arg(it->directory, *qm),
+ QString::fromLatin1("%1/%2/%3").arg(metapath, it->name, *qm))) {
+ qDebug() << "failed!";
+ throw QInstaller::Error(QObject::tr("Could not copy the translation %1 to its "
+ "target location %2.").arg(*qm, it->name));
+ } else {
+ qDebug() << "done";
+ }
+ }
+ }
+
+ if (!translations.isEmpty()) {
+ update.appendChild(doc.createElement(QLatin1String("Translations")))
+ .appendChild(doc.createTextNode(translations.join(QChar::fromLatin1(','))));
+ }
+
+ }
+
+ // copy license files
+ const QDomNodeList licenseNodes = package.firstChildElement(QLatin1String("Licenses")).childNodes();
+ for (int i = 0; i < licenseNodes.count(); ++i) {
+ const QDomNode licenseNode = licenseNodes.at(i);
+ if (licenseNode.nodeName() == QLatin1String("License")) {
+ const QString &licenseFile =
+ licenseNode.toElement().attributeNode(QLatin1String("file")).value();
+ const QString &sourceFile =
+ QString::fromLatin1("%1/meta/%2").arg(it->directory).arg(licenseFile);
+ if (!QFile::exists(sourceFile)) {
+ throw QInstaller::Error(QObject::tr("Could not find any license matching %1 while "
+ "copying license files of %2.").arg(licenseFile, it->name));
+ }
+
+ qDebug() << "\tCopying associated license file " << licenseFile << " into "
+ "the meta package...";
+ if (!QFile::copy(sourceFile, QString::fromLatin1("%1/%2/%3")
+ .arg(metapath, it->name, licenseFile))) {
+ qDebug() << "failed!";
+ throw QInstaller::Error(QObject::tr("Could not copy the license file %1 to its "
+ "target location %2.").arg(licenseFile, it->name));
+ } else {
+ qDebug() << "done.";
+ }
+
+ // Translated License files
+ for (int j = 0; j < translations.size(); ++j) {
+ QFileInfo translationFile(translations.at(j));
+ QFileInfo untranslated(licenseFile);
+ const QString &translatedLicenseFile =
+ QString::fromLatin1("%2_%3.%4").arg(untranslated.baseName(),
+ translationFile.baseName(), untranslated.completeSuffix());
+ const QString &translatedSourceFile =
+ QString::fromLatin1("%1/meta/%2").arg(it->directory).arg(translatedLicenseFile);
+ if (!QFile::exists(translatedSourceFile)) {
+ qDebug() << "Could not find translated license file" << translatedSourceFile;
+ continue;
+ }
+
+ qDebug() << "\tCopying associated license file" << translatedLicenseFile
+ << "into the meta package...";
+
+ if (!QFile::copy(translatedSourceFile, QString::fromLatin1("%1/%2/%3")
+ .arg(metapath, it->name, translatedLicenseFile))) {
+ qDebug() << "\tfailed!";
+ } else {
+ qDebug() << "\tdone.";
+ }
+ }
+ }
+ }
+
+ if (licenseNodes.count() > 0)
+ update.appendChild(package.firstChildElement(QLatin1String("Licenses")).cloneNode());
+ }
+
+ doc.appendChild(root);
+
+ const QString updatesXmlFile = QFileInfo(metapath, QLatin1String("Updates.xml")).absoluteFilePath();
+ QFile updatesXml(updatesXmlFile);
+
+ QInstaller::openForWrite(&updatesXml, updatesXmlFile);
+ QInstaller::blockingWrite(&updatesXml, doc.toByteArray());
+}
+
+PackageInfoVector QInstallerTools::createListOfPackages(const QString &packagesDirectory,
+ const QStringList &filteredPackages, FilterType filterType)
+{
+ qDebug() << "Collecting information about available packages...";
+
+ bool ignoreInvalidPackages = qApp->arguments().contains(QString::fromLatin1("--ignore-invalid-packages"));
+
+ PackageInfoVector dict;
+ const QFileInfoList entries = QDir(packagesDirectory)
+ .entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ for (QFileInfoList::const_iterator it = entries.begin(); it != entries.end(); ++it) {
+ if (filterType == Exclude) {
+ if (filteredPackages.contains(it->fileName()))
+ continue;
+ } else {
+ if (!filteredPackages.contains(it->fileName()))
+ continue;
+ }
+ qDebug() << QString::fromLatin1("\tfound subdirectory %1").arg(it->fileName());
+ // because the filter is QDir::Dirs - filename means the name of the subdirectory
+ if (it->fileName().contains(QLatin1Char('-'))) {
+ if (ignoreInvalidPackages)
+ continue;
+ throw QInstaller::Error(QObject::tr("Component %1 can't contain '-'. This is not allowed, because "
+ "it is used as the separator between the component name and the version number internally.")
+ .arg(it->fileName()));
+ }
+
+ QFile file(QString::fromLatin1("%1/meta/package.xml").arg(it->filePath()));
+ if (!file.exists()) {
+ if (ignoreInvalidPackages)
+ continue;
+ throw QInstaller::Error(QObject::tr("Component %1 does not contain a package "
+ "description(meta/package.xml is missing).").arg(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(QObject::tr("Component package description for %1 is invalid. "
+ "Error at line: %2, column: %3 -> %4").arg(it->fileName(), QString::number(errorLine),
+ QString::number(errorColumn), error));
+ }
+
+ const QString name = doc.firstChildElement(QLatin1String("Package"))
+ .firstChildElement(QLatin1String("Name")).text();
+ if (name != it->fileName()) {
+ if (ignoreInvalidPackages)
+ continue;
+ throw QInstaller::Error(QObject::tr("Component folder name must match component name: "
+ "%1 in %2/").arg(name, it->fileName()));
+ }
+
+ PackageInfo info;
+ info.name = name;
+ info.version = doc.firstChildElement(QLatin1String("Package")).
+ firstChildElement(QLatin1String("Version")).text();
+ if (!QRegExp(QLatin1String("[0-9]+((\\.|-)[0-9]+)*")).exactMatch(info.version)) {
+ if (ignoreInvalidPackages)
+ continue;
+ throw QInstaller::Error(QObject::tr("Component version for %1 is invalid! <Version>%2</version>")
+ .arg(it->fileName(), info.version));
+ }
+ info.dependencies = doc.firstChildElement(QLatin1String("Package")).
+ firstChildElement(QLatin1String("Dependencies")).text().split(QRegExp(QLatin1String("\\b(,|, )\\b")),
+ QString::SkipEmptyParts);
+ info.directory = it->filePath();
+ dict.push_back(info);
+
+ qDebug() << QString::fromLatin1("\t- it provides the package %1 - %2").arg(name, info.version);
+ }
+
+ if (dict.isEmpty())
+ qDebug() << "No available packages found at the specified location.";
+
+ return dict;
+}
+
+QMap<QString, QString> QInstallerTools::buildPathToVersionMap(const PackageInfoVector &info)
+{
+ QMap<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)
+{
+ qDebug() << "searching sha1sum node for" << nodename;
+ for (int i = 0; i < list.size(); ++i) {
+ QDomNode curNode = list.at(i);
+ QDomNode nameTag = curNode.firstChildElement(QLatin1String("Name"));
+ if (!nameTag.isNull() && nameTag.toElement().text() == nodename) {
+ QDomNode sha1Node = doc.createElement(QLatin1String("SHA1"));
+ sha1Node.appendChild(doc.createTextNode(QString::fromLatin1(sha1sum.toHex().constData())));
+ curNode.appendChild(sha1Node);
+ }
+ }
+}
+
+void QInstallerTools::compressMetaDirectories(const QString &repoDir, const QString &baseDir,
+ const QMap<QString, QString> &versionMapping)
+{
+ QDomDocument doc;
+ QDomElement root;
+ // use existing Updates.xml, if any
+ QFile existingUpdatesXml(QFileInfo(QDir(repoDir), QLatin1String("Updates.xml")).absoluteFilePath());
+ if (!existingUpdatesXml.open(QIODevice::ReadOnly) || !doc.setContent(&existingUpdatesXml)) {
+ qDebug() << "Could not find Updates.xml";
+ } else {
+ root = doc.documentElement();
+ }
+ existingUpdatesXml.close();
+
+ QDir dir(repoDir);
+ const QStringList sub = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ QDomNodeList elements = doc.elementsByTagName(QLatin1String("PackageUpdate"));
+ foreach (const QString &i, sub) {
+ QDir sd(dir);
+ sd.cd(i);
+ const QString path = QString(i).remove(baseDir);
+ const QString versionPrefix = versionMapping[path];
+ if (path.isNull())
+ continue;
+ const QString absPath = sd.absolutePath();
+ const QString fn = QLatin1String(versionPrefix.toLatin1() + "meta.7z");
+ const QString tmpTarget = repoDir + QLatin1String("/") +fn;
+ compressDirectory(QStringList() << absPath, tmpTarget);
+
+ // remove the files that got compressed
+ QInstaller::removeFiles(absPath, true);
+
+ QFile tmp(tmpTarget);
+ tmp.open(QFile::ReadOnly);
+ QByteArray fileToCheck = tmp.readAll();
+ QByteArray sha1Sum = QCryptographicHash::hash(fileToCheck, QCryptographicHash::Sha1);
+ writeSHA1ToNodeWithName(doc, elements, sha1Sum, path);
+ const QString finalTarget = absPath + QLatin1String("/") + fn;
+ if (!tmp.rename(finalTarget))
+ throw QInstaller::Error(QObject::tr("Could not move %1 to %2").arg(tmpTarget, finalTarget));
+ }
+
+ QInstaller::openForWrite(&existingUpdatesXml, existingUpdatesXml.fileName());
+ QInstaller::blockingWrite(&existingUpdatesXml, doc.toByteArray());
+ existingUpdatesXml.close();
+}
+
+void QInstallerTools::copyComponentData(const QString &packageDir, const QString &repoDir,
+ PackageInfoVector &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 dataDirPath = QString::fromLatin1("%1/%2/data").arg(packageDir, name);
+ const QDir dataDir(dataDirPath);
+ if (!QDir().mkpath(QString::fromLatin1("%1/%2").arg(repoDir, name))) {
+ throw QInstaller::Error(QObject::tr("Could not create repository folder for component %1")
+ .arg(name));
+ }
+
+ const QStringList entries = dataDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files);
+ foreach (const QString &entry, entries) {
+ QString target;
+ QFileInfo fileInfo(dataDir.absoluteFilePath(entry));
+ if (fileInfo.isFile()) {
+ target = QString::fromLatin1("%1/%2/%4%3").arg(repoDir, name, entry, info.version);
+ QFile tmp(dataDir.absoluteFilePath(entry));
+ qDebug() << QString::fromLatin1("Copying archive from %1 to %2").arg(tmp.fileName(), target);
+ QInstaller::openForRead(&tmp, tmp.fileName());
+ if (!tmp.copy(target)) {
+ throw QInstaller::Error(QObject::tr("Could not copy %1 to %2: %3").arg(tmp.fileName(),
+ target, tmp.errorString()));
+ }
+ } else if (fileInfo.isDir()) {
+ qDebug() << "Compressing data directory" << entry;
+ target = QString::fromLatin1("%1/%2/%4%3.7z").arg(repoDir, name, entry, info.version);
+ QInstallerTools::compressDirectory(QStringList() << dataDir.absoluteFilePath(entry), target);
+ } else {
+ continue;
+ }
+ infos[i].copiedArchives.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, archiveFile.fileName());
+ const QByteArray archiveData = archiveFile.readAll();
+ archiveFile.close();
+
+ QInstaller::openForWrite(&archiveHashFile, archiveHashFile.fileName());
+ const QByteArray hashOfArchiveData = QCryptographicHash::hash(archiveData,
+ QCryptographicHash::Sha1).toHex();
+ archiveHashFile.write(hashOfArchiveData);
+ qDebug() << "Generated sha1 hash:" << hashOfArchiveData;
+ infos[i].copiedArchives.append(archiveHashFile.fileName());
+ archiveHashFile.close();
+ } catch (const QInstaller::Error &/*e*/) {
+ archiveFile.close();
+ archiveHashFile.close();
+ throw;
+ }
+ }
+ }
+}