diff options
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/ifwtools/binarycreator.cpp | 72 | ||||
-rw-r--r-- | src/libs/ifwtools/binarycreator.h | 4 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 3 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.h | 1 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 146 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.h | 8 |
6 files changed, 150 insertions, 84 deletions
diff --git a/src/libs/ifwtools/binarycreator.cpp b/src/libs/ifwtools/binarycreator.cpp index 5bef651a8..d7adc2a52 100644 --- a/src/libs/ifwtools/binarycreator.cpp +++ b/src/libs/ifwtools/binarycreator.cpp @@ -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)) { @@ -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; } @@ -754,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; } @@ -762,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() && !args.compileResource) { + 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; } @@ -838,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"); @@ -852,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; @@ -878,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); +} diff --git a/src/libs/ifwtools/binarycreator.h b/src/libs/ifwtools/binarycreator.h index 7c14ea039..779725660 100644 --- a/src/libs/ifwtools/binarycreator.h +++ b/src/libs/ifwtools/binarycreator.h @@ -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. @@ -68,6 +68,7 @@ struct IFWTOOLS_EXPORT BinaryCreatorArgs FilterType ftype = QInstallerTools::Exclude; bool compileResource = false; QString signingIdentity; + bool createMaintenanceTool = false; }; class BundleBackup @@ -124,6 +125,7 @@ void copyConfigData(const QString &configFile, const QString &targetDir); void copyHighDPIImage(const QFileInfo &childFileInfo, const QString &childName, const QString &targetFile); int IFWTOOLS_EXPORT createBinary(BinaryCreatorArgs args, QString &argumentError); +void IFWTOOLS_EXPORT createMTDatFile(QFile &datFile); } // namespace QInstallerTools diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 0c9533c8d..48d071321 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -1289,9 +1289,10 @@ PackageManagerCore::PackageManagerCore() and \a mode to set the server side authorization key. */ PackageManagerCore::PackageManagerCore(qint64 magicmaker, const QList<OperationBlob> &operations, + const QString &datFileName, const QString &socketName, const QString &key, Protocol::Mode mode, const QHash<QString, QString> ¶ms, const bool commandLineInstance) - : d(new PackageManagerCorePrivate(this, magicmaker, operations)) + : d(new PackageManagerCorePrivate(this, magicmaker, operations, datFileName)) { setCommandLineInstance(commandLineInstance); Repository::registerMetaType(); // register, cause we stream the type as QVariant diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index ebb590e35..db1c0765f 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -63,6 +63,7 @@ class INSTALLER_EXPORT PackageManagerCore : public QObject public: PackageManagerCore(); PackageManagerCore(qint64 magicmaker, const QList<OperationBlob> &ops, + const QString &datFilename = QString(), const QString &socketName = QString(), const QString &key = QLatin1String(Protocol::DefaultAuthorizationKey), Protocol::Mode mode = Protocol::Mode::Production, diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 845c9cf02..c61c6bc99 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -188,11 +188,12 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core) , m_autoAcceptLicenses(false) , m_disableWriteMaintenanceTool(false) , m_autoConfirmCommand(false) + , m_datFileName(QString()) { } PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker, - const QList<OperationBlob> &performedOperations) + const QList<OperationBlob> &performedOperations, const QString &datFileName) : m_updateFinder(nullptr) , m_localPackageHub(std::make_shared<LocalPackageHub>()) , m_status(PackageManagerCore::Unfinished) @@ -226,6 +227,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q , m_autoAcceptLicenses(false) , m_disableWriteMaintenanceTool(false) , m_autoConfirmCommand(false) + , m_datFileName(datFileName) { foreach (const OperationBlob &operation, performedOperations) { QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance() @@ -766,7 +768,12 @@ Operation *PackageManagerCorePrivate::takeOwnedOperation(Operation *operation) QString PackageManagerCorePrivate::maintenanceToolName() const { - QString filename = m_data.settings().maintenanceToolName(); + QString filename; + if (isInstaller()) + filename = m_data.settings().maintenanceToolName(); + else + filename = QCoreApplication::applicationName(); + #if defined(Q_OS_MACOS) if (QInstaller::isInBundle(QCoreApplication::applicationDirPath())) filename += QLatin1String(".app/Contents/MacOS/") + filename; @@ -809,6 +816,13 @@ QString PackageManagerCorePrivate::offlineBinaryName() const return QString::fromLatin1("%1/%2").arg(targetDir()).arg(filename); } +QString PackageManagerCorePrivate::datFileName() +{ + if (m_datFileName.isEmpty()) + m_datFileName = targetDir() + QLatin1Char('/') + m_data.settings().maintenanceToolName() + QLatin1String(".dat"); + return m_datFileName; +} + static QNetworkProxy readProxy(QXmlStreamReader &reader) { QNetworkProxy proxy(QNetworkProxy::HttpProxy); @@ -1153,12 +1167,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q // other code a lot (since installers don't have any appended data either) QFile dataOut(generateTemporaryFileName()); QInstaller::openForWrite(&dataOut); - QInstaller::appendInt64(&dataOut, 0); // operations start - QInstaller::appendInt64(&dataOut, 0); // operations end - QInstaller::appendInt64(&dataOut, 0); // resource count - QInstaller::appendInt64(&dataOut, 4 * sizeof(qint64)); // data block size - QInstaller::appendInt64(&dataOut, BinaryContent::MagicUninstallerMarker); - QInstaller::appendInt64(&dataOut, BinaryContent::MagicCookie); + QInstallerTools::createMTDatFile(dataOut); { QFile dummy(resourcePath.filePath(QLatin1String("installer.dat"))); @@ -1263,19 +1272,9 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinaryData(QFileDevice *outp QInstaller::appendInt64(output, BinaryContent::MagicUninstallerMarker); } -void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOperations) +void PackageManagerCorePrivate::writeMaintenanceToolAppBundle(OperationList &performedOperations) { - if (m_disableWriteMaintenanceTool) { - qCDebug(QInstaller::lcInstallerInstallLog()) << "Maintenance tool writing disabled."; - return; - } - - bool gainedAdminRights = false; - if (!directoryWritable(targetDir())) { - m_core->gainAdminRights(); - gainedAdminRights = true; - } - +#ifdef Q_OS_MACOS const QString targetAppDirPath = QFileInfo(maintenanceToolName()).path(); if (!QDir().exists(targetAppDirPath)) { // create the directory containing the maintenance tool (like a bundle structure on macOS...) @@ -1285,8 +1284,6 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper performOperationThreaded(op); performedOperations.append(takeOwnedOperation(op)); } - -#ifdef Q_OS_MACOS // if it is a bundle, we need some stuff in it... const QString sourceAppDirPath = QCoreApplication::applicationDirPath(); if (isInstaller() && QInstaller::isInBundle(sourceAppDirPath)) { @@ -1357,6 +1354,20 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper performOperationThreaded(op); } #endif +} + +void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOperations) +{ + if (m_disableWriteMaintenanceTool) { + qCDebug(QInstaller::lcInstallerInstallLog()) << "Maintenance tool writing disabled."; + return; + } + + bool gainedAdminRights = false; + if (!directoryWritable(targetDir())) { + m_core->gainAdminRights(); + gainedAdminRights = true; + } try { // 1 - check if we have a installer base replacement @@ -1392,45 +1403,70 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper // 5.1 - this will only happen -if- we wrote out a new binary bool newBinaryWritten = false; - bool replacementExists = false; + QString mtName = maintenanceToolName(); const QString installerBaseBinary = replaceVariables(m_installerBaseBinaryUnreplaced); if (!installerBaseBinary.isEmpty() && QFileInfo(installerBaseBinary).exists()) { qCDebug(QInstaller::lcInstallerInstallLog) << "Got a replacement installer base binary:" << installerBaseBinary; - - QFile replacementBinary(installerBaseBinary); - try { - QInstaller::openForRead(&replacementBinary); - writeMaintenanceToolBinary(&replacementBinary, replacementBinary.size(), true); - qCDebug(QInstaller::lcInstallerInstallLog) << "Wrote the binary with the new replacement."; - - newBinaryWritten = true; - replacementExists = true; - } catch (const Error &error) { - qCWarning(QInstaller::lcInstallerInstallLog) << error.message(); - } - - if (!replacementBinary.remove()) { - // Is there anything more sensible we can do with this error? I think not. It's not serious - // enough for throwing / aborting the process. - qCDebug(QInstaller::lcInstallerInstallLog) << "Cannot remove installer base binary" - << installerBaseBinary << "after updating the maintenance tool:" - << replacementBinary.errorString(); + if (QInstaller::isInBundle(installerBaseBinary)) { + // In macOS the installerbase is a whole app bundle. We do not modify the maintenancetool name in app bundle + // so that possible signing and notarization will remain. Therefore, the actual maintenance tool name might + // differ from the one defined in the settings. + try { + const QString maintenanceToolRenamedName = installerBaseBinary + QLatin1String(".new"); + qCDebug(QInstaller::lcInstallerInstallLog) << "Writing maintenance tool " << maintenanceToolRenamedName; + QInstaller::copyDirectoryContents(installerBaseBinary, maintenanceToolRenamedName); + + newBinaryWritten = true; + mtName = installerBaseBinary; + } catch (const Error &error) { + qCWarning(QInstaller::lcInstallerInstallLog) << error.message(); + } + try { + QInstaller::removeDirectory(installerBaseBinary); + qCDebug(QInstaller::lcInstallerInstallLog) << "Removed installer base binary" + << installerBaseBinary << "after updating the maintenance tool."; + } catch (const Error &error) { + qCDebug(QInstaller::lcInstallerInstallLog) << "Cannot remove installer base binary" + << installerBaseBinary << "after updating the maintenance tool:" + << error.message(); + } } else { - qCDebug(QInstaller::lcInstallerInstallLog) << "Removed installer base binary" - << installerBaseBinary << "after updating the maintenance tool."; + QFile replacementBinary(installerBaseBinary); + try { + QInstaller::openForRead(&replacementBinary); + writeMaintenanceToolBinary(&replacementBinary, replacementBinary.size(), true); + qCDebug(QInstaller::lcInstallerInstallLog) << "Wrote the binary with the new replacement."; + + newBinaryWritten = true; + } catch (const Error &error) { + qCWarning(QInstaller::lcInstallerInstallLog) << error.message(); + } + + if (!replacementBinary.remove()) { + // Is there anything more sensible we can do with this error? I think not. It's not serious + // enough for throwing / aborting the process. + qCDebug(QInstaller::lcInstallerInstallLog) << "Cannot remove installer base binary" + << installerBaseBinary << "after updating the maintenance tool:" + << replacementBinary.errorString(); + } else { + qCDebug(QInstaller::lcInstallerInstallLog) << "Removed installer base binary" + << installerBaseBinary << "after updating the maintenance tool."; + } } m_installerBaseBinaryUnreplaced.clear(); } else if (!installerBaseBinary.isEmpty() && !QFileInfo(installerBaseBinary).exists()) { qCWarning(QInstaller::lcInstallerInstallLog) << "The current maintenance tool could not be updated." << installerBaseBinary << "does not exist. Please fix the \"setInstallerBaseBinary" "(<temp_installer_base_binary_path>)\" call in your script."; + writeMaintenanceToolAppBundle(performedOperations); + } else { + writeMaintenanceToolAppBundle(performedOperations); } QFile input; BinaryLayout layout; - const QString dataFile = targetDir() + QLatin1Char('/') + m_data.settings().maintenanceToolName() - + QLatin1String(".dat"); + const QString dataFile = datFileName(); try { if (isInstaller()) { if (QFile::exists(dataFile)) { @@ -1526,7 +1562,9 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper writeMaintenanceConfigFiles(); QFile::remove(dataFile); - QFile::rename(dataFile + QLatin1String(".new"), dataFile); + QFileInfo fi(mtName); + //Rename the dat file according to maintenancetool name + QFile::rename(dataFile + QLatin1String(".new"), targetDir() + QLatin1Char('/') + fi.baseName() + QLatin1String(".dat")); const bool restart = !statusCanceledOrFailed() && m_needsHardRestart; qCDebug(QInstaller::lcInstallerInstallLog) << "Maintenance tool hard restart:" @@ -1534,11 +1572,11 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper if (newBinaryWritten) { if (isInstaller()) - QFile::rename(maintenanceToolName() + QLatin1String(".new"), maintenanceToolName()); + QFile::rename(mtName + QLatin1String(".new"), mtName); else - deferredRename(maintenanceToolName() + QLatin1String(".new"), maintenanceToolName(), restart); - - writeMaintenanceToolAlias(); + deferredRename(mtName + QLatin1String(".new"), mtName, restart); + QFileInfo mtFileName(mtName); + writeMaintenanceToolAlias(mtFileName.fileName()); } else if (restart) { SelfRestarter::setRestartOnQuit(true); } @@ -1610,7 +1648,7 @@ void PackageManagerCorePrivate::writeOfflineBaseBinary() } } -void PackageManagerCorePrivate::writeMaintenanceToolAlias() +void PackageManagerCorePrivate::writeMaintenanceToolAlias(const QString &maintenanceToolName) { #ifdef Q_OS_MACOS const QString aliasPath = maintenanceToolAliasPath(); @@ -1618,7 +1656,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolAlias() return; QString maintenanceToolBundle = QString::fromLatin1("%1/%2") - .arg(targetDir(), m_data.settings().maintenanceToolName()); + .arg(targetDir(), maintenanceToolName); if (!maintenanceToolBundle.endsWith(QLatin1String(".app"))) maintenanceToolBundle += QLatin1String(".app"); @@ -1627,6 +1665,8 @@ void PackageManagerCorePrivate::writeMaintenanceToolAlias() targetDir.mkpath(targetDir.absolutePath()); mkalias(maintenanceToolBundle, aliasPath); +#else + Q_UNUSED(maintenanceToolName) #endif } diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index d7c0b30d3..a42033ff6 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -69,7 +69,7 @@ class PackageManagerCorePrivate : public QObject public: explicit PackageManagerCorePrivate(PackageManagerCore *core); explicit PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker, - const QList<OperationBlob> &performedOperations); + const QList<OperationBlob> &performedOperations, const QString &datFileName); ~PackageManagerCorePrivate(); static bool isProcessRunning(const QString &name, const QList<ProcessInfo> &processes); @@ -92,6 +92,7 @@ public: QString maintenanceToolAliasPath() const; QString installerBinaryPath() const; QString offlineBinaryName() const; + QString datFileName(); void writeMaintenanceConfigFiles(); void readMaintenanceConfigFiles(const QString &targetDir); @@ -99,7 +100,7 @@ public: void writeMaintenanceTool(OperationList performedOperations); void writeOfflineBaseBinary(); - void writeMaintenanceToolAlias(); + void writeMaintenanceToolAlias(const QString &maintenanceToolName); QString componentsXmlPath() const; QString configurationFileName() const; @@ -254,6 +255,7 @@ private: void writeMaintenanceToolBinary(QFile *const input, qint64 size, bool writeBinaryLayout); void writeMaintenanceToolBinaryData(QFileDevice *output, QFile *const input, const OperationList &performed, const BinaryLayout &layout); + void writeMaintenanceToolAppBundle(OperationList &performedOperations); void runUndoOperations(const OperationList &undoOperations, double undoOperationProgressSize, bool adminRightsGained, bool deleteOperation); @@ -324,6 +326,8 @@ private: // < name (component replacing others), components to replace> QHash<QString, QStringList > m_componentReplaces; + + QString m_datFileName; }; } // namespace QInstaller |