diff options
author | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2020-11-20 17:09:30 +0200 |
---|---|---|
committer | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2020-12-02 10:25:18 +0000 |
commit | 885a41d1667ac8ccf59a4de76cb8449074a466ac (patch) | |
tree | 7e0909c5b06754f458c6b6e7d3a77a4ffd994be7 /tools | |
parent | f053b9a627921b03529b4f797a97b582675fbe71 (diff) |
Tools: refactor to move general purpose functionality to installer lib
This makes it possible to utilize parts of our existing tooling in the
offline installer from online installer generation process.
Task-number: QTIFW-2048
Change-Id: I7ee605be75541cc83a3b6909089bda45f0835bcf
Reviewed-by: Katja Marttila <katja.marttila@qt.io>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/archivegen/archivegen.pro | 6 | ||||
-rw-r--r-- | tools/binarycreator/binarycreator.cpp | 1043 | ||||
-rw-r--r-- | tools/binarycreator/binarycreator.pro | 9 | ||||
-rw-r--r-- | tools/binarycreator/binarycreator.qrc | 7 | ||||
-rw-r--r-- | tools/binarycreator/main.cpp | 210 | ||||
-rw-r--r-- | tools/binarycreator/rcc/qcorecmdlineargs_p.h | 59 | ||||
-rw-r--r-- | tools/binarycreator/rcc/rcc.cpp | 1038 | ||||
-rw-r--r-- | tools/binarycreator/rcc/rcc.h | 140 | ||||
-rw-r--r-- | tools/binarycreator/rcc/rccmain.cpp | 239 | ||||
-rw-r--r-- | tools/binarycreator/resources/copylibsintobundle.sh | 189 | ||||
-rw-r--r-- | tools/binarycreator/resources/default_icon_mac.icns | bin | 118992 -> 0 bytes | |||
-rw-r--r-- | tools/common/repositorygen.cpp | 965 | ||||
-rw-r--r-- | tools/common/repositorygen.h | 87 | ||||
-rw-r--r-- | tools/repogen/repogen.cpp | 4 | ||||
-rw-r--r-- | tools/repogen/repogen.pri | 1 | ||||
-rw-r--r-- | tools/repogen/repogen.pro | 5 |
16 files changed, 217 insertions, 3785 deletions
diff --git a/tools/archivegen/archivegen.pro b/tools/archivegen/archivegen.pro index 2cb8b6bdc..0a5032d2f 100644 --- a/tools/archivegen/archivegen.pro +++ b/tools/archivegen/archivegen.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = archivegen -INCLUDEPATH += . .. ../common +INCLUDEPATH += . .. include(../../installerfw.pri) @@ -11,9 +11,7 @@ LIBS += -l7z CONFIG += console DESTDIR = $$IFW_APP_PATH -SOURCES += archive.cpp \ - ../common/repositorygen.cpp -HEADERS += ../common/repositorygen.h +SOURCES += archive.cpp macx:include(../../no_app_bundle.pri) diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp deleted file mode 100644 index f6662615e..000000000 --- a/tools/binarycreator/binarycreator.cpp +++ /dev/null @@ -1,1043 +0,0 @@ -/************************************************************************** -** -** Copyright (C) 2017 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 "common/repositorygen.h" - -#include <qtpatch.h> - -#include <binarycontent.h> -#include <binaryformat.h> -#include <errors.h> -#include <fileio.h> -#include <fileutils.h> -#include <init.h> -#include <repository.h> -#include <settings.h> -#include <utils.h> - -#include <QDateTime> -#include <QDirIterator> -#include <QDomDocument> -#include <QProcess> -#include <QRegExp> -#include <QSettings> -#include <QTemporaryFile> -#include <QTemporaryDir> - -#include <iostream> - -#ifdef Q_OS_MACOS -#include <QtCore/QtEndian> -#include <QtCore/QFile> -#include <QtCore/QVersionNumber> - -#include <mach-o/fat.h> -#include <mach-o/loader.h> -#endif - -using namespace QInstaller; - -struct Input { - QString outputPath; - QString installerExePath; - QInstallerTools::PackageInfoVector packages; - QInstaller::ResourceCollectionManager manager; -}; - -class BundleBackup -{ -public: - explicit BundleBackup(const QString &bundle = QString()) - : bundle(bundle) - { - if (!bundle.isEmpty() && QFileInfo(bundle).exists()) { - backup = generateTemporaryFileName(bundle); - QFile::rename(bundle, backup); - } - } - - ~BundleBackup() - { - if (!backup.isEmpty()) { - removeDirectory(bundle); - QFile::rename(backup, bundle); - } - } - - void release() const - { - if (!backup.isEmpty()) - removeDirectory(backup); - backup.clear(); - } - -private: - const QString bundle; - mutable QString backup; -}; - -#ifndef Q_OS_WIN -static void chmod755(const QString &absolutFilePath) -{ - QFile::setPermissions(absolutFilePath, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner - | QFile::ReadGroup | QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther); -} -#endif - -#ifdef Q_OS_MACOS -template <typename T = uint32_t> T readInt(QIODevice *ioDevice, bool *ok, - bool swap, bool peek = false) { - const auto bytes = peek - ? ioDevice->peek(sizeof(T)) - : ioDevice->read(sizeof(T)); - if (bytes.size() != sizeof(T)) { - if (ok) - *ok = false; - return T(); - } - if (ok) - *ok = true; - T n = *reinterpret_cast<const T *>(bytes.constData()); - return swap ? qbswap(n) : n; -} - -static QVersionNumber readMachOMinimumSystemVersion(QIODevice *device) -{ - bool ok; - std::vector<qint64> machoOffsets; - - qint64 pos = device->pos(); - uint32_t magic = readInt(device, &ok, false); - if (magic == FAT_MAGIC || magic == FAT_CIGAM || - magic == FAT_MAGIC_64 || magic == FAT_CIGAM_64) { - bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64; - uint32_t nfat = readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - for (uint32_t n = 0; n < nfat; ++n) { - const bool is64bit = magic == FAT_MAGIC_64 || magic == FAT_CIGAM_64; - fat_arch_64 fat_arch; - fat_arch.cputype = static_cast<cpu_type_t>(readInt(device, &ok, swap)); - if (!ok) - return QVersionNumber(); - - fat_arch.cpusubtype = static_cast<cpu_subtype_t>(readInt(device, &ok, swap)); - if (!ok) - return QVersionNumber(); - - fat_arch.offset = is64bit - ? readInt<uint64_t>(device, &ok, swap) : readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - fat_arch.size = is64bit - ? readInt<uint64_t>(device, &ok, swap) : readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - fat_arch.align = readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - fat_arch.reserved = is64bit ? readInt(device, &ok, swap) : 0; - if (!ok) - return QVersionNumber(); - - machoOffsets.push_back(static_cast<qint64>(fat_arch.offset)); - } - } else if (!ok) { - return QVersionNumber(); - } - - // Wasn't a fat file, so we just read a thin Mach-O from the original offset - if (machoOffsets.empty()) - machoOffsets.push_back(pos); - - std::vector<QVersionNumber> versions; - - for (const auto &offset : machoOffsets) { - if (!device->seek(offset)) - return QVersionNumber(); - - bool swap = false; - mach_header_64 header; - header.magic = readInt(device, nullptr, swap); - switch (header.magic) { - case MH_CIGAM: - case MH_CIGAM_64: - swap = true; - break; - case MH_MAGIC: - case MH_MAGIC_64: - break; - default: - return QVersionNumber(); - } - - header.cputype = static_cast<cpu_type_t>(readInt(device, &ok, swap)); - if (!ok) - return QVersionNumber(); - - header.cpusubtype = static_cast<cpu_subtype_t>(readInt(device, &ok, swap)); - if (!ok) - return QVersionNumber(); - - header.filetype = readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - header.ncmds = readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - header.sizeofcmds = readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - header.flags = readInt(device, &ok, swap); - if (!ok) - return QVersionNumber(); - - header.reserved = header.magic == MH_MAGIC_64 || header.magic == MH_CIGAM_64 - ? readInt(device, &ok, swap) : 0; - if (!ok) - return QVersionNumber(); - - for (uint32_t i = 0; i < header.ncmds; ++i) { - const uint32_t cmd = readInt(device, nullptr, swap); - const uint32_t cmdsize = readInt(device, nullptr, swap); - if (cmd == 0 || cmdsize == 0) - return QVersionNumber(); - - switch (cmd) { - case LC_VERSION_MIN_MACOSX: - case LC_VERSION_MIN_IPHONEOS: - case LC_VERSION_MIN_TVOS: - case LC_VERSION_MIN_WATCHOS: - const uint32_t version = readInt(device, &ok, swap, true); - if (!ok) - return QVersionNumber(); - - versions.push_back(QVersionNumber( - static_cast<int>(version >> 16), - static_cast<int>((version >> 8) & 0xff), - static_cast<int>(version & 0xff))); - break; - } - - const qint64 remaining = static_cast<qint64>(cmdsize - sizeof(cmd) - sizeof(cmdsize)); - if (device->read(remaining).size() != remaining) - return QVersionNumber(); - } - } - - std::sort(versions.begin(), versions.end()); - return !versions.empty() ? versions.front() : QVersionNumber(); -} -#endif - -static int assemble(Input input, const QInstaller::Settings &settings, const QString &signingIdentity) -{ -#ifdef Q_OS_MACOS - if (QInstaller::isInBundle(input.installerExePath)) { - const QString bundle = input.installerExePath; - // if the input file was a bundle - const QSettings s(QString::fromLatin1("%1/Contents/Info.plist").arg(input.installerExePath), - QSettings::NativeFormat); - input.installerExePath = QString::fromLatin1("%1/Contents/MacOS/%2").arg(bundle) - .arg(s.value(QLatin1String("CFBundleExecutable"), - QFileInfo(input.installerExePath).completeBaseName()).toString()); - } - - const bool createDMG = input.outputPath.endsWith(QLatin1String(".dmg")); - if (createDMG) - input.outputPath.replace(input.outputPath.length() - 4, 4, QLatin1String(".app")); - - const bool isBundle = input.outputPath.endsWith(QLatin1String(".app")); - const QString bundle = isBundle ? input.outputPath : QString(); - const BundleBackup bundleBackup(bundle); - - if (isBundle) { - // output should be a bundle - const QFileInfo fi(input.outputPath); - - QString minimumSystemVersion; - QFile file(input.installerExePath); - if (file.open(QIODevice::ReadOnly)) - minimumSystemVersion = readMachOMinimumSystemVersion(&file).normalized().toString(); - - const QString contentsResourcesPath = fi.filePath() + QLatin1String("/Contents/Resources/"); - - QInstaller::mkpath(fi.filePath() + QLatin1String("/Contents/MacOS")); - QInstaller::mkpath(contentsResourcesPath); - - { - QFile pkgInfo(fi.filePath() + QLatin1String("/Contents/PkgInfo")); - pkgInfo.open(QIODevice::WriteOnly); - QTextStream pkgInfoStream(&pkgInfo); - pkgInfoStream << QLatin1String("APPL????") << endl; - } - - QString iconFile; - if (QFile::exists(settings.installerApplicationIcon())) { - iconFile = settings.installerApplicationIcon(); - } else { - iconFile = QString::fromLatin1(":/resources/default_icon_mac.icns"); - } - - const QString iconTargetFile = fi.completeBaseName() + QLatin1String(".icns"); - QFile::copy(iconFile, contentsResourcesPath + iconTargetFile); - if (QDir(qApp->applicationDirPath() + QLatin1String("/qt_menu.nib")).exists()) { - copyDirectoryContents(qApp->applicationDirPath() + QLatin1String("/qt_menu.nib"), - contentsResourcesPath + QLatin1String("/qt_menu.nib")); - } - - QFile infoPList(fi.filePath() + QLatin1String("/Contents/Info.plist")); - infoPList.open(QIODevice::WriteOnly); - QTextStream plistStream(&infoPList); - plistStream << QLatin1String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") << endl; - plistStream << QLatin1String("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" " - "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">") << endl; - plistStream << QLatin1String("<plist version=\"1.0\">") << endl; - plistStream << QLatin1String("<dict>") << endl; - plistStream << QLatin1String("\t<key>CFBundleIconFile</key>") << endl; - plistStream << QLatin1String("\t<string>") << iconTargetFile << QLatin1String("</string>") - << endl; - plistStream << QLatin1String("\t<key>CFBundlePackageType</key>") << endl; - plistStream << QLatin1String("\t<string>APPL</string>") << endl; -#define QUOTE_(x) #x -#define QUOTE(x) QUOTE_(x) - plistStream << QLatin1String("\t<key>CFBundleShortVersionString</key>") << endl; - plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>") - << endl; - plistStream << QLatin1String("\t<key>CFBundleVersion</key>") << endl; - plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>") - << endl; -#undef QUOTE -#undef QUOTE_ - plistStream << QLatin1String("\t<key>CFBundleSignature</key>") << endl; - plistStream << QLatin1String("\t<string>\?\?\?\?</string>") << endl; - plistStream << QLatin1String("\t<key>CFBundleExecutable</key>") << endl; - plistStream << QLatin1String("\t<string>") << fi.completeBaseName() << QLatin1String("</string>") - << endl; - plistStream << QLatin1String("\t<key>CFBundleIdentifier</key>") << endl; - plistStream << QLatin1String("\t<string>com.yourcompany.installerbase</string>") << endl; - plistStream << QLatin1String("\t<key>NOTE</key>") << endl; - plistStream << QLatin1String("\t<string>This file was generated by Qt Installer Framework.</string>") - << endl; - plistStream << QLatin1String("\t<key>NSPrincipalClass</key>") << endl; - plistStream << QLatin1String("\t<string>NSApplication</string>") << endl; - if (!minimumSystemVersion.isEmpty()) { - plistStream << QLatin1String("\t<key>LSMinimumSystemVersion</key>") << endl; - plistStream << QLatin1String("\t<string>") << minimumSystemVersion << QLatin1String("</string>") << endl; - } - plistStream << QLatin1String("</dict>") << endl; - plistStream << QLatin1String("</plist>") << endl; - - input.outputPath = QString::fromLatin1("%1/Contents/MacOS/%2").arg(input.outputPath) - .arg(fi.completeBaseName()); - } -#elif defined(Q_OS_LINUX) - Q_UNUSED(settings) -#endif - - QTemporaryFile file(input.outputPath); - if (!file.open()) { - throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(input.installerExePath, - input.outputPath, file.errorString())); - } - - const QString tempFile = file.fileName(); - file.close(); - file.remove(); - - QFile instExe(input.installerExePath); - if (!instExe.copy(tempFile)) { - throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(instExe.fileName(), - tempFile, instExe.errorString())); - } - - QtPatch::patchBinaryFile(tempFile, QByteArray("MY_InstallerCreateDateTime_MY"), - QDateTime::currentDateTime().toString(QLatin1String("yyyy-MM-dd - HH:mm:ss")).toLatin1()); - - - input.installerExePath = tempFile; - -#if defined(Q_OS_WIN) - // setting the windows icon must happen before we append our binary data - otherwise they get lost :-/ - if (QFile::exists(settings.installerApplicationIcon())) { - // no error handling as this is not fatal - setApplicationIcon(tempFile, settings.installerApplicationIcon()); - } -#elif defined(Q_OS_MACOS) - if (isBundle) { - // no error handling as this is not fatal - const QString copyscript = QDir::temp().absoluteFilePath(QLatin1String("copylibsintobundle.sh")); - QFile::copy(QLatin1String(":/resources/copylibsintobundle.sh"), copyscript); - QFile::rename(tempFile, input.outputPath); - chmod755(copyscript); - QProcess p; - p.start(copyscript, QStringList() << bundle); - p.waitForFinished(-1); - QFile::rename(input.outputPath, tempFile); - QFile::remove(copyscript); - } -#endif - - QFile out(generateTemporaryFileName()); - - QString targetName = input.outputPath; -#ifdef Q_OS_MACOS - QDir resourcePath(QFileInfo(input.outputPath).dir()); - resourcePath.cdUp(); - resourcePath.cd(QLatin1String("Resources")); - targetName = resourcePath.filePath(QLatin1String("installer.dat")); -#endif - - { - QFile target(targetName); - if (target.exists() && !target.remove()) { - qCritical("Cannot remove target %s: %s", qPrintable(target.fileName()), - qPrintable(target.errorString())); - QFile::remove(tempFile); - return EXIT_FAILURE; - } - } - - try { - QInstaller::openForWrite(&out); - QFile exe(input.installerExePath); - -#ifdef Q_OS_MACOS - if (!exe.copy(input.outputPath)) { - throw Error(QString::fromLatin1("Cannot copy %1 to %2: %3").arg(exe.fileName(), - input.outputPath, exe.errorString())); - } -#else - QInstaller::openForRead(&exe); - QInstaller::appendData(&out, &exe, exe.size()); -#endif - - foreach (const QInstallerTools::PackageInfo &info, input.packages) { - QInstaller::ResourceCollection collection; - collection.setName(info.name.toUtf8()); - - qDebug() << "Creating resource archive for" << info.name; - foreach (const QString &file, info.copiedFiles) { - const QSharedPointer<Resource> resource(new Resource(file)); - qDebug().nospace() << "Appending " << file << " (" << humanReadableSize(resource->size()) << ")"; - collection.appendResource(resource); - } - input.manager.insertCollection(collection); - } - - const QList<QInstaller::OperationBlob> operations; - BinaryContent::writeBinaryContent(&out, operations, input.manager, - BinaryContent::MagicInstallerMarker, BinaryContent::MagicCookie); - } catch (const Error &e) { - qCritical("Error occurred while assembling the installer: %s", qPrintable(e.message())); - QFile::remove(tempFile); - return EXIT_FAILURE; - } - - if (!out.rename(targetName)) { - qCritical("Cannot write installer to %s: %s", targetName.toUtf8().constData(), - out.errorString().toUtf8().constData()); - QFile::remove(tempFile); - return EXIT_FAILURE; - } - -#ifndef Q_OS_WIN - chmod755(out.fileName()); -#endif - QFile::remove(tempFile); - -#ifdef Q_OS_MACOS - if (isBundle && !signingIdentity.isEmpty()) { - qDebug() << "Signing .app bundle..."; - - QProcess p; - p.start(QLatin1String("codesign"), - QStringList() << QLatin1String("--force") - << QLatin1String("--deep") - << QLatin1String("--sign") << signingIdentity - << bundle); - - if (!p.waitForFinished(-1)) { - qCritical("Failed to sign app bundle: error while running '%s %s': %s", - p.program().toUtf8().constData(), - p.arguments().join(QLatin1Char(' ')).toUtf8().constData(), - p.errorString().toUtf8().constData()); - return EXIT_FAILURE; - } - - if (p.exitStatus() == QProcess::NormalExit) { - if (p.exitCode() != 0) { - qCritical("Failed to sign app bundle: running codesign failed " - "with exit code %d: %s", p.exitCode(), - p.readAllStandardError().constData()); - return EXIT_FAILURE; - } - } - - qDebug() << "done."; - } - - bundleBackup.release(); - - if (createDMG) { - qDebug() << "creating a DMG disk image..."; - - const QString volumeName = QFileInfo(input.outputPath).fileName(); - const QString imagePath = QString::fromLatin1("%1/%2.dmg") - .arg(QFileInfo(bundle).path()) - .arg(volumeName); - - // no error handling as this is not fatal - QProcess p; - p.start(QLatin1String("/usr/bin/hdiutil"), - QStringList() << QLatin1String("create") - << imagePath - << QLatin1String("-srcfolder") - << bundle - << QLatin1String("-ov") - << QLatin1String("-volname") - << volumeName - << QLatin1String("-fs") - << QLatin1String("HFS+")); - qDebug() << "running " << p.program() << p.arguments(); - p.waitForFinished(-1); - qDebug() << "removing" << bundle; - QDir(bundle).removeRecursively(); - qDebug() << "done."; - } -#else - Q_UNUSED(signingIdentity) -#endif - return EXIT_SUCCESS; -} - -QT_BEGIN_NAMESPACE -int runRcc(int argc, char *argv[]); -QT_END_NAMESPACE - -static int runRcc(const QStringList &args) -{ - const int argc = args.count(); - QVector<char*> argv(argc, nullptr); - for (int i = 0; i < argc; ++i) - argv[i] = qstrdup(qPrintable(args[i])); - - // Note: this does not run the rcc provided by Qt, this one is using the compiled in binarycreator - // version. If it happens that resource mapping fails, we might need to adapt the code here... - const int result = runRcc(argc, argv.data()); - - foreach (char *arg, argv) - delete [] arg; - - return result; -} - -class WorkingDirectoryChange -{ -public: - explicit WorkingDirectoryChange(const QString &path) - : oldPath(QDir::currentPath()) - { - QDir::setCurrent(path); - } - - virtual ~WorkingDirectoryChange() - { - QDir::setCurrent(oldPath); - } - -private: - const QString oldPath; -}; - -static QSharedPointer<QInstaller::Resource> createDefaultResourceFile(const QString &directory, - const QString &binaryName) -{ - QTemporaryFile projectFile(directory + QLatin1String("/rccprojectXXXXXX.qrc")); - if (!projectFile.open()) - throw Error(QString::fromLatin1("Cannot create temporary file for generated rcc project file")); - projectFile.close(); - - const WorkingDirectoryChange wd(directory); - const QString projectFileName = QFileInfo(projectFile.fileName()).absoluteFilePath(); - - // 1. create the .qrc file - if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-project") << QLatin1String("-o") - << projectFileName) != EXIT_SUCCESS) { - throw Error(QString::fromLatin1("Cannot create rcc project file.")); - } - - // 2. create the binary resource file from the .qrc file - if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-binary") << QLatin1String("-o") - << binaryName << projectFileName) != EXIT_SUCCESS) { - throw Error(QString::fromLatin1("Cannot compile rcc project file.")); - } - - return QSharedPointer<QInstaller::Resource>(new QInstaller::Resource(binaryName, binaryName - .toUtf8())); -} - -static -QList<QSharedPointer<QInstaller::Resource> > createBinaryResourceFiles(const QStringList &resources) -{ - QList<QSharedPointer<QInstaller::Resource> > result; - foreach (const QString &resource, resources) { - QFile file(resource); - if (file.exists()) { - const QString binaryName = generateTemporaryFileName(); - const QString fileName = QFileInfo(file.fileName()).absoluteFilePath(); - const int status = runRcc(QStringList() << QLatin1String("rcc") - << QLatin1String("-binary") << QLatin1String("-o") << binaryName << fileName); - if (status != EXIT_SUCCESS) - continue; - - result.append(QSharedPointer<QInstaller::Resource> (new QInstaller::Resource(binaryName, - binaryName.toUtf8()))); - } - } - return result; -} - -static void printUsage() -{ - QString suffix; -#ifdef Q_OS_WIN - suffix = QLatin1String(".exe"); -#endif - const QString appName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); - std::cout << "Usage: " << appName << " [options] target" << std::endl; - std::cout << std::endl; - std::cout << "Options:" << std::endl; - - std::cout << " -t|--template file Use file as installer template binary" << std::endl; - std::cout << " If this parameter is not given, the template used" << std::endl; - std::cout << " defaults to installerbase." << std::endl; - - QInstallerTools::printRepositoryGenOptions(); - - std::cout << " -c|--config file The file containing the installer configuration" << std::endl; - - std::cout << " -n|--online-only Do not add any package into the installer" << std::endl; - std::cout << " (for online only installers)" << std::endl; - - std::cout << " -f|--offline-only Forces the installer to act as an offline installer, " << std::endl; - std::cout << " i.e. never access online repositories" << std::endl; - - std::cout << " -r|--resources r1,.,rn include the given resource files into the binary" << std::endl; - - std::cout << " -v|--verbose Verbose output" << std::endl; - std::cout << " -rcc|--compile-resource Compiles the default resource and outputs the result into" - << std::endl; - std::cout << " 'update.rcc' in the current path." << std::endl; -#ifdef Q_OS_MACOS - std::cout << " -s|--sign identity Sign generated app bundle using the given code " << std::endl; - std::cout << " signing identity" << std::endl; -#endif - std::cout << std::endl; - std::cout << "Packages are to be found in the current working directory and get listed as " - "their names" << std::endl << std::endl; - std::cout << "Example (offline installer):" << std::endl; - char sep = QDir::separator().toLatin1(); - std::cout << " " << appName << " --offline-only -c installer-config" << sep << "config.xml -p " - "packages-directory -t installerbase" << suffix << " SDKInstaller" << suffix << std::endl; - std::cout << "Creates an offline installer for the SDK, containing all dependencies." << std::endl; - std::cout << std::endl; - std::cout << "Example (online installer):" << std::endl; - std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " - "-e org.qt-project.sdk.qt,org.qt-project.qtcreator -t installerbase" << suffix << " SDKInstaller" - << suffix << std::endl; - std::cout << std::endl; - std::cout << "Creates an installer for the SDK without qt and qt creator." << std::endl; - std::cout << std::endl; - std::cout << "Example update.rcc:" << std::endl; - std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " - "-rcc" << std::endl; -} - -void copyConfigData(const QString &configFile, const QString &targetDir) -{ - qDebug() << "Begin to copy configuration file and data."; - - const QString sourceConfigFile = QFileInfo(configFile).absoluteFilePath(); - const QString targetConfigFile = targetDir + QLatin1String("/config.xml"); - QInstallerTools::copyWithException(sourceConfigFile, targetConfigFile, QLatin1String("configuration")); - - QFile configXml(targetConfigFile); - QInstaller::openForRead(&configXml); - - QDomDocument dom; - dom.setContent(&configXml); - configXml.close(); - - // iterate over all child elements, searching for relative file names - const QDomNodeList children = dom.documentElement().childNodes(); - const QString sourceConfigFilePath = QFileInfo(sourceConfigFile).absolutePath(); - for (int i = 0; i < children.count(); ++i) { - QDomElement domElement = children.at(i).toElement(); - if (domElement.isNull()) - continue; - - const QString tagName = domElement.tagName(); - const QString elementText = domElement.text(); - qDebug().noquote() << QString::fromLatin1("Read dom element: <%1>%2</%1>.").arg(tagName, elementText); - - if (tagName == QLatin1String("ProductImages")) { - const QDomNodeList childNodes = domElement.childNodes(); - for (int i = 0; i < childNodes.count(); ++i) { - const QDomElement childElement = childNodes.at(i).toElement(); - const QString childName = childElement.tagName(); - if (childName != QLatin1String("Image")) - continue; - - const QString targetFile = targetDir + QLatin1Char('/') + childElement.text(); - const QFileInfo childFileInfo = QFileInfo(sourceConfigFilePath, childElement.text()); - QInstallerTools::copyWithException(childFileInfo.absoluteFilePath(), targetFile, childName); - } - continue; - } - - QString newName = domElement.text().replace(QRegExp(QLatin1String("\\\\|/|\\.|:")), - QLatin1String("_")); - - QString targetFile; - QFileInfo elementFileInfo; - if (tagName == QLatin1String("Icon") || tagName == QLatin1String("InstallerApplicationIcon")) { -#if defined(Q_OS_MACOS) - const QString suffix = QLatin1String(".icns"); -#elif defined(Q_OS_WIN) - const QString suffix = QLatin1String(".ico"); -#else - const QString suffix = QLatin1String(".png"); -#endif - elementFileInfo = QFileInfo(sourceConfigFilePath, elementText + suffix); - targetFile = targetDir + QLatin1Char('/') + newName + suffix; - } else { - elementFileInfo = QFileInfo(sourceConfigFilePath, elementText); - const QString suffix = elementFileInfo.completeSuffix(); - if (!suffix.isEmpty()) - newName.append(QLatin1Char('.') + suffix); - targetFile = targetDir + QLatin1Char('/') + newName; - } - if (!elementFileInfo.exists() || elementFileInfo.isDir()) - continue; - - domElement.replaceChild(dom.createTextNode(newName), domElement.firstChild()); - QInstallerTools::copyWithException(elementFileInfo.absoluteFilePath(), targetFile, tagName); - } - - QInstaller::openForWrite(&configXml); - QTextStream stream(&configXml); - dom.save(stream, 4); - - qDebug() << "done.\n"; -} - -static int printErrorAndUsageAndExit(const QString &err) -{ - std::cerr << qPrintable(err) << std::endl << std::endl; - printUsage(); - return EXIT_FAILURE; -} - -int main(int argc, char **argv) -{ -// increase maximum numbers of file descriptors -#if defined (Q_OS_MACOS) - struct rlimit rl; - getrlimit(RLIMIT_NOFILE, &rl); - rl.rlim_cur = qMin(static_cast<rlim_t>(OPEN_MAX), rl.rlim_max); - setrlimit(RLIMIT_NOFILE, &rl); -#endif - QCoreApplication app(argc, argv); - - QInstaller::init(); - - QString templateBinary = QLatin1String("installerbase"); - QString suffix; -#ifdef Q_OS_WIN - suffix = QLatin1String(".exe"); - templateBinary = templateBinary + suffix; -#endif - if (!QFileInfo(templateBinary).exists()) - templateBinary = QString::fromLatin1("%1/%2").arg(qApp->applicationDirPath(), templateBinary); - - QString target; - QString configFile; - QStringList packagesDirectories; - QStringList repositoryDirectories; - bool onlineOnly = false; - bool offlineOnly = false; - QStringList resources; - QStringList filteredPackages; - QInstallerTools::FilterType ftype = QInstallerTools::Exclude; - bool compileResource = false; - QString signingIdentity; - - const QStringList args = app.arguments().mid(1); - for (QStringList::const_iterator it = args.begin(); it != args.end(); ++it) { - if (*it == QLatin1String("-h") || *it == QLatin1String("--help")) { - printUsage(); - return 0; - } else if (*it == QLatin1String("-p") || *it == QLatin1String("--packages")) { - ++it; - if (it == args.end()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Packages parameter missing argument.")); - } - if (!QFileInfo(*it).exists()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package directory not found at the " - "specified location.")); - } - packagesDirectories.append(*it); - } else if (*it == QLatin1String("--repository")) { - ++it; - if (it == args.end()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Repository parameter missing argument.")); - } - if (QFileInfo(*it).exists()) { - repositoryDirectories.append(*it); - } else { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Only local filesystem repositories now supported.")); - } - } else if (*it == QLatin1String("-e") || *it == QLatin1String("--exclude")) { - ++it; - if (!filteredPackages.isEmpty()) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: --include and --exclude are mutually " - "exclusive. Use either one or the other.")); - if (it == args.end() || it->startsWith(QLatin1String("-"))) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package to exclude missing.")); - filteredPackages = it->split(QLatin1Char(',')); - } else if (*it == QLatin1String("-i") || *it == QLatin1String("--include")) { - ++it; - if (!filteredPackages.isEmpty()) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: --include and --exclude are mutually " - "exclusive. Use either one or the other.")); - if (it == args.end() || it->startsWith(QLatin1String("-"))) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package to include missing.")); - filteredPackages = it->split(QLatin1Char(',')); - ftype = QInstallerTools::Include; - } - else if (*it == QLatin1String("-v") || *it == QLatin1String("--verbose")) { - QInstaller::setVerbose(true); - } else if (*it == QLatin1String("-n") || *it == QLatin1String("--online-only")) { - if (!filteredPackages.isEmpty()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: 'online-only' option cannot be used " - "in conjunction with the 'include' or 'exclude' option. An 'online-only' installer will never " - "contain any components apart from the root component.")); - } - onlineOnly = true; - } else if (*it == QLatin1String("-f") || *it == QLatin1String("--offline-only")) { - offlineOnly = true; - } else if (*it == QLatin1String("-t") || *it == QLatin1String("--template")) { - ++it; - if (it == args.end()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Template parameter missing argument.")); - } - templateBinary = *it; -#ifdef Q_OS_WIN - if (!templateBinary.endsWith(suffix)) - templateBinary = templateBinary + suffix; -#endif - if (!QFileInfo(templateBinary).exists()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Template not found at the specified " - "location.")); - } - } else if (*it == QLatin1String("-c") || *it == QLatin1String("--config")) { - ++it; - if (it == args.end()) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Config parameter missing argument.")); - const QFileInfo fi(*it); - if (!fi.exists()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Config file %1 not found at the " - "specified location.").arg(*it)); - } - if (!fi.isFile()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Configuration %1 is not a file.") - .arg(*it)); - } - if (!fi.isReadable()) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Config file %1 is not readable.") - .arg(*it)); - } - configFile = *it; - } else if (*it == QLatin1String("-r") || *it == QLatin1String("--resources")) { - ++it; - if (it == args.end() || it->startsWith(QLatin1String("-"))) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Resource files to include are missing.")); - resources = it->split(QLatin1Char(',')); - } else if (*it == QLatin1String("--ignore-translations") - || *it == QLatin1String("--ignore-invalid-packages")) { - continue; - } else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) { - compileResource = true; -#ifdef Q_OS_MACOS - } else if (*it == QLatin1String("-s") || *it == QLatin1String("--sign")) { - ++it; - if (it == args.end() || it->startsWith(QLatin1String("-"))) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: No code signing identity specified.")); - signingIdentity = *it; -#endif - } else { - if (it->startsWith(QLatin1String("-"))) { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Unknown option \"%1\" used. Maybe you " - "are using an old syntax.").arg(*it)); - } else if (target.isEmpty()) { - target = *it; -#ifdef Q_OS_WIN - if (!target.endsWith(suffix)) - target = target + suffix; -#endif - } else { - return printErrorAndUsageAndExit(QString::fromLatin1("Error: You are using an old syntax please add the " - "component name with the include option") - .arg(*it)); - } - } - } - - if (onlineOnly && offlineOnly) { - return printErrorAndUsageAndExit(QString::fromLatin1("You cannot use --online-only and " - "--offline-only at the same time.")); - } - - if (onlineOnly) { - filteredPackages.append(QLatin1String("X_fake_filter_component_for_online_only_installer_X")); - ftype = QInstallerTools::Include; - } - - if (target.isEmpty() && !compileResource) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Target parameter missing.")); - - if (configFile.isEmpty()) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: No configuration file selected.")); - - if (packagesDirectories.isEmpty() && repositoryDirectories.isEmpty()) - return printErrorAndUsageAndExit(QString::fromLatin1("Error: Both Package directory and Repository parameters missing.")); - - qDebug() << "Parsed arguments, ok."; - - Input input; - int exitCode = EXIT_FAILURE; - QTemporaryDir tmp; - tmp.setAutoRemove(false); - const QString tmpMetaDir = tmp.path(); - QTemporaryDir tmp2; - tmp2.setAutoRemove(false); - const QString tmpRepoDir = tmp2.path(); - try { - const Settings settings = Settings::fromFileAndPrefix(configFile, QFileInfo(configFile) - .absolutePath()); - - // Note: the order here is important - - QInstallerTools::PackageInfoVector packages; - - // 1; update the list of available compressed packages - if (!repositoryDirectories.isEmpty()) { - // 1.1; search packages - QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages(repositoryDirectories, - &filteredPackages, ftype); - // 1.2; add to common vector - packages.append(precompressedPackages); - } - - // 2; update the list of available prepared packages - if (!packagesDirectories.isEmpty()) { - // 2.1; search packages - QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(packagesDirectories, - &filteredPackages, ftype); - // 2.2; copy the packages data and setup the packages vector with the files we copied, - // must happen before copying meta data because files will be compressed if - // needed and meta data generation relies on this - QInstallerTools::copyComponentData(packagesDirectories, tmpRepoDir, &preparedPackages); - // 2.3; add to common vector - packages.append(preparedPackages); - } - - // 3; copy the meta data of the available packages, generate Updates.xml - QInstallerTools::copyMetaData(tmpMetaDir, tmpRepoDir, packages, settings - .applicationName(), settings.version(), QStringList()); - - // 4; copy the configuration file and and icons etc. - copyConfigData(configFile, tmpMetaDir + QLatin1String("/installer-config")); - { - QSettings confInternal(tmpMetaDir + QLatin1String("/config/config-internal.ini") - , QSettings::IniFormat); - // assume offline installer if there are no repositories and no - //--online-only not set - offlineOnly = offlineOnly | settings.repositories().isEmpty(); - if (onlineOnly) - offlineOnly = !onlineOnly; - confInternal.setValue(QLatin1String("offlineOnly"), offlineOnly); - } - -#ifdef Q_OS_MACOS - // on mac, we enforce building a bundle - if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) - target += QLatin1String(".app"); -#endif - if (!compileResource) { - // 5; put the copied resources into a resource file - QInstaller::ResourceCollection metaCollection("QResources"); - metaCollection.appendResource(createDefaultResourceFile(tmpMetaDir, - generateTemporaryFileName())); - metaCollection.appendResources(createBinaryResourceFiles(resources)); - input.manager.insertCollection(metaCollection); - - input.packages = packages; - input.outputPath = target; - input.installerExePath = templateBinary; - - qDebug() << "Creating the binary"; - exitCode = assemble(input, settings, signingIdentity); - } else { - createDefaultResourceFile(tmpMetaDir, QDir::currentPath() + QLatin1String("/update.rcc")); - exitCode = EXIT_SUCCESS; - } - } catch (const Error &e) { - QFile::remove(input.outputPath); - std::cerr << "Caught exception: " << e.message() << std::endl; - } catch (...) { - QFile::remove(input.outputPath); - std::cerr << "Unknown exception caught" << std::endl; - } - - qDebug() << "Cleaning up..."; - const QInstaller::ResourceCollection collection = input.manager.collectionByName("QResources"); - foreach (const QSharedPointer<QInstaller::Resource> &resource, collection.resources()) - QFile::remove(QString::fromUtf8(resource->name())); - QInstaller::removeDirectory(tmpMetaDir, true); - QInstaller::removeDirectory(tmpRepoDir, true); - - return exitCode; -} diff --git a/tools/binarycreator/binarycreator.pro b/tools/binarycreator/binarycreator.pro index ddde5e984..994de83c1 100644 --- a/tools/binarycreator/binarycreator.pro +++ b/tools/binarycreator/binarycreator.pro @@ -1,6 +1,6 @@ TEMPLATE = app TARGET = binarycreator -INCLUDEPATH += . .. rcc ../common +INCLUDEPATH += . .. include(../../installerfw.pri) @@ -9,12 +9,7 @@ QT += qml xml CONFIG += console DESTDIR = $$IFW_APP_PATH -SOURCES = binarycreator.cpp \ - rcc/rcc.cpp \ - rcc/rccmain.cpp \ - ../common/repositorygen.cpp -HEADERS = rcc/rcc.h -RESOURCES += binarycreator.qrc +SOURCES = main.cpp macx:include(../../no_app_bundle.pri) diff --git a/tools/binarycreator/binarycreator.qrc b/tools/binarycreator/binarycreator.qrc deleted file mode 100644 index b64e3a21a..000000000 --- a/tools/binarycreator/binarycreator.qrc +++ /dev/null @@ -1,7 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource> - <file>resources/default_icon_mac.icns</file> - <file>resources/copylibsintobundle.sh</file> - <file alias="resources/installerbase.ico">../../src/sdk/installerbase.ico</file> -</qresource> -</RCC> diff --git a/tools/binarycreator/main.cpp b/tools/binarycreator/main.cpp new file mode 100644 index 000000000..b5a0ae4f7 --- /dev/null +++ b/tools/binarycreator/main.cpp @@ -0,0 +1,210 @@ +/************************************************************************** +** +** 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 <binarycreator.h> +#include <init.h> +#include <utils.h> + +#include <QtCore/QDebug> + +#include <iostream> + +using namespace QInstaller; + +static void printUsage() +{ + QString suffix; +#ifdef Q_OS_WIN + suffix = QLatin1String(".exe"); +#endif + const QString appName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); + std::cout << "Usage: " << appName << " [options] target" << std::endl; + std::cout << std::endl; + std::cout << "Options:" << std::endl; + + std::cout << " -t|--template file Use file as installer template binary" << std::endl; + std::cout << " If this parameter is not given, the template used" << std::endl; + std::cout << " defaults to installerbase." << std::endl; + + QInstallerTools::printRepositoryGenOptions(); + + std::cout << " -c|--config file The file containing the installer configuration" << std::endl; + + std::cout << " -n|--online-only Do not add any package into the installer" << std::endl; + std::cout << " (for online only installers)" << std::endl; + + std::cout << " -f|--offline-only Forces the installer to act as an offline installer, " << std::endl; + std::cout << " i.e. never access online repositories" << std::endl; + + std::cout << " -r|--resources r1,.,rn include the given resource files into the binary" << std::endl; + + std::cout << " -v|--verbose Verbose output" << std::endl; + std::cout << " -rcc|--compile-resource Compiles the default resource and outputs the result into" + << std::endl; + std::cout << " 'update.rcc' in the current path." << std::endl; +#ifdef Q_OS_MACOS + std::cout << " -s|--sign identity Sign generated app bundle using the given code " << std::endl; + std::cout << " signing identity" << std::endl; +#endif + std::cout << std::endl; + std::cout << "Packages are to be found in the current working directory and get listed as " + "their names" << std::endl << std::endl; + std::cout << "Example (offline installer):" << std::endl; + char sep = QDir::separator().toLatin1(); + std::cout << " " << appName << " --offline-only -c installer-config" << sep << "config.xml -p " + "packages-directory -t installerbase" << suffix << " SDKInstaller" << suffix << std::endl; + std::cout << "Creates an offline installer for the SDK, containing all dependencies." << std::endl; + std::cout << std::endl; + std::cout << "Example (online installer):" << std::endl; + std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " + "-e org.qt-project.sdk.qt,org.qt-project.qtcreator -t installerbase" << suffix << " SDKInstaller" + << suffix << std::endl; + std::cout << std::endl; + std::cout << "Creates an installer for the SDK without qt and qt creator." << std::endl; + std::cout << std::endl; + std::cout << "Example update.rcc:" << std::endl; + std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " + "-rcc" << std::endl; +} + +static int printErrorAndUsageAndExit(const QString &err) +{ + std::cerr << qPrintable(err) << std::endl << std::endl; + printUsage(); + return EXIT_FAILURE; +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QInstaller::init(); + + QInstallerTools::BinaryCreatorArgs parsedArgs; + + parsedArgs.templateBinary = QLatin1String("installerbase"); + QString suffix; +#ifdef Q_OS_WIN + suffix = QLatin1String(".exe"); + parsedArgs.templateBinary = parsedArgs.templateBinary + suffix; +#endif + if (!QFileInfo(parsedArgs.templateBinary).exists()) + parsedArgs.templateBinary = QString::fromLatin1("%1/%2").arg(qApp->applicationDirPath(), parsedArgs.templateBinary); + + const QStringList args = app.arguments().mid(1); + for (QStringList::const_iterator it = args.begin(); it != args.end(); ++it) { + if (*it == QLatin1String("-h") || *it == QLatin1String("--help")) { + printUsage(); + return 0; + } else if (*it == QLatin1String("-p") || *it == QLatin1String("--packages")) { + ++it; + if (it == args.end()) { + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Packages parameter missing argument.")); + } + parsedArgs.packagesDirectories.append(*it); + } else if (*it == QLatin1String("--repository")) { + ++it; + if (it == args.end()) { + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Repository parameter missing argument.")); + } + parsedArgs.repositoryDirectories.append(*it); + } else if (*it == QLatin1String("-e") || *it == QLatin1String("--exclude")) { + ++it; + if (!parsedArgs.filteredPackages.isEmpty()) + return printErrorAndUsageAndExit(QString::fromLatin1("Error: --include and --exclude are mutually " + "exclusive. Use either one or the other.")); + if (it == args.end() || it->startsWith(QLatin1String("-"))) + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package to exclude missing.")); + parsedArgs.filteredPackages = it->split(QLatin1Char(',')); + } else if (*it == QLatin1String("-i") || *it == QLatin1String("--include")) { + ++it; + if (!parsedArgs.filteredPackages.isEmpty()) + return printErrorAndUsageAndExit(QString::fromLatin1("Error: --include and --exclude are mutually " + "exclusive. Use either one or the other.")); + if (it == args.end() || it->startsWith(QLatin1String("-"))) + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package to include missing.")); + parsedArgs.filteredPackages = it->split(QLatin1Char(',')); + parsedArgs.ftype = QInstallerTools::Include; + } + else if (*it == QLatin1String("-v") || *it == QLatin1String("--verbose")) { + QInstaller::setVerbose(true); + } else if (*it == QLatin1String("-n") || *it == QLatin1String("--online-only")) { + parsedArgs.onlineOnly = true; + } else if (*it == QLatin1String("-f") || *it == QLatin1String("--offline-only")) { + parsedArgs.offlineOnly = true; + } else if (*it == QLatin1String("-t") || *it == QLatin1String("--template")) { + ++it; + if (it == args.end()) { + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Template parameter missing argument.")); + } + parsedArgs.templateBinary = *it; + } else if (*it == QLatin1String("-c") || *it == QLatin1String("--config")) { + ++it; + if (it == args.end()) + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Config parameter missing argument.")); + parsedArgs.configFile = *it; + } else if (*it == QLatin1String("-r") || *it == QLatin1String("--resources")) { + ++it; + if (it == args.end() || it->startsWith(QLatin1String("-"))) + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Resource files to include are missing.")); + parsedArgs.resources = it->split(QLatin1Char(',')); + } else if (*it == QLatin1String("--ignore-translations") + || *it == QLatin1String("--ignore-invalid-packages")) { + continue; + } else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) { + parsedArgs.compileResource = true; +#ifdef Q_OS_MACOS + } else if (*it == QLatin1String("-s") || *it == QLatin1String("--sign")) { + ++it; + if (it == args.end() || it->startsWith(QLatin1String("-"))) + return printErrorAndUsageAndExit(QString::fromLatin1("Error: No code signing identity specified.")); + parsedArgs.signingIdentity = *it; +#endif + } else { + if (it->startsWith(QLatin1String("-"))) { + return printErrorAndUsageAndExit(QString::fromLatin1("Error: Unknown option \"%1\" used. Maybe you " + "are using an old syntax.").arg(*it)); + } else if (parsedArgs.target.isEmpty()) { + parsedArgs.target = *it; + } else { + return printErrorAndUsageAndExit(QString::fromLatin1("Error: You are using an old syntax please add the " + "component name with the include option") + .arg(*it)); + } + } + } + + QString errorMsg; + if (QInstallerTools::createBinary(parsedArgs, errorMsg) == EXIT_FAILURE) { + if (!errorMsg.isEmpty()) + printErrorAndUsageAndExit(errorMsg); + + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/tools/binarycreator/rcc/qcorecmdlineargs_p.h b/tools/binarycreator/rcc/qcorecmdlineargs_p.h deleted file mode 100644 index 9ea85de8a..000000000 --- a/tools/binarycreator/rcc/qcorecmdlineargs_p.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $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$ -** -****************************************************************************/ - -#ifndef QCORECMDLINEARGS_P_H -#define QCORECMDLINEARGS_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "QtCore/qstring.h" -#include "QtCore/qstringlist.h" - -QT_BEGIN_NAMESPACE - -static inline QStringList qCmdLineArgs(int argc, char *argv[]) -{ - QStringList args; - for (int i = 0; i != argc; ++i) - args += QString::fromLocal8Bit(argv[i]); - return args; -} - - -QT_END_NAMESPACE - -#endif // QCORECMDLINEARGS_WIN_P_H diff --git a/tools/binarycreator/rcc/rcc.cpp b/tools/binarycreator/rcc/rcc.cpp deleted file mode 100644 index 10b7cbc4f..000000000 --- a/tools/binarycreator/rcc/rcc.cpp +++ /dev/null @@ -1,1038 +0,0 @@ -/************************************************************************** -** -** Copyright (C) 2017 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 "rcc.h" - -#include <QtCore/QByteArray> -#include <QtCore/QDateTime> -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QDirIterator> -#include <QtCore/QFile> -#include <QtCore/QIODevice> -#include <QtCore/QLocale> -#include <QtCore/QRegExp> -#include <QtCore/QStack> - -#include <QXmlStreamReader> - -QT_BEGIN_NAMESPACE - -enum { - CONSTANT_USENAMESPACE = 1, - CONSTANT_COMPRESSLEVEL_DEFAULT = -1, - CONSTANT_COMPRESSTHRESHOLD_DEFAULT = 70 -}; - - -#define writeString(s) write(s, sizeof(s)) - -void RCCResourceLibrary::write(const char *str, int len) -{ - --len; // trailing \0 on string literals... - int n = m_out.size(); - m_out.resize(n + len); - memcpy(m_out.data() + n, str, len); -} - -void RCCResourceLibrary::writeByteArray(const QByteArray &other) -{ - m_out.append(other); -} - -static inline QString msgOpenReadFailed(const QString &fname, const QString &why) -{ - return QString::fromUtf8("Unable to open %1 for reading: %2\n").arg(fname).arg(why); -} - - -/////////////////////////////////////////////////////////// -// -// RCCFileInfo -// -/////////////////////////////////////////////////////////// - -class RCCFileInfo -{ -public: - enum Flags - { - NoFlags = 0x00, - Compressed = 0x01, - Directory = 0x02 - }; - - RCCFileInfo(const QString &name = QString(), const QFileInfo &fileInfo = QFileInfo(), - QLocale::Language language = QLocale::C, - QLocale::Country country = QLocale::AnyCountry, - uint flags = NoFlags, - int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT, - int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT); - ~RCCFileInfo(); - - QString resourceName() const; - -public: - qint64 writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage); - qint64 writeDataName(RCCResourceLibrary &, qint64 offset); - void writeDataInfo(RCCResourceLibrary &lib); - - int m_flags; - QString m_name; - QLocale::Language m_language; - QLocale::Country m_country; - QFileInfo m_fileInfo; - RCCFileInfo *m_parent; - QHash<QString, RCCFileInfo*> m_children; - int m_compressLevel; - int m_compressThreshold; - - qint64 m_nameOffset; - qint64 m_dataOffset; - qint64 m_childOffset; -}; - -RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo, - QLocale::Language language, QLocale::Country country, uint flags, - int compressLevel, int compressThreshold) -{ - m_name = name; - m_fileInfo = fileInfo; - m_language = language; - m_country = country; - m_flags = flags; - m_parent = nullptr; - m_nameOffset = 0; - m_dataOffset = 0; - m_childOffset = 0; - m_compressLevel = compressLevel; - m_compressThreshold = compressThreshold; -} - -RCCFileInfo::~RCCFileInfo() -{ - qDeleteAll(m_children); -} - -QString RCCFileInfo::resourceName() const -{ - QString resource = m_name; - for (RCCFileInfo *p = m_parent; p; p = p->m_parent) - resource = resource.prepend(p->m_name + QLatin1Char('/')); - return QLatin1Char(':') + resource; -} - -void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) -{ - const bool text = (lib.m_format == RCCResourceLibrary::C_Code); - //some info - if (text) { - if (m_language != QLocale::C) { - lib.writeString(" // "); - lib.writeByteArray(resourceName().toLocal8Bit()); - lib.writeString(" ["); - lib.writeByteArray(QByteArray::number(m_country)); - lib.writeString("::"); - lib.writeByteArray(QByteArray::number(m_language)); - lib.writeString("[\n "); - } else { - lib.writeString(" // "); - lib.writeByteArray(resourceName().toLocal8Bit()); - lib.writeString("\n "); - } - } - - //pointer data - if (m_flags & RCCFileInfo::Directory) { - // name offset - lib.writeNumber4(m_nameOffset); - - // flags - lib.writeNumber2(m_flags); - - // child count - lib.writeNumber4(m_children.size()); - - // first child offset - lib.writeNumber4(m_childOffset); - } else { - // name offset - lib.writeNumber4(m_nameOffset); - - // flags - lib.writeNumber2(m_flags); - - // locale - lib.writeNumber2(m_country); - lib.writeNumber2(m_language); - - //data offset - lib.writeNumber4(m_dataOffset); - } - if (text) - lib.writeChar('\n'); -} - -qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, - QString *errorMessage) -{ - const bool text = (lib.m_format == RCCResourceLibrary::C_Code); - - //capture the offset - m_dataOffset = offset; - - //find the data to be written - QFile file(m_fileInfo.absoluteFilePath()); - if (!file.open(QFile::ReadOnly)) { - *errorMessage = msgOpenReadFailed(m_fileInfo.absoluteFilePath(), file.errorString()); - return 0; - } - QByteArray data = file.readAll(); - -#ifndef QT_NO_COMPRESS - // Check if compression is useful for this file - if (m_compressLevel != 0 && data.size() != 0) { - QByteArray compressed = - qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel); - - int compressRatio = int(100.0 * (data.size() - compressed.size()) / data.size()); - if (compressRatio >= m_compressThreshold) { - data = compressed; - m_flags |= Compressed; - } - } -#endif // QT_NO_COMPRESS - - // some info - if (text) { - lib.writeString(" // "); - lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit()); - lib.writeString("\n "); - } - - // write the length - - lib.writeNumber4(data.size()); - if (text) - lib.writeString("\n "); - offset += 4; - - // write the payload - const char *p = data.constData(); - if (text) { - for (int i = data.size(), j = 0; --i >= 0; --j) { - lib.writeHex(*p++); - if (j == 0) { - lib.writeString("\n "); - j = 16; - } - } - } else { - for (int i = data.size(); --i >= 0; ) - lib.writeChar(*p++); - } - offset += data.size(); - - // done - if (text) - lib.writeString("\n "); - return offset; -} - -qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) -{ - const bool text = (lib.m_format == RCCResourceLibrary::C_Code); - - // capture the offset - m_nameOffset = offset; - - // some info - if (text) { - lib.writeString(" // "); - lib.writeByteArray(m_name.toLocal8Bit()); - lib.writeString("\n "); - } - - // write the length - lib.writeNumber2(m_name.length()); - if (text) - lib.writeString("\n "); - offset += 2; - - // write the hash - lib.writeNumber4(qt_hash(m_name)); - if (text) - lib.writeString("\n "); - offset += 4; - - // write the m_name - const QChar *unicode = m_name.unicode(); - for (int i = 0; i < m_name.length(); ++i) { - lib.writeNumber2(unicode[i].unicode()); - if (text && i % 16 == 0) - lib.writeString("\n "); - } - offset += m_name.length()*2; - - // done - if (text) - lib.writeString("\n "); - return offset; -} - - -/////////////////////////////////////////////////////////// -// -// RCCResourceLibrary -// -/////////////////////////////////////////////////////////// - -RCCResourceLibrary::Strings::Strings() : - TAG_RCC(QLatin1String("RCC")), - TAG_RESOURCE(QLatin1String("qresource")), - TAG_FILE(QLatin1String("file")), - ATTRIBUTE_LANG(QLatin1String("lang")), - ATTRIBUTE_PREFIX(QLatin1String("prefix")), - ATTRIBUTE_ALIAS(QLatin1String("alias")), - ATTRIBUTE_THRESHOLD(QLatin1String("threshold")), - ATTRIBUTE_COMPRESS(QLatin1String("compress")) -{ -} - -RCCResourceLibrary::RCCResourceLibrary() - : m_root(nullptr), - m_format(C_Code), - m_verbose(false), - m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT), - m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT), - m_treeOffset(0), - m_namesOffset(0), - m_dataOffset(0), - m_useNameSpace(CONSTANT_USENAMESPACE), - m_errorDevice(nullptr) -{ - m_out.reserve(30 * 1000 * 1000); -} - -RCCResourceLibrary::~RCCResourceLibrary() -{ - delete m_root; -} - -enum RCCXmlTag { - RccTag, - ResourceTag, - FileTag -}; - -bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, - const QString &fname, QString currentPath, bool ignoreErrors) -{ - Q_ASSERT(m_errorDevice); - const QChar slash = QLatin1Char('/'); - if (!currentPath.isEmpty() && !currentPath.endsWith(slash)) - currentPath += slash; - - QXmlStreamReader reader(inputDevice); - QStack<RCCXmlTag> tokens; - - QString prefix; - QLocale::Language language = QLocale::c().language(); - QLocale::Country country = QLocale::c().country(); - QString alias; - int compressLevel = m_compressLevel; - int compressThreshold = m_compressThreshold; - - while (!reader.atEnd()) { - QXmlStreamReader::TokenType t = reader.readNext(); - switch (t) { - case QXmlStreamReader::StartElement: - if (reader.name() == m_strings.TAG_RCC) { - if (!tokens.isEmpty()) - reader.raiseError(QLatin1String("expected <RCC> tag")); - else - tokens.push(RccTag); - } else if (reader.name() == m_strings.TAG_RESOURCE) { - if (tokens.isEmpty() || tokens.top() != RccTag) { - reader.raiseError(QLatin1String("unexpected <RESOURCE> tag")); - } else { - tokens.push(ResourceTag); - - QXmlStreamAttributes attributes = reader.attributes(); - language = QLocale::c().language(); - country = QLocale::c().country(); - - if (attributes.hasAttribute(m_strings.ATTRIBUTE_LANG)) { - QString attribute = attributes.value(m_strings.ATTRIBUTE_LANG).toString(); - QLocale lang = QLocale(attribute); - language = lang.language(); - if (2 == attribute.length()) { - // Language only - country = QLocale::AnyCountry; - } else { - country = lang.country(); - } - } - - prefix.clear(); - if (attributes.hasAttribute(m_strings.ATTRIBUTE_PREFIX)) - prefix = attributes.value(m_strings.ATTRIBUTE_PREFIX).toString(); - if (!prefix.startsWith(slash)) - prefix.prepend(slash); - if (!prefix.endsWith(slash)) - prefix += slash; - } - } else if (reader.name() == m_strings.TAG_FILE) { - if (tokens.isEmpty() || tokens.top() != ResourceTag) { - reader.raiseError(QLatin1String("unexpected <FILE> tag")); - } else { - tokens.push(FileTag); - - QXmlStreamAttributes attributes = reader.attributes(); - alias.clear(); - if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS)) - alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString(); - - compressLevel = m_compressLevel; - if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) - compressLevel = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString().toInt(); - - compressThreshold = m_compressThreshold; - if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD)) - compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt(); - - // Special case for -no-compress. Overrides all other settings. - if (m_compressLevel == -2) - compressLevel = 0; - } - } else { - reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString())); - } - break; - - case QXmlStreamReader::EndElement: - if (reader.name() == m_strings.TAG_RCC) { - if (!tokens.isEmpty() && tokens.top() == RccTag) - tokens.pop(); - else - reader.raiseError(QLatin1String("unexpected closing tag")); - } else if (reader.name() == m_strings.TAG_RESOURCE) { - if (!tokens.isEmpty() && tokens.top() == ResourceTag) - tokens.pop(); - else - reader.raiseError(QLatin1String("unexpected closing tag")); - } else if (reader.name() == m_strings.TAG_FILE) { - if (!tokens.isEmpty() && tokens.top() == FileTag) - tokens.pop(); - else - reader.raiseError(QLatin1String("unexpected closing tag")); - } - break; - - case QXmlStreamReader::Characters: - if (reader.isWhitespace()) - break; - if (tokens.isEmpty() || tokens.top() != FileTag) { - reader.raiseError(QLatin1String("unexpected text")); - } else { - QString fileName = reader.text().toString(); - if (fileName.isEmpty()) { - const QString msg = QString::fromLatin1("RCC: Warning: Null node in XML of '%1'\n").arg(fname); - m_errorDevice->write(msg.toUtf8()); - } - - if (alias.isNull()) - alias = fileName; - - alias = QDir::cleanPath(alias); - while (alias.startsWith(QLatin1String("../"))) - alias.remove(0, 3); - alias = QDir::cleanPath(m_resourceRoot) + prefix + alias; - - QString absFileName = fileName; - if (QDir::isRelativePath(absFileName)) - absFileName.prepend(currentPath); - QFileInfo file(absFileName); - if (!file.exists()) { - m_failedResources.push_back(absFileName); - const QString msg = QString::fromLatin1("RCC: Error in '%1': Cannot find file '%2'\n").arg(fname).arg(fileName); - m_errorDevice->write(msg.toUtf8()); - if (ignoreErrors) - continue; - else - return false; - } else if (file.isFile()) { - const bool arc = - addFile(alias, - RCCFileInfo(alias.section(slash, -1), - file, - language, - country, - RCCFileInfo::NoFlags, - compressLevel, - compressThreshold) - ); - if (!arc) - m_failedResources.push_back(absFileName); - } else { - QDir dir; - if (file.isDir()) { - dir.setPath(file.filePath()); - } else { - dir.setPath(file.path()); - dir.setNameFilters(QStringList(file.fileName())); - if (alias.endsWith(file.fileName())) - alias = alias.left(alias.length()-file.fileName().length()); - } - if (!alias.endsWith(slash)) - alias += slash; - QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories); - while (it.hasNext()) { - it.next(); - QFileInfo child(it.fileInfo()); - if (child.fileName() != QLatin1String(".") && child.fileName() != QLatin1String("..")) { - const bool arc = - addFile(alias + child.fileName(), - RCCFileInfo(child.fileName(), - child, - language, - country, - child.isDir() ? RCCFileInfo::Directory : RCCFileInfo::NoFlags, - compressLevel, - compressThreshold) - ); - if (!arc) - m_failedResources.push_back(child.fileName()); - } - } - } - } - break; - - default: - break; - } - } - - if (reader.hasError()) { - if (ignoreErrors) - return true; - int errorLine = reader.lineNumber(); - int errorColumn = reader.columnNumber(); - QString errorMessage = reader.errorString(); - QString msg = QString::fromLatin1("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMessage); - m_errorDevice->write(msg.toUtf8()); - return false; - } - - if (m_root == nullptr) { - const QString msg = QString::fromUtf8("RCC: Warning: No resources in '%1'.\n").arg(fname); - m_errorDevice->write(msg.toUtf8()); - if (!ignoreErrors && m_format == Binary) { - // create dummy entry, otherwise loading with QResource will crash - m_root = new RCCFileInfo(QString(), QFileInfo(), - QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory); - } - } - - return true; -} - -bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) -{ - Q_ASSERT(m_errorDevice); - if (file.m_fileInfo.size() > 0xffffffff) { - const QString msg = QString::fromUtf8("File too big: %1\n").arg(file.m_fileInfo.absoluteFilePath()); - m_errorDevice->write(msg.toUtf8()); - return false; - } - if (!m_root) - m_root = new RCCFileInfo(QString(), QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory); - - RCCFileInfo *parent = m_root; - const QStringList nodes = alias.split(QLatin1Char('/')); - for (int i = 1; i < nodes.size()-1; ++i) { - const QString node = nodes.at(i); - if (node.isEmpty()) - continue; - if (!parent->m_children.contains(node)) { - RCCFileInfo *s = new RCCFileInfo(node, QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory); - s->m_parent = parent; - parent->m_children.insert(node, s); - parent = s; - } else { - parent = parent->m_children[node]; - } - } - - const QString filename = nodes.at(nodes.size()-1); - RCCFileInfo *s = new RCCFileInfo(file); - s->m_parent = parent; - if (parent->m_children.contains(filename)) { - foreach (const QString &fileName, m_fileNames) - qWarning("%s: Warning: potential duplicate alias detected: '%s'", - qPrintable(fileName), qPrintable(filename)); - } - parent->m_children.insertMulti(filename, s); - return true; -} - -void RCCResourceLibrary::reset() -{ - if (m_root) { - delete m_root; - m_root = nullptr; - } - m_errorDevice = nullptr; - m_failedResources.clear(); -} - - -bool RCCResourceLibrary::readFiles(bool ignoreErrors, QIODevice &errorDevice) -{ - reset(); - m_errorDevice = &errorDevice; - //read in data - if (m_verbose) { - const QString msg = QString::fromUtf8("Processing %1 files [%2]\n") - .arg(m_fileNames.size()).arg(static_cast<int>(ignoreErrors)); - m_errorDevice->write(msg.toUtf8()); - } - for (int i = 0; i < m_fileNames.size(); ++i) { - QFile fileIn; - QString fname = m_fileNames.at(i); - QString pwd; - if (fname == QLatin1String("-")) { - fname = QLatin1String("(stdin)"); - pwd = QDir::currentPath(); - fileIn.setFileName(fname); - if (!fileIn.open(stdin, QIODevice::ReadOnly)) { - m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8()); - return false; - } - } else { - pwd = QFileInfo(fname).path(); - fileIn.setFileName(fname); - if (!fileIn.open(QIODevice::ReadOnly)) { - m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8()); - return false; - } - } - if (m_verbose) { - const QString msg = QString::fromUtf8("Interpreting %1\n").arg(fname); - m_errorDevice->write(msg.toUtf8()); - } - - if (!interpretResourceFile(&fileIn, fname, pwd, ignoreErrors)) - return false; - } - return true; -} - -QStringList RCCResourceLibrary::dataFiles() const -{ - QStringList ret; - QStack<RCCFileInfo*> pending; - - if (!m_root) - return ret; - pending.push(m_root); - while (!pending.isEmpty()) { - RCCFileInfo *file = pending.pop(); - for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin(); - it != file->m_children.end(); ++it) { - RCCFileInfo *child = it.value(); - if (child->m_flags & RCCFileInfo::Directory) - pending.push(child); - ret.append(child->m_fileInfo.filePath()); - } - } - return ret; -} - -// Determine map of resource identifier (':/newPrefix/images/p1.png') to file via recursion -static void resourceDataFileMapRecursion(const RCCFileInfo *m_root, const QString &path, RCCResourceLibrary::ResourceDataFileMap &m) -{ - typedef QHash<QString, RCCFileInfo*>::const_iterator ChildConstIterator; - const QChar slash = QLatin1Char('/'); - const ChildConstIterator cend = m_root->m_children.constEnd(); - for (ChildConstIterator it = m_root->m_children.constBegin(); it != cend; ++it) { - const RCCFileInfo *child = it.value(); - QString childName = path; - childName += slash; - childName += child->m_name; - if (child->m_flags & RCCFileInfo::Directory) { - resourceDataFileMapRecursion(child, childName, m); - } else { - m.insert(childName, child->m_fileInfo.filePath()); - } - } -} - -RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap() const -{ - ResourceDataFileMap rc; - if (m_root) - resourceDataFileMapRecursion(m_root, QString(QLatin1Char(':')), rc); - return rc; -} - -bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &errorDevice) -{ - m_errorDevice = &errorDevice; - //write out - if (m_verbose) - m_errorDevice->write("Outputting code\n"); - if (!writeHeader()) { - m_errorDevice->write("Cannot write header\n"); - return false; - } - if (m_root) { - if (!writeDataBlobs()) { - m_errorDevice->write("Cannot write data blobs.\n"); - return false; - } - if (!writeDataNames()) { - m_errorDevice->write("Cannot write file names\n"); - return false; - } - if (!writeDataStructure()) { - m_errorDevice->write("Cannot write data tree\n"); - return false; - } - } - if (!writeInitializer()) { - m_errorDevice->write("Cannot write footer\n"); - return false; - } - outDevice.write(m_out.constData(), m_out.size()); - return true; -} - -void RCCResourceLibrary::writeHex(quint8 tmp) -{ - const char digits[] = "0123456789abcdef"; - writeChar('0'); - writeChar('x'); - if (tmp < 16) { - writeChar(digits[tmp]); - } else { - writeChar(digits[tmp >> 4]); - writeChar(digits[tmp & 0xf]); - } - writeChar(','); -} - -void RCCResourceLibrary::writeNumber2(quint16 number) -{ - if (m_format == RCCResourceLibrary::Binary) { - writeChar(number >> 8); - writeChar(number); - } else { - writeHex(number >> 8); - writeHex(number); - } -} - -void RCCResourceLibrary::writeNumber4(quint32 number) -{ - if (m_format == RCCResourceLibrary::Binary) { - writeChar(number >> 24); - writeChar(number >> 16); - writeChar(number >> 8); - writeChar(number); - } else { - writeHex(number >> 24); - writeHex(number >> 16); - writeHex(number >> 8); - writeHex(number); - } -} - -bool RCCResourceLibrary::writeHeader() -{ - if (m_format == C_Code) { - writeString("/****************************************************************************\n"); - writeString("** Resource object code\n"); - writeString("**\n"); - writeString("** Created: "); - writeByteArray(QDateTime::currentDateTime().toString().toLatin1()); - writeString("\n** by: The Resource Compiler for Qt version "); - writeByteArray(QT_VERSION_STR); - writeString("\n**\n"); - writeString("** WARNING! All changes made in this file will be lost!\n"); - writeString( "*****************************************************************************/\n\n"); - writeString("#include <QtCore/qglobal.h>\n\n"); - } else if (m_format == Binary) { - writeString("qres"); - writeNumber4(0); - writeNumber4(0); - writeNumber4(0); - writeNumber4(0); - } - return true; -} - -bool RCCResourceLibrary::writeDataBlobs() -{ - Q_ASSERT(m_errorDevice); - if (m_format == C_Code) - writeString("static const unsigned char qt_resource_data[] = {\n"); - else if (m_format == Binary) - m_dataOffset = m_out.size(); - QStack<RCCFileInfo*> pending; - - if (!m_root) - return false; - - pending.push(m_root); - qint64 offset = 0; - QString errorMessage; - while (!pending.isEmpty()) { - RCCFileInfo *file = pending.pop(); - for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin(); - it != file->m_children.end(); ++it) { - RCCFileInfo *child = it.value(); - if (child->m_flags & RCCFileInfo::Directory) - pending.push(child); - else { - offset = child->writeDataBlob(*this, offset, &errorMessage); - if (offset == 0) { - m_errorDevice->write(errorMessage.toUtf8()); - return false; - } - } - } - } - if (m_format == C_Code) - writeString("\n};\n\n"); - return true; -} - -bool RCCResourceLibrary::writeDataNames() -{ - if (m_format == C_Code) - writeString("static const unsigned char qt_resource_name[] = {\n"); - else if (m_format == Binary) - m_namesOffset = m_out.size(); - - QHash<QString, int> names; - QStack<RCCFileInfo*> pending; - - if (!m_root) - return false; - - pending.push(m_root); - qint64 offset = 0; - while (!pending.isEmpty()) { - RCCFileInfo *file = pending.pop(); - for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin(); - it != file->m_children.end(); ++it) { - RCCFileInfo *child = it.value(); - if (child->m_flags & RCCFileInfo::Directory) - pending.push(child); - if (names.contains(child->m_name)) { - child->m_nameOffset = names.value(child->m_name); - } else { - names.insert(child->m_name, offset); - offset = child->writeDataName(*this, offset); - } - } - } - if (m_format == C_Code) - writeString("\n};\n\n"); - return true; -} - -static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *right) -{ - return qt_hash(left->m_name) < qt_hash(right->m_name); -} - -bool RCCResourceLibrary::writeDataStructure() -{ - if (m_format == C_Code) - writeString("static const unsigned char qt_resource_struct[] = {\n"); - else if (m_format == Binary) - m_treeOffset = m_out.size(); - QStack<RCCFileInfo*> pending; - - if (!m_root) - return false; - - //calculate the child offsets (flat) - pending.push(m_root); - int offset = 1; - while (!pending.isEmpty()) { - RCCFileInfo *file = pending.pop(); - file->m_childOffset = offset; - - //sort by hash value for binary lookup - QList<RCCFileInfo*> m_children = file->m_children.values(); - qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash); - - //write out the actual data now - for (int i = 0; i < m_children.size(); ++i) { - RCCFileInfo *child = m_children.at(i); - ++offset; - if (child->m_flags & RCCFileInfo::Directory) - pending.push(child); - } - } - - //write out the structure (ie iterate again!) - pending.push(m_root); - m_root->writeDataInfo(*this); - while (!pending.isEmpty()) { - RCCFileInfo *file = pending.pop(); - - //sort by hash value for binary lookup - QList<RCCFileInfo*> m_children = file->m_children.values(); - qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash); - - //write out the actual data now - for (int i = 0; i < m_children.size(); ++i) { - RCCFileInfo *child = m_children.at(i); - child->writeDataInfo(*this); - if (child->m_flags & RCCFileInfo::Directory) - pending.push(child); - } - } - if (m_format == C_Code) - writeString("\n};\n\n"); - - return true; -} - -void RCCResourceLibrary::writeMangleNamespaceFunction(const QByteArray &name) -{ - if (m_useNameSpace) { - writeString("QT_MANGLE_NAMESPACE("); - writeByteArray(name); - writeChar(')'); - } else { - writeByteArray(name); - } -} - -void RCCResourceLibrary::writeAddNamespaceFunction(const QByteArray &name) -{ - if (m_useNameSpace) { - writeString("QT_PREPEND_NAMESPACE("); - writeByteArray(name); - writeChar(')'); - } else { - writeByteArray(name); - } -} - -bool RCCResourceLibrary::writeInitializer() -{ - if (m_format == C_Code) { - //write("\nQT_BEGIN_NAMESPACE\n"); - QString initName = m_initName; - if (!initName.isEmpty()) { - initName.prepend(QLatin1Char('_')); - initName.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_")); - } - - //init - if (m_useNameSpace) - writeString("QT_BEGIN_NAMESPACE\n\n"); - if (m_root) { - writeString("extern Q_CORE_EXPORT bool qRegisterResourceData\n " - "(int, const unsigned char *, " - "const unsigned char *, const unsigned char *);\n\n"); - writeString("extern Q_CORE_EXPORT bool qUnregisterResourceData\n " - "(int, const unsigned char *, " - "const unsigned char *, const unsigned char *);\n\n"); - } - if (m_useNameSpace) - writeString("QT_END_NAMESPACE\n\n\n"); - QString initResources = QLatin1String("qInitResources"); - initResources += initName; - writeString("int "); - writeMangleNamespaceFunction(initResources.toLatin1()); - writeString("()\n{\n"); - - if (m_root) { - writeString(" "); - writeAddNamespaceFunction("qRegisterResourceData"); - writeString("\n (0x01, qt_resource_struct, " - "qt_resource_name, qt_resource_data);\n"); - } - writeString(" return 1;\n"); - writeString("}\n\n"); - writeString("Q_CONSTRUCTOR_FUNCTION("); - writeMangleNamespaceFunction(initResources.toLatin1()); - writeString(")\n\n"); - - //cleanup - QString cleanResources = QLatin1String("qCleanupResources"); - cleanResources += initName; - writeString("int "); - writeMangleNamespaceFunction(cleanResources.toLatin1()); - writeString("()\n{\n"); - if (m_root) { - writeString(" "); - writeAddNamespaceFunction("qUnregisterResourceData"); - writeString("\n (0x01, qt_resource_struct, " - "qt_resource_name, qt_resource_data);\n"); - } - writeString(" return 1;\n"); - writeString("}\n\n"); - writeString("Q_DESTRUCTOR_FUNCTION("); - writeMangleNamespaceFunction(cleanResources.toLatin1()); - writeString(")\n\n"); - } else if (m_format == Binary) { - int i = 4; - char *p = m_out.data(); - p[i++] = 0; // 0x01 - p[i++] = 0; - p[i++] = 0; - p[i++] = 1; - - p[i++] = (m_treeOffset >> 24) & 0xff; - p[i++] = (m_treeOffset >> 16) & 0xff; - p[i++] = (m_treeOffset >> 8) & 0xff; - p[i++] = (m_treeOffset >> 0) & 0xff; - - p[i++] = (m_dataOffset >> 24) & 0xff; - p[i++] = (m_dataOffset >> 16) & 0xff; - p[i++] = (m_dataOffset >> 8) & 0xff; - p[i++] = (m_dataOffset >> 0) & 0xff; - - p[i++] = (m_namesOffset >> 24) & 0xff; - p[i++] = (m_namesOffset >> 16) & 0xff; - p[i++] = (m_namesOffset >> 8) & 0xff; - p[i++] = (m_namesOffset >> 0) & 0xff; - } - return true; -} - -QT_END_NAMESPACE diff --git a/tools/binarycreator/rcc/rcc.h b/tools/binarycreator/rcc/rcc.h deleted file mode 100644 index ecf408dbc..000000000 --- a/tools/binarycreator/rcc/rcc.h +++ /dev/null @@ -1,140 +0,0 @@ -/************************************************************************** -** -** Copyright (C) 2017 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$ -** -**************************************************************************/ - -#ifndef RCC_H -#define RCC_H - -#include <QtCore/QStringList> -#include <QtCore/QHash> -#include <QtCore/QString> - -QT_BEGIN_NAMESPACE - -class RCCFileInfo; -class QIODevice; -class QTextStream; - - -class RCCResourceLibrary -{ - RCCResourceLibrary(const RCCResourceLibrary &); - RCCResourceLibrary &operator=(const RCCResourceLibrary &); - -public: - RCCResourceLibrary(); - ~RCCResourceLibrary(); - - bool output(QIODevice &out, QIODevice &errorDevice); - - bool readFiles(bool ignoreErrors, QIODevice &errorDevice); - - enum Format { Binary, C_Code }; - void setFormat(Format f) { m_format = f; } - Format format() const { return m_format; } - - void setInputFiles(const QStringList &files) { m_fileNames = files; } - QStringList inputFiles() const { return m_fileNames; } - - QStringList dataFiles() const; - - // Return a map of resource identifier (':/newPrefix/images/p1.png') to file. - typedef QHash<QString, QString> ResourceDataFileMap; - ResourceDataFileMap resourceDataFileMap() const; - - void setVerbose(bool b) { m_verbose = b; } - bool verbose() const { return m_verbose; } - - void setInitName(const QString &name) { m_initName = name; } - QString initName() const { return m_initName; } - - void setCompressLevel(int c) { m_compressLevel = c; } - int compressLevel() const { return m_compressLevel; } - - void setCompressThreshold(int t) { m_compressThreshold = t; } - int compressThreshold() const { return m_compressThreshold; } - - void setResourceRoot(const QString &root) { m_resourceRoot = root; } - QString resourceRoot() const { return m_resourceRoot; } - - void setUseNameSpace(bool v) { m_useNameSpace = v; } - bool useNameSpace() const { return m_useNameSpace; } - - QStringList failedResources() const { return m_failedResources; } - -private: - struct Strings { - Strings(); - const QString TAG_RCC; - const QString TAG_RESOURCE; - const QString TAG_FILE; - const QString ATTRIBUTE_LANG; - const QString ATTRIBUTE_PREFIX; - const QString ATTRIBUTE_ALIAS; - const QString ATTRIBUTE_THRESHOLD; - const QString ATTRIBUTE_COMPRESS; - }; - friend class RCCFileInfo; - void reset(); - bool addFile(const QString &alias, const RCCFileInfo &file); - bool interpretResourceFile(QIODevice *inputDevice, const QString &file, - QString currentPath = QString(), bool ignoreErrors = false); - bool writeHeader(); - bool writeDataBlobs(); - bool writeDataNames(); - bool writeDataStructure(); - bool writeInitializer(); - void writeMangleNamespaceFunction(const QByteArray &name); - void writeAddNamespaceFunction(const QByteArray &name); - void writeHex(quint8 number); - void writeNumber2(quint16 number); - void writeNumber4(quint32 number); - void writeChar(char c) { m_out.append(c); } - void writeByteArray(const QByteArray &); - void write(const char *, int len); - - const Strings m_strings; - RCCFileInfo *m_root; - QStringList m_fileNames; - QString m_resourceRoot; - QString m_initName; - Format m_format; - bool m_verbose; - int m_compressLevel; - int m_compressThreshold; - int m_treeOffset; - int m_namesOffset; - int m_dataOffset; - bool m_useNameSpace; - QStringList m_failedResources; - QIODevice *m_errorDevice; - QByteArray m_out; -}; - -QT_END_NAMESPACE - -#endif // RCC_H diff --git a/tools/binarycreator/rcc/rccmain.cpp b/tools/binarycreator/rcc/rccmain.cpp deleted file mode 100644 index 8c33997dd..000000000 --- a/tools/binarycreator/rcc/rccmain.cpp +++ /dev/null @@ -1,239 +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 <rcc.h> -#include "qcorecmdlineargs_p.h" - -#include <QDebug> -#include <QDir> -#include <QFile> -#include <QFileInfo> -#include <QTextStream> - -QT_BEGIN_NAMESPACE - -void showHelp(const QString &argv0, const QString &error) -{ - fprintf(stderr, "Qt resource compiler\n"); - if (!error.isEmpty()) - fprintf(stderr, "%s: %s\n", qPrintable(argv0), qPrintable(error)); - fprintf(stderr, "Usage: %s [options] <inputs>\n\n" - "Options:\n" - " -o file write output to file rather than stdout\n" - " -name name create an external initialization function with name\n" - " -threshold level threshold to consider compressing files\n" - " -compress level compress input files by level\n" - " -root path prefix resource access path with root path\n" - " -no-compress disable all compression\n" - " -binary output a binary file for use as a dynamic resource\n" - " -namespace turn off namespace macros\n" - " -project Output a resource file containing all\n" - " files from the current directory\n" - " -version display version\n" - " -help display this information\n", - qPrintable(argv0)); -} - -void dumpRecursive(const QDir &dir, QTextStream &out) -{ - QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot - | QDir::NoSymLinks); - foreach (const QFileInfo &entry, entries) { - if (entry.isDir()) { - dumpRecursive(entry.filePath(), out); - } else { - out << QLatin1String("<file>") - << entry.filePath() - << QLatin1String("</file>\n"); - } - } -} - -int createProject(const QString &outFileName) -{ - QFile file; - bool isOk = false; - if (outFileName.isEmpty()) { - isOk = file.open(stdout, QFile::WriteOnly | QFile::Text); - } else { - file.setFileName(outFileName); - isOk = file.open(QFile::WriteOnly | QFile::Text); - } - if (!isOk) { - fprintf(stderr, "Unable to open %s: %s\n", - outFileName.isEmpty() ? qPrintable(outFileName) : "standard output", - qPrintable(file.errorString())); - return 1; - } - - QTextStream out(&file); - out << QLatin1String("<!DOCTYPE RCC><RCC version=\"1.0\">\n" - "<qresource>\n"); - - // use "." as dir to get relative file paths - dumpRecursive(QDir(QLatin1String(".")), out); - - out << QLatin1String("</qresource>\n" - "</RCC>\n"); - - return 0; -} - -int runRcc(int argc, char *argv[]) -{ - QString outFilename; - bool helpRequested = false; - bool list = false; - bool projectRequested = false; - QStringList filenamesIn; - - QStringList args = qCmdLineArgs(argc, argv); - - RCCResourceLibrary library; - - //parse options - QString errorMsg; - for (int i = 1; i < args.count() && errorMsg.isEmpty(); i++) { - if (args[i].isEmpty()) - continue; - if (args[i][0] == QLatin1Char('-')) { // option - QString opt = args[i]; - if (opt == QLatin1String("-o")) { - if (!(i < argc-1)) { - errorMsg = QLatin1String("Missing output name"); - break; - } - outFilename = args[++i]; - } else if (opt == QLatin1String("-name")) { - if (!(i < argc-1)) { - errorMsg = QLatin1String("Missing target name"); - break; - } - library.setInitName(args[++i]); - } else if (opt == QLatin1String("-root")) { - if (!(i < argc-1)) { - errorMsg = QLatin1String("Missing root path"); - break; - } - library.setResourceRoot(QDir::cleanPath(args[++i])); - if (library.resourceRoot().isEmpty() - || library.resourceRoot().at(0) != QLatin1Char('/')) - errorMsg = QLatin1String("Root must start with a /"); - } else if (opt == QLatin1String("-compress")) { - if (!(i < argc-1)) { - errorMsg = QLatin1String("Missing compression level"); - break; - } - library.setCompressLevel(args[++i].toInt()); - } else if (opt == QLatin1String("-threshold")) { - if (!(i < argc-1)) { - errorMsg = QLatin1String("Missing compression threshold"); - break; - } - library.setCompressThreshold(args[++i].toInt()); - } else if (opt == QLatin1String("-binary")) { - library.setFormat(RCCResourceLibrary::Binary); - } else if (opt == QLatin1String("-namespace")) { - library.setUseNameSpace(!library.useNameSpace()); - } else if (opt == QLatin1String("-verbose")) { - library.setVerbose(true); - } else if (opt == QLatin1String("-list")) { - list = true; - } else if (opt == QLatin1String("-version") || opt == QLatin1String("-v")) { - fprintf(stderr, "Qt Resource Compiler version %s\n", QT_VERSION_STR); - return 1; - } else if (opt == QLatin1String("-help") || opt == QLatin1String("-h")) { - helpRequested = true; - } else if (opt == QLatin1String("-no-compress")) { - library.setCompressLevel(-2); - } else if (opt == QLatin1String("-project")) { - projectRequested = true; - } else { - errorMsg = QString::fromLatin1("Unknown option: '%1'").arg(args[i]); - } - } else { - if (!QFile::exists(args[i])) { - qWarning("%s: File does not exist '%s'", - qPrintable(args[0]), qPrintable(args[i])); - return 1; - } - filenamesIn.append(args[i]); - } - } - - if (projectRequested && !helpRequested) { - return createProject(outFilename); - } - - if (!filenamesIn.size() || !errorMsg.isEmpty() || helpRequested) { - showHelp(args[0], errorMsg); - return 1; - } - QFile errorDevice; - errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text); - - if (library.verbose()) - errorDevice.write("Qt resource compiler\n"); - - library.setInputFiles(filenamesIn); - - if (!library.readFiles(list, errorDevice)) - return 1; - - // open output - QFile out; - QIODevice::OpenMode mode = QIODevice::WriteOnly; - if (library.format() == RCCResourceLibrary::C_Code) - mode |= QIODevice::Text; - - if (outFilename.isEmpty() || outFilename == QLatin1String("-")) { - // using this overload close() only flushes. - out.open(stdout, mode); - } else { - out.setFileName(outFilename); - if (!out.open(mode)) { - const QString msg = QString::fromUtf8("Unable to open %1 for writing: %2\n").arg(outFilename).arg(out.errorString()); - errorDevice.write(msg.toUtf8()); - return 1; - } - } - - // do the task - if (list) { - const QStringList data = library.dataFiles(); - for (int i = 0; i < data.size(); ++i) { - out.write(qPrintable(QDir::cleanPath(data.at(i)))); - out.write("\n"); - } - return 0; - } - - return library.output(out, errorDevice) ? 0 : 1; -} - -QT_END_NAMESPACE diff --git a/tools/binarycreator/resources/copylibsintobundle.sh b/tools/binarycreator/resources/copylibsintobundle.sh deleted file mode 100644 index 1ad5da4db..000000000 --- a/tools/binarycreator/resources/copylibsintobundle.sh +++ /dev/null @@ -1,189 +0,0 @@ -#!/bin/sh -############################################################################# -## -## Copyright (C) 2017 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$ -## -############################################################################# - - -# this script puts all libs directly needed by the bundle into it - -QTDIR="" -IS_DEBUG=0 -HAVE_CORE=0 -HAVE_SVG=0 -HAVE_PHONON=0 -HAVE_SCRIPT=0 -HAVE_SQL=0 -HAVE_WEBKIT=0 - -function handleFile() -{ - local FILE=$1 - local BUNDLE=$2 - - # all dynamic libs directly needed by the bundle, which are not in /System/Library or in /usr/lib (which are system default libs, which we don't want) - local LIBS=`xcrun otool -L $FILE | grep -v 'executable_path' | grep -v '/System/Library' | grep -v '/usr/lib' | grep '/' | sed -ne 's,^ *\(.*\) (.*,\1,p'` - - local lib - for lib in $LIBS; do - local NAME=`basename $lib` - - if echo $NAME | grep 'QtCore' >/dev/null; then - HAVE_CORE=1 - QTDIR=`echo $lib | sed -ne 's,^\(.*\)/lib/[^/]*QtCore.*$,\1,p'` - if echo $NAME | grep 'debug' >/dev/null; then - IS_DEBUG=1 - fi - elif echo $NAME | grep 'QtSvg' >/dev/null; then - HAVE_SVG=1 - elif echo $NAME | grep 'phonon' >/dev/null; then - HAVE_PHONON=1 - elif echo $NAME | grep 'QtScript' >/dev/null; then - HAVE_SCRIPT=1 - elif echo $NAME | grep 'QtSql' >/dev/null; then - HAVE_SQL=1 - elif echo $NAME | grep 'QtWebKit' >/dev/null; then - HAVE_WEBKIT=1 - fi - - if [ `basename $FILE` != $NAME ]; then - - # this part handles libraries which are macOS frameworks - if echo $lib | grep '\.framework' >/dev/null; then - local FRAMEWORKPATH=`echo $lib | sed -ne 's,\(.*\.framework\).*,\1,p'` - local FRAMEWORKNAME=`basename $FRAMEWORKPATH` - local NEWFRAMEWORKPATH=`echo $lib | sed -ne "s,.*\($FRAMEWORKNAME\),\1,p"` - - # Qt installed via the precompled binaries... - if [ $FRAMEWORKPATH = $FRAMEWORKNAME ]; then - FRAMEWORKPATH="/Library/Frameworks/$FRAMEWORKNAME" - if [ ! -e "$FRAMEWORKPATH" ]; then - echo "Framework $FRAMEWORKNAME not found." - exit 1 - fi - fi - - if [ ! -e "$BUNDLE/Contents/Frameworks/$NEWFRAMEWORKPATH" ]; then - echo Embedding framework $FRAMEWORKNAME - - - # copy the framework into the bundle - cp -R $FRAMEWORKPATH $BUNDLE/Contents/Frameworks - # remove debug libs we've copied - find $BUNDLE/Contents/Frameworks/$FRAMEWORKNAME -regex '.*_debug\(\.dSYM\)*' | xargs rm -rf - - handleFile "$BUNDLE/Contents/Frameworks/$NEWFRAMEWORKPATH" "$BUNDLE" - fi - # and inform the dynamic linker about this - xcrun install_name_tool -change $lib @executable_path/../Frameworks/$NEWFRAMEWORKPATH $FILE - - - # this part handles 'normal' dynamic libraries (.dylib) - else - if [ ! -e "$BUNDLE/Contents/Frameworks/$NAME" ]; then - echo Embedding library $NAME - - # Qt installed via the precompled binaries... - if [ $lib = $NAME ]; then - lib="/Library/Frameworks/$NAME" - if [ ! -e "$lib" ]; then - lib="/usr/lib/$NAME" - fi - if [ ! -e "$lib" ]; then - echo "Library $NAME not found." - exit 1 - fi - fi - - # copy the lib into the bundle - cp $lib $BUNDLE/Contents/Frameworks - handleFile "$BUNDLE/Contents/Frameworks/$NAME" "$BUNDLE" - fi - - # and inform the dynamic linker about this - xcrun install_name_tool -change $lib @executable_path/../Frameworks/$NAME $FILE - fi - - fi - done -} - -function handleQtPlugins() -{ - local PLUGINPATH=$QTDIR/plugins - - # QTDIR was not found, then we're using /Developer/Applications/Qt - if [ "$PLUGINPATH" = "/plugins" ]; then - PLUGINPATH="/Developer/Applications/Qt/plugins" - fi - - CLASS=$1 - EXECUTABLE=$2 - BUNDLE=$3 - mkdir -p $BUNDLE/Contents/plugins/$CLASS - echo Add $CLASS plugins - for plugin in `ls $PLUGINPATH/$CLASS/*`; do - plugin=`basename $plugin` - if echo $plugin | grep 'debug' >/dev/null; then - #if [ $IS_DEBUG -eq 1 ]; then - cp "$PLUGINPATH/$CLASS/$plugin" $BUNDLE/Contents/plugins/$CLASS - xcrun install_name_tool -change $plugin @executable_path/../plugins/$CLASS/$plugin $EXECUTABLE - handleFile $BUNDLE/Contents/plugins/$CLASS/$plugin $BUNDLE - #fi - else - #if [ $IS_DEBUG -eq 0 ]; then - cp "$PLUGINPATH/$CLASS/$plugin" $BUNDLE/Contents/plugins/$CLASS - xcrun install_name_tool -change $plugin @executable_path/../plugins/$CLASS/$plugin $EXECUTABLE - handleFile $BUNDLE/Contents/plugins/$CLASS/$plugin $BUNDLE - #fi - fi - done -} - -# the app bundle we're working with -BUNDLE=$1 -# the executable inside of the bundle -EXECUTABLE=$BUNDLE/Contents/MacOS/`xargs < $BUNDLE/Contents/Info.plist | sed -ne 's,.*<key>CFBundleExecutable</key> <string>\([^<]*\)</string>.*,\1,p'` - -mkdir -p $BUNDLE/Contents/Frameworks - -handleFile $EXECUTABLE $BUNDLE - -if [ $HAVE_CORE -eq 1 ]; then - handleQtPlugins "imageformats" "$EXECUTABLE" "$BUNDLE" -fi -if [ $HAVE_SVG -eq 1 ]; then - handleQtPlugins "iconengines" "$EXECUTABLE" "$BUNDLE" -fi -if [ $HAVE_PHONON -eq 1 ]; then - handleQtPlugins "phonon_backend" "$EXECUTABLE" "$BUNDLE" -fi -if [ $HAVE_SQL -eq 1 ]; then - handleQtPlugins "sqldrivers" "$EXECUTABLE" "$BUNDLE" -fi -if [ $HAVE_WEBKIT -eq 1 ]; then - handleQtPlugins "codecs" "$EXECUTABLE" "$BUNDLE" -fi diff --git a/tools/binarycreator/resources/default_icon_mac.icns b/tools/binarycreator/resources/default_icon_mac.icns Binary files differdeleted file mode 100644 index 8d870d649..000000000 --- a/tools/binarycreator/resources/default_icon_mac.icns +++ /dev/null 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; -} diff --git a/tools/common/repositorygen.h b/tools/common/repositorygen.h deleted file mode 100644 index f5202c1fc..000000000 --- a/tools/common/repositorygen.h +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************** -** -** Copyright (C) 2017 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$ -** -**************************************************************************/ - -#ifndef QINSTALLER_REPOSITORYGEN_H -#define QINSTALLER_REPOSITORYGEN_H - -#include <QHash> -#include <QString> -#include <QStringList> -#include <QVector> -#include <QDomDocument> - -namespace QInstallerTools { - - -struct PackageInfo -{ - QString name; - QString version; - QString directory; - QStringList dependencies; - QStringList copiedFiles; - QString metaFile; - QString metaNode; -}; -typedef QVector<PackageInfo> PackageInfoVector; - -enum FilterType { - Include, - Exclude -}; - -void printRepositoryGenOptions(); -QString makePathAbsolute(const QString &path); -void copyWithException(const QString &source, const QString &target, const QString &kind = QString()); - -PackageInfoVector createListOfPackages(const QStringList &packagesDirectories, QStringList *packagesToFilter, - FilterType ftype); - -PackageInfoVector createListOfRepositoryPackages(const QStringList &repositoryDirectories, QStringList *packagesToFilter, - FilterType filterType); - -QHash<QString, QString> buildPathToVersionMapping(const PackageInfoVector &info); - -void compressMetaDirectories(const QString &repoDir, const QString &existingUnite7zUrl, - const QHash<QString, QString> &versionMapping, bool createSplitMetadata, bool createUnifiedMetadata); - -QStringList unifyMetadata(const QString &repoDir, const QString &existingRepoDir, QDomDocument doc); -void splitMetadata(const QStringList &entryList, const QString &repoDir, QDomDocument doc, - const QHash<QString, QString> &versionMapping); - -void copyMetaData(const QString &outDir, const QString &dataDir, const PackageInfoVector &packages, - const QString &appName, const QString& appVersion, const QStringList &uniteMetadatas); -void copyComponentData(const QStringList &packageDir, const QString &repoDir, PackageInfoVector *const infos); - -void filterNewComponents(const QString &repositoryDir, QInstallerTools::PackageInfoVector &packages); - -QString existingUniteMeta7z(const QString &repositoryDir); - -} // namespace QInstallerTools - -#endif // QINSTALLER_REPOSITORYGEN_H diff --git a/tools/repogen/repogen.cpp b/tools/repogen/repogen.cpp index 5c67cbc1c..10aa0370b 100644 --- a/tools/repogen/repogen.cpp +++ b/tools/repogen/repogen.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -25,8 +25,8 @@ ** $QT_END_LICENSE$ ** **************************************************************************/ -#include "common/repositorygen.h" +#include <repositorygen.h> #include <errors.h> #include <fileutils.h> #include <init.h> diff --git a/tools/repogen/repogen.pri b/tools/repogen/repogen.pri deleted file mode 100644 index 319b137ff..000000000 --- a/tools/repogen/repogen.pri +++ /dev/null @@ -1 +0,0 @@ -INCLUDEPATH += $$PWD/../common diff --git a/tools/repogen/repogen.pro b/tools/repogen/repogen.pro index 016a8fe8e..0380bb78b 100644 --- a/tools/repogen/repogen.pro +++ b/tools/repogen/repogen.pro @@ -2,7 +2,6 @@ TEMPLATE = app TARGET = repogen INCLUDEPATH += . .. -include(repogen.pri) include(../../installerfw.pri) QT -= gui @@ -11,9 +10,7 @@ QT += qml xml CONFIG += console DESTDIR = $$IFW_APP_PATH -SOURCES += repogen.cpp \ - ../common/repositorygen.cpp -HEADERS += ../common/repositorygen.h +SOURCES += repogen.cpp macx:include(../../no_app_bundle.pri) |