summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKatja Marttila <katja.marttila@qt.io>2022-09-22 15:40:14 +0300
committerKatja Marttila <katja.marttila@qt.io>2022-10-20 12:07:51 +0300
commitf5dff60486e4d6ef355e1420226f1d059b0e441d (patch)
tree63bde6b764d7887f59382ee550551508531d0926
parenta9b7904472b8172f82e751999837b16082731a76 (diff)
Allow generation and signing of MT in macos
Previously maintenance tool could be updated from online repository placing installerbase to repository and setting setInstallerBaseBinary() in install script. The maintenancetool app bundle was written in the code and installerbase placed under .app/Contents/MacOS/. This prevented the maintenancetool app bundle to be signed and notarized. Fixed so that the whole app bundle can be placed to repository. This does not break the signing nor notarization as the whole bundle is copied as it is. The setInstallerBaseBinary() is still needed in the install script so that the installer knows which bundle is the maintenance tool. Old way of updating maintenancetool still exists, if the installerbaseBinary does not contain the ending 'app' installer assumes that the maintenance tool is the executable itself instead of whole app bundle. This change also adds a new binarycreator switch --create-maintenancetool, which can be used in macos to create the app bundle for maintenance tool. Task-number: QTIFW-2750 Change-Id: I3483ddb815d035644e826559947f6f9de4af9361 Reviewed-by: Arttu Tarkiainen <arttu.tarkiainen@qt.io>
-rw-r--r--doc/installerfw.qdoc43
-rw-r--r--src/libs/ifwtools/binarycreator.cpp72
-rw-r--r--src/libs/ifwtools/binarycreator.h4
-rw-r--r--src/libs/installer/packagemanagercore.cpp3
-rw-r--r--src/libs/installer/packagemanagercore.h1
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp146
-rw-r--r--src/libs/installer/packagemanagercore_p.h8
-rw-r--r--src/sdk/sdkapp.h45
-rw-r--r--tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp2
-rw-r--r--tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp2
-rw-r--r--tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp4
-rw-r--r--tests/auto/installer/treename/tst_treename.cpp4
-rw-r--r--tools/binarycreator/main.cpp13
13 files changed, 236 insertions, 111 deletions
diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc
index 29399f0ba..e69a545b2 100644
--- a/doc/installerfw.qdoc
+++ b/doc/installerfw.qdoc
@@ -1861,13 +1861,30 @@
For full reference of elements supported by the configuration file, see \l{Configuration File}.
+ \section2 Getting the Maintenance Tool
+
+ The maintenance tool for Linux and Windows is the same as the \c installerbase
+ executable located in your Qt Installer Framework's \c installation bin folder.
+ For macOS the maintenance tool app bundle can be created using the \c binarycreator
+ tool with the command line switch \c --mt or \c --create-maintenancetool. The
+ name of the macOS app bundle can be configured in config.xml using
+ the \c <MaintenanceToolName> element. The app bundle can be later signed and
+ notarized if needed.
+
+ \code
+ binarycreator -c config/config.xml --mt
+ \endcode
+
\section2 Populating the Maintenance Tool Component
- The \c installerbase executable from Qt Installer Framework's install folder and \c update.rcc
- generated in the \l{Compiling the Update Resource} step should be copied to the component's data
- directory. The meta directory should contain a \c package.xml file with the package information
- elements of your choice. However it is a good idea to mark the component \c <Essential> so that
- it gets automatically installed when running the updater. You may also want to mark the component
+ In Linux and in Windows the \c installerbase executable from Qt Installer
+ Framework's installation folder, or in macOS the maintenance tool app bundle,
+ should be copied to the component's data directory. If you generated the
+ \c update.rcc in the \l{Compiling the Update Resource} step, copy that to
+ the data directory as well. The meta directory should contain a \c package.xml
+ file with the package information elements of your choice. However, it is a
+ good idea to mark the component \c <Essential> so that it gets automatically
+ installed when running the updater. You may also want to mark the component
\c <Virtual> to hide it from the component selection.
For further information about the \c package.xml file, see
@@ -1890,11 +1907,21 @@
Component.prototype.onInstallationStarted = function()
{
if (component.updateRequested() || component.installationRequested()) {
- if (installer.value("os") == "win")
+ if (installer.value("os") == "win") {
component.installerbaseBinaryPath = "@TargetDir@/installerbase.exe";
- else if (installer.value("os") == "x11" || installer.value("os") == "mac")
+ } else if (installer.value("os") == "x11") {
component.installerbaseBinaryPath = "@TargetDir@/installerbase";
-
+ } else if (installer.value("os") == "mac") {
+ // In macOs maintenance tool can be either installerbase from Qt Installer
+ // Framework's install folder, or app bundle created by binarycreator
+ // with --create-maintenancetool switch. "MaintenanceTool.app" -name
+ // may differ depending on what has been defined in config.xml while
+ // creating the maintenance tool.
+ // Use either of the following (not both):
+
+ // component.installerbaseBinaryPath = "@TargetDir@/installerbase";
+ component.installerbaseBinaryPath = "@TargetDir@/MaintenanceTool.app";
+ }
installer.setInstallerBaseBinary(component.installerbaseBinaryPath);
var updateResourceFilePath = installer.value("TargetDir") + "/update.rcc";
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> &params, 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
diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h
index 2d6189960..d5d126f26 100644
--- a/src/sdk/sdkapp.h
+++ b/src/sdk/sdkapp.h
@@ -109,14 +109,9 @@ public:
}
binary.close();
#endif
- QString fileName = datFile(binaryFile());
- quint64 cookie = QInstaller::BinaryContent::MagicCookieDat;
- if (fileName.isEmpty()) {
- fileName = binaryFile();
- cookie = QInstaller::BinaryContent::MagicCookie;
- }
-
- binary.setFileName(fileName);
+ QString datFileName = datFile(binaryFile());
+ quint64 cookie = datFileName.isEmpty() ? QInstaller::BinaryContent::MagicCookie : QInstaller::BinaryContent::MagicCookieDat;
+ binary.setFileName(!datFileName.isEmpty() ? datFileName : binaryFile());
QInstaller::openForRead(&binary);
qint64 magicMarker;
@@ -185,12 +180,12 @@ public:
const QStringList arguments = m_parser.value(CommandLineOptions::scStartClientLong)
.split(QLatin1Char(','), Qt::SkipEmptyParts);
m_core = new QInstaller::PackageManagerCore(
- magicMarker, oldOperations,
+ magicMarker, oldOperations, datFileName,
arguments.value(0, QLatin1String(QInstaller::Protocol::DefaultSocket)),
arguments.value(1, QLatin1String(QInstaller::Protocol::DefaultAuthorizationKey)),
QInstaller::Protocol::Mode::Debug, userArgs, isCommandLineInterface);
} else {
- m_core = new QInstaller::PackageManagerCore(magicMarker, oldOperations,
+ m_core = new QInstaller::PackageManagerCore(magicMarker, oldOperations, datFileName,
QUuid::createUuid().toString(), QUuid::createUuid().toString(),
QInstaller::Protocol::Mode::Production, userArgs, isCommandLineInterface);
}
@@ -469,13 +464,39 @@ public:
if (magicMarker == QInstaller::BinaryContent::MagicUninstallerMarker) {
QFileInfo fi(binaryFile);
QString bundlePath;
+ QString datFileName;
if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath))
fi.setFile(bundlePath);
#ifdef Q_OS_MACOS
- return fi.absoluteDir().filePath(fi.baseName() + QLatin1String(".dat"));
+ datFileName = fi.absoluteDir().filePath(fi.baseName() + QLatin1String(".dat"));
#else
- return fi.absoluteDir().filePath(qApp->applicationName() + QLatin1String(".dat"));
+ datFileName = fi.absoluteDir().filePath(qApp->applicationName() + QLatin1String(".dat"));
#endif
+ // When running maintenance tool, datFile name should be the same as the application name.
+ // In case we have updated maintenance tool in previous maintenance tool run, the datFile
+ // name may not match if the maintenance tool name has changed. In that case try to
+ // look for the dat file from the root folder of the install.
+ if (!QFileInfo::exists(datFileName)) {
+ QFileInfo fi(datFileName);
+ QDirIterator it(fi.absolutePath(),
+ QStringList() << QLatin1String("*.dat"),
+ QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
+ while (it.hasNext()) {
+ try {
+ QFile f(it.next());
+ f.open(QIODevice::ReadOnly);
+ if (f.fileName().endsWith(QLatin1String("installer.dat")))
+ continue;
+ QInstaller::BinaryContent::findMagicCookie(&f, magicMarker);
+ datFileName = f.fileName();
+ break;
+ } catch (const QInstaller::Error &error) {
+ Q_UNUSED(error)
+ continue;
+ }
+ }
+ }
+ return datFileName;
}
return QString();
}
diff --git a/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp b/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp
index baf954a44..67856a74c 100644
--- a/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp
+++ b/tests/auto/installer/createshortcutoperation/tst_createshortcutoperation.cpp
@@ -53,7 +53,7 @@ private:
{
QInstaller::init();
QScopedPointer<PackageManagerCore> core(new PackageManagerCore(BinaryContent::MagicInstallerMarker,
- QList<OperationBlob> (), QString(), Protocol::DefaultAuthorizationKey,
+ QList<OperationBlob> (), QString(), QString(), Protocol::DefaultAuthorizationKey,
Protocol::Mode::Production, QHash<QString, QString>(), true));
core->setAllowedRunningProcesses(QStringList() << QCoreApplication::applicationFilePath());
diff --git a/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp b/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp
index 464e1eef7..d7ef0df90 100644
--- a/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp
+++ b/tests/auto/installer/messageboxhandler/tst_messageboxhandler.cpp
@@ -93,7 +93,7 @@ private slots:
QInstaller::init(); //This will eat debug output
core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList<OperationBlob> (),
- QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production,
+ QString(), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production,
QHash<QString, QString>(), true);
core->setAllowedRunningProcesses(QStringList() << QCoreApplication::applicationFilePath());
core->disableWriteMaintenanceTool();
diff --git a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
index aa74d8dbe..44dc65960 100644
--- a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
+++ b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp
@@ -339,7 +339,7 @@ private slots:
QHash<QString, QString> userValues;
PackageManagerCore *core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList<OperationBlob> (),
- QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production,
+ QString(), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production,
userValues, true);
QCOMPARE(core->value("AllUsers"), QLatin1String(""));
QCOMPARE(core->value("ProductName"), QLatin1String("Unit Test Application"));
@@ -361,7 +361,7 @@ private slots:
userValues.insert("RootDir", "Overwritten RootDir");
PackageManagerCore *core = new PackageManagerCore(BinaryContent::MagicInstallerMarker, QList<OperationBlob> (),
- QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production,
+ QString(), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production,
userValues, true);
QCOMPARE(core->value("AllUsers"), QLatin1String("true"));
QCOMPARE(core->value("ProductName"), QLatin1String("Overwritten ProductName"));
diff --git a/tests/auto/installer/treename/tst_treename.cpp b/tests/auto/installer/treename/tst_treename.cpp
index 3d42126eb..2c8be6ddd 100644
--- a/tests/auto/installer/treename/tst_treename.cpp
+++ b/tests/auto/installer/treename/tst_treename.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 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.
@@ -394,7 +394,7 @@ void tst_TreeName::remotePackageConflictsLocal()
QHash<QString, QString> params;
params.insert(scTargetDir, qApp->applicationDirPath());
PackageManagerCore core(BinaryContent::MagicPackageManagerMarker, QList<OperationBlob>(),
- QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production, params);
+ QString(), QString(), Protocol::DefaultAuthorizationKey, Protocol::Mode::Production, params);
core.settings().setAllowUnstableComponents(true);
core.settings().setDefaultRepositories(QSet<Repository>()
diff --git a/tools/binarycreator/main.cpp b/tools/binarycreator/main.cpp
index d74644670..1840d4c2a 100644
--- a/tools/binarycreator/main.cpp
+++ b/tools/binarycreator/main.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 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.
@@ -72,6 +72,9 @@ static void printUsage()
<< std::endl;
std::cout << " 'update.rcc' in the current path." << std::endl;
#ifdef Q_OS_MACOS
+ std::cout << " --mt|--create-maintenancetool " << std::endl;
+ std::cout << " Creates maintenance tool app bundle. Target option is omitted, bundle name "<<std::endl;
+ std::cout << " can be configured in the config.xml using element <MaintenanceToolName>." << std::endl;
std::cout << " -s|--sign identity Sign generated app bundle using the given code " << std::endl;
std::cout << " signing identity" << std::endl;
#endif
@@ -99,6 +102,11 @@ static void printUsage()
std::cout << "Example update.rcc:" << std::endl;
std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory "
"-rcc" << std::endl;
+#ifdef Q_OS_MACOS
+ std::cout << "Example (maintenance tool bundle):" << std::endl;
+ std::cout << " " << appName << " -c installer-config" << sep << "config.xml" << " --mt" << std::endl;
+ std::cout << std::endl;
+#endif
}
static int printErrorAndUsageAndExit(const QString &err)
@@ -206,6 +214,9 @@ int main(int argc, char **argv)
}
parsedArgs.compression = static_cast<AbstractArchive::CompressionLevel>(value);
#ifdef Q_OS_MACOS
+ } else if (*it == QLatin1String("--mt") || *it == QLatin1String("--create-maintenancetool")) {
+ parsedArgs.createMaintenanceTool = true;
+
} else if (*it == QLatin1String("-s") || *it == QLatin1String("--sign")) {
++it;
if (it == args.end() || it->startsWith(QLatin1String("-")))