diff options
Diffstat (limited to 'src/libs/ifwtools/binarycreator.cpp')
-rw-r--r-- | src/libs/ifwtools/binarycreator.cpp | 176 |
1 files changed, 103 insertions, 73 deletions
diff --git a/src/libs/ifwtools/binarycreator.cpp b/src/libs/ifwtools/binarycreator.cpp index a813c7f50..341052650 100644 --- a/src/libs/ifwtools/binarycreator.cpp +++ b/src/libs/ifwtools/binarycreator.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -43,7 +43,7 @@ #include <QDirIterator> #include <QDomDocument> #include <QProcess> -#include <QRegExp> +#include <QRegularExpression> #include <QSettings> #include <QTemporaryFile> #include <QTemporaryDir> @@ -223,7 +223,7 @@ static QVersionNumber readMachOMinimumSystemVersion(QIODevice *device) } #endif -static int assemble(Input input, const QInstaller::Settings &settings, const QString &signingIdentity) +static int assemble(Input input, const QInstaller::Settings &settings, const BinaryCreatorArgs &args) { #ifdef Q_OS_MACOS if (QInstaller::isInBundle(input.installerExePath)) { @@ -262,7 +262,7 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt QFile pkgInfo(fi.filePath() + QLatin1String("/Contents/PkgInfo")); pkgInfo.open(QIODevice::WriteOnly); QTextStream pkgInfoStream(&pkgInfo); - pkgInfoStream << QLatin1String("APPL????") << endl; + pkgInfoStream << QLatin1String("APPL????") << Qt::endl; } QString iconFile; @@ -282,44 +282,44 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt 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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") << Qt::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; + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">") << Qt::endl; + plistStream << QLatin1String("<plist version=\"1.0\">") << Qt::endl; + plistStream << QLatin1String("<dict>") << Qt::endl; + plistStream << QLatin1String("\t<key>CFBundleIconFile</key>") << Qt::endl; plistStream << QLatin1String("\t<string>") << iconTargetFile << QLatin1String("</string>") - << endl; - plistStream << QLatin1String("\t<key>CFBundlePackageType</key>") << endl; - plistStream << QLatin1String("\t<string>APPL</string>") << endl; + << Qt::endl; + plistStream << QLatin1String("\t<key>CFBundlePackageType</key>") << Qt::endl; + plistStream << QLatin1String("\t<string>APPL</string>") << Qt::endl; #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) - plistStream << QLatin1String("\t<key>CFBundleShortVersionString</key>") << endl; + plistStream << QLatin1String("\t<key>CFBundleShortVersionString</key>") << Qt::endl; plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>") - << endl; - plistStream << QLatin1String("\t<key>CFBundleVersion</key>") << endl; + << Qt::endl; + plistStream << QLatin1String("\t<key>CFBundleVersion</key>") << Qt::endl; plistStream << QLatin1String("\t<string>") << QLatin1String(QUOTE(IFW_VERSION_STR)) << ("</string>") - << endl; + << Qt::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<key>CFBundleSignature</key>") << Qt::endl; + plistStream << QLatin1String("\t<string>\?\?\?\?</string>") << Qt::endl; + plistStream << QLatin1String("\t<key>CFBundleExecutable</key>") << Qt::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; + << Qt::endl; + plistStream << QLatin1String("\t<key>CFBundleIdentifier</key>") << Qt::endl; + plistStream << QLatin1String("\t<string>com.yourcompany.installerbase</string>") << Qt::endl; + plistStream << QLatin1String("\t<key>NOTE</key>") << Qt::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; + << Qt::endl; + plistStream << QLatin1String("\t<key>NSPrincipalClass</key>") << Qt::endl; + plistStream << QLatin1String("\t<string>NSApplication</string>") << Qt::endl; if (!minimumSystemVersion.isEmpty()) { - plistStream << QLatin1String("\t<key>LSMinimumSystemVersion</key>") << endl; - plistStream << QLatin1String("\t<string>") << minimumSystemVersion << QLatin1String("</string>") << endl; + plistStream << QLatin1String("\t<key>LSMinimumSystemVersion</key>") << Qt::endl; + plistStream << QLatin1String("\t<string>") << minimumSystemVersion << QLatin1String("</string>") << Qt::endl; } - plistStream << QLatin1String("</dict>") << endl; - plistStream << QLatin1String("</plist>") << endl; + plistStream << QLatin1String("</dict>") << Qt::endl; + plistStream << QLatin1String("</plist>") << Qt::endl; input.outputPath = QString::fromLatin1("%1/Contents/MacOS/%2").arg(input.outputPath) .arg(fi.completeBaseName()); @@ -405,22 +405,26 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt 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 &copiedFile, info.copiedFiles) { - const QSharedPointer<Resource> resource(new Resource(copiedFile)); - qDebug().nospace() << "Appending " << copiedFile << " (" << humanReadableSize(resource->size()) << ")"; - collection.appendResource(resource); + if (!args.createMaintenanceTool) { + 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 &copiedFile, info.copiedFiles) { + const QSharedPointer<Resource> resource(new Resource(copiedFile)); + qDebug().nospace() << "Appending " << copiedFile << " (" << humanReadableSize(resource->size()) << ")"; + collection.appendResource(resource); + } + input.manager.insertCollection(collection); } - input.manager.insertCollection(collection); + + const QList<QInstaller::OperationBlob> operations; + BinaryContent::writeBinaryContent(&out, operations, input.manager, + BinaryContent::MagicInstallerMarker, BinaryContent::MagicCookie); + } else { + createMTDatFile(out); } - 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); @@ -445,14 +449,14 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt QFile::remove(tempFile); #ifdef Q_OS_MACOS - if (isBundle && !signingIdentity.isEmpty()) { + if (isBundle && !args.signingIdentity.isEmpty()) { qDebug() << "Signing .app bundle..."; QProcess p; p.start(QLatin1String("codesign"), QStringList() << QLatin1String("--force") << QLatin1String("--deep") - << QLatin1String("--sign") << signingIdentity + << QLatin1String("--sign") << args.signingIdentity << bundle); if (!p.waitForFinished(-1)) { @@ -503,8 +507,6 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt QDir(bundle).removeRecursively(); qDebug() << "done."; } -#else - Q_UNUSED(signingIdentity) #endif return EXIT_SUCCESS; } @@ -609,27 +611,38 @@ void QInstallerTools::copyConfigData(const QString &configFile, const QString &t qDebug().noquote() << QString::fromLatin1("Read dom element: <%1>%2</%1>.").arg(tagName, elementText); if (tagName == QLatin1String("ProductImages")) { - const QDomNodeList childNodes = domElement.childNodes(); - for (int index = 0; index < childNodes.count(); ++index) { - const QDomElement childElement = childNodes.at(index).toElement(); - const QString childName = childElement.tagName(); - if (childName != QLatin1String("Image")) + const QDomNodeList productImageNode = domElement.childNodes(); + for (int j = 0; j < productImageNode.count(); ++j) { + QDomElement productImagesElement = productImageNode.at(j).toElement(); + if (productImagesElement.isNull()) continue; + const QString childName = productImagesElement.tagName(); + if (childName != QLatin1String("ProductImage")) + continue; + const QDomNodeList imageNode = productImagesElement.childNodes(); + for (int k = 0; k < imageNode.count(); ++k) { + QDomElement productImageElement = imageNode.at(k).toElement(); + if (productImageElement.isNull()) + continue; + const QString imageChildName = productImageElement.tagName(); + if (imageChildName != QLatin1String("Image")) + continue; + const QString targetFile = targetDir + QLatin1Char('/') + productImageElement.text(); + const QFileInfo childFileInfo = QFileInfo(sourceConfigFilePath, productImageElement.text()); + QInstallerTools::copyWithException(childFileInfo.absoluteFilePath(), targetFile, imageChildName); + copyHighDPIImage(childFileInfo, imageChildName, targetFile); + } - const QString targetFile = targetDir + QLatin1Char('/') + childElement.text(); - const QFileInfo childFileInfo = QFileInfo(sourceConfigFilePath, childElement.text()); - QInstallerTools::copyWithException(childFileInfo.absoluteFilePath(), targetFile, childName); - copyHighDPIImage(childFileInfo, childName, targetFile); } continue; } - QString newName = domElement.text().replace(QRegExp(QLatin1String("\\\\|/|\\.|:")), - QLatin1String("_")); + static const QRegularExpression regex(QLatin1String("\\\\|/|\\.|:")); + QString newName = domElement.text().replace(regex, QLatin1String("_")); QString targetFile; QFileInfo elementFileInfo; - if (tagName == QLatin1String("Icon") || tagName == QLatin1String("InstallerApplicationIcon")) { + if (tagName == QLatin1String("InstallerApplicationIcon")) { #if defined(Q_OS_MACOS) const QString suffix = QLatin1String(".icns"); #elif defined(Q_OS_WIN) @@ -691,13 +704,13 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError // Begin check arguments foreach (const QString &packageDir, args.packagesDirectories) { - if (!QFileInfo(packageDir).exists()) { + if (!QFileInfo::exists(packageDir)) { argumentError = QString::fromLatin1("Error: Package directory not found at the specified location."); return EXIT_FAILURE; } } foreach (const QString &repositoryDir, args.repositoryDirectories) { - if (!QFileInfo(repositoryDir).exists()) { + if (!QFileInfo::exists(repositoryDir)) { argumentError = QString::fromLatin1("Error: Only local filesystem repositories now supported."); return EXIT_FAILURE; } @@ -708,12 +721,12 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError "contain any components apart from the root component."); return EXIT_FAILURE; } - if (!QFileInfo(args.templateBinary).exists()) { + if (!QFileInfo::exists(args.templateBinary)) { #ifdef Q_OS_WIN if (!args.templateBinary.endsWith(suffix)) args.templateBinary = args.templateBinary + suffix; // Try again with added executable suffix - if (!QFileInfo(args.templateBinary).exists()) { + if (!QFileInfo::exists(args.templateBinary)) { argumentError = QString::fromLatin1("Error: Template base binary not found at the specified location."); return EXIT_FAILURE; } @@ -743,7 +756,7 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError "--offline-only at the same time."); return EXIT_FAILURE; } - if (args.target.isEmpty() && !args.compileResource) { + if (args.target.isEmpty() && !args.compileResource && !args.createMaintenanceTool) { argumentError = QString::fromLatin1("Error: Target parameter missing."); return EXIT_FAILURE; } @@ -751,7 +764,9 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError argumentError = QString::fromLatin1("Error: No configuration file selected."); return EXIT_FAILURE; } - if (args.packagesDirectories.isEmpty() && args.repositoryDirectories.isEmpty()) { + if (args.packagesDirectories.isEmpty() && args.repositoryDirectories.isEmpty() + && !args.compileResource + && !args.createMaintenanceTool) { argumentError = QString::fromLatin1("Error: Both Package directory and Repository parameters missing."); return EXIT_FAILURE; } @@ -804,7 +819,8 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError // 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 - copyComponentData(args.packagesDirectories, tmpRepoDir, &preparedPackages); + copyComponentData(args.packagesDirectories, tmpRepoDir, &preparedPackages, + args.archiveSuffix, args.compression); // 2.3; add to common vector packages.append(preparedPackages); } @@ -826,11 +842,6 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError confInternal.setValue(QLatin1String("offlineOnly"), args.offlineOnly); } -#ifdef Q_OS_MACOS - // on mac, we enforce building a bundle - if (!args.target.endsWith(QLatin1String(".app")) && !args.target.endsWith(QLatin1String(".dmg"))) - args.target += QLatin1String(".app"); -#endif if (!args.compileResource) { // 5; put the copied resources into a resource file ResourceCollection metaCollection("QResources"); @@ -840,11 +851,20 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError input.manager.insertCollection(metaCollection); input.packages = packages; - input.outputPath = args.target; + if (args.createMaintenanceTool) + input.outputPath = settings.maintenanceToolName(); + else + input.outputPath = args.target; input.installerExePath = args.templateBinary; +#ifdef Q_OS_MACOS + // on mac, we enforce building a bundle + if (!input.outputPath.endsWith(QLatin1String(".app")) && !input.outputPath.endsWith(QLatin1String(".dmg"))) + input.outputPath += QLatin1String(".app"); +#endif + qDebug() << "Creating the binary"; - exitCode = assemble(input, settings, args.signingIdentity); + exitCode = assemble(input, settings, args); } else { createDefaultResourceFile(tmpMetaDir, QDir::currentPath() + QLatin1String("/update.rcc")); exitCode = EXIT_SUCCESS; @@ -866,3 +886,13 @@ int QInstallerTools::createBinary(BinaryCreatorArgs args, QString &argumentError return exitCode; } + +void QInstallerTools::createMTDatFile(QFile &datFile) +{ + QInstaller::appendInt64(&datFile, 0); // operations start + QInstaller::appendInt64(&datFile, 0); // operations end + QInstaller::appendInt64(&datFile, 0); // resource count + QInstaller::appendInt64(&datFile, 4 * sizeof(qint64)); // data block size + QInstaller::appendInt64(&datFile, BinaryContent::MagicUninstallerMarker); + QInstaller::appendInt64(&datFile, BinaryContent::MagicCookie); +} |