summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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("-")))