From 0f4ceb1950c18d7de27265504e104a65f2be7628 Mon Sep 17 00:00:00 2001 From: kh1 Date: Wed, 16 Oct 2013 15:04:28 +0200 Subject: Implement a way to replace the default resource. Change-Id: I2e362d255bf2526f216cbb872bbb64d37383d229 Reviewed-by: Tim Jenssen Reviewed-by: Michal Klocek --- src/libs/installer/binaryformat.cpp | 23 +++++++++++++- src/libs/installer/binaryformat.h | 1 + src/libs/installer/packagemanagercore_p.cpp | 49 +++++++++++++++++++---------- src/sdk/installerbase.cpp | 5 +++ tools/binarycreator/binarycreator.cpp | 33 +++++++++++++------ 5 files changed, 84 insertions(+), 27 deletions(-) diff --git a/src/libs/installer/binaryformat.cpp b/src/libs/installer/binaryformat.cpp index fe1c61ced..081555a59 100644 --- a/src/libs/installer/binaryformat.cpp +++ b/src/libs/installer/binaryformat.cpp @@ -796,7 +796,7 @@ BinaryContentPrivate::BinaryContentPrivate(const BinaryContentPrivate &other) BinaryContentPrivate::~BinaryContentPrivate() { foreach (const QByteArray &rccData, m_resourceMappings) - QResource::unregisterResource((const uchar*)rccData.constData()); + QResource::unregisterResource((const uchar*)rccData.constData(), QLatin1String(":/metadata")); m_resourceMappings.clear(); } @@ -1137,6 +1137,27 @@ int BinaryContent::registerEmbeddedQResources() return d->m_resourceMappings.count(); } +/*! + Registers the passed file as default resource content. If the embedded resources are already mapped into + memory, it will replace the first with the new content. +*/ +void BinaryContent::registerAsDefaultQResource(const QString &path) +{ + QFile resource(path); + bool success = resource.open(QIODevice::ReadOnly); + if (success && (d->m_resourceMappings.count() > 0)) { + success = QResource::unregisterResource((const uchar*)d->m_resourceMappings.takeFirst().constData(), + QLatin1String(":/metadata")); + } + + if (success) { + d->m_resourceMappings.prepend(addResourceFromBinary(&resource, Range::fromStartAndEnd(0, + resource.size()))); + } else { + qWarning() << QString::fromLatin1("Could not register '%1' as default resource.").arg(path); + } +} + /*! Returns the binary component index as read from the file. */ diff --git a/src/libs/installer/binaryformat.h b/src/libs/installer/binaryformat.h index d255ea8a9..0abe78030 100644 --- a/src/libs/installer/binaryformat.h +++ b/src/libs/installer/binaryformat.h @@ -242,6 +242,7 @@ public: qint64 magicMarker() const; int registerEmbeddedQResources(); + void registerAsDefaultQResource(const QString &path); QInstallerCreator::ComponentIndex componentIndex() const; private: diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index a8978bb52..7cd2c292c 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -1094,7 +1094,25 @@ void PackageManagerCorePrivate::writeUninstallerBinaryData(QIODevice *output, QF const qint64 dataBlockStart = output->pos(); QVector >resourceSegments; - foreach (const Range &segment, layout.metadataResourceSegments) { + QVector >existingResourceSegments = layout.metadataResourceSegments; + + const QString newDefaultResource = m_core->value(QString::fromLatin1("DefaultResourceReplacement")); + if (!newDefaultResource.isEmpty()) { + QFile file(newDefaultResource); + if (file.open(QIODevice::ReadOnly)) { + resourceSegments.append(Range::fromStartAndLength(output->pos(), file.size())); + appendData(output, &file, file.size()); + existingResourceSegments.remove(0); + + file.remove(); // clear all possible leftovers + m_core->setValue(QString::fromLatin1("DefaultResourceReplacement"), QString()); + } else { + qWarning() << QString::fromLatin1("Could not replace default resource with '%1'.") + .arg(newDefaultResource); + } + } + + foreach (const Range &segment, existingResourceSegments) { input->seek(segment.start()); resourceSegments.append(Range::fromStartAndLength(output->pos(), segment.length())); appendData(output, input, segment.length()); @@ -1156,8 +1174,6 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio performedOperations.append(takeOwnedOperation(op)); } - writeMaintenanceConfigFiles(); - #ifdef Q_OS_MAC // if it is a bundle, we need some stuff in it... const QString sourceAppDirPath = QCoreApplication::applicationDirPath(); @@ -1264,12 +1280,8 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio bool newBinaryWritten = false; bool replacementExists = false; - const QString installerBaseBinary = m_core->replaceVariables(m_installerBaseBinaryUnreplaced); - if (!installerBaseBinary.isEmpty() && !QFileInfo(installerBaseBinary).exists()) { - qWarning() << "The current installer base binary could not updated with a not existing '%1'. " - "Please fix the 'installer.setInstallerBaseBinary()' call " - "in your scripts."; - } else if (!installerBaseBinary.isEmpty()) { + const QString installerBaseBinary = replaceVariables(m_installerBaseBinaryUnreplaced); + if (!installerBaseBinary.isEmpty() && QFileInfo(installerBaseBinary).exists()) { qDebug() << "Got a replacement installer base binary:" << installerBaseBinary; QFile replacementBinary(installerBaseBinary); @@ -1285,16 +1297,20 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio qDebug() << error.message(); } - if (replacementBinary.remove()) { - qDebug() << QString::fromLatin1("Removed temporary installer base replacement binary file: %1").arg( - installerBaseBinary); - } else { + 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. - qDebug() << QString::fromLatin1("Could not remove installer base binary (%1) after updating " + qDebug() << QString::fromLatin1("Could not remove installer base binary '%1' after updating " "the uninstaller: %2").arg(installerBaseBinary, replacementBinary.errorString()); + } else { + qDebug() << QString::fromLatin1("Removed installer base binary '%1' after updating the " + "uninstaller/ maintenance tool.").arg(installerBaseBinary); } m_installerBaseBinaryUnreplaced.clear(); + } else if (!installerBaseBinary.isEmpty() && !QFileInfo(installerBaseBinary).exists()) { + qWarning() << QString::fromLatin1("The current uninstaller/ maintenance tool could not be " + "updated. '%1' does not exist. Please fix the 'setInstallerBaseBinary()' call in your script.").arg(installerBaseBinary); } QFile input; @@ -1338,9 +1354,7 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio #endif } - performedOperations = sortOperationsBasedOnComponentDependencies( - performedOperations); - + performedOperations = sortOperationsBasedOnComponentDependencies(performedOperations); m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true")); try { @@ -1371,6 +1385,7 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio appendInt64(&file, MagicCookie); } input.close(); + writeMaintenanceConfigFiles(); deferredRename(dataFile + QLatin1String(".new"), dataFile, false); if (newBinaryWritten) { diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp index e188107f9..8d7518fcf 100644 --- a/src/sdk/installerbase.cpp +++ b/src/sdk/installerbase.cpp @@ -360,6 +360,11 @@ int main(int argc, char *argv[]) } } + // this needs to happen after we parse the arguments, but before we use the actual resources + const QString newDefaultResource = core.value(QString::fromLatin1("DefaultResourceReplacement")); + if (!newDefaultResource.isEmpty()) + content.registerAsDefaultQResource(newDefaultResource); + if (QInstaller::isVerbose()) { qDebug() << "Resource tree after loading the in-binary resource:"; QDirIterator it(QLatin1String(":/"), QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden, diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp index 8792eb537..688ecf4db 100644 --- a/tools/binarycreator/binarycreator.cpp +++ b/tools/binarycreator/binarycreator.cpp @@ -400,7 +400,7 @@ private: const QString oldPath; }; -static QString createBinaryResourceFile(const QString &directory) +static QString createBinaryResourceFile(const QString &directory, const QString &binaryName) { QTemporaryFile projectFile(directory + QLatin1String("/rccprojectXXXXXX.qrc")); if (!projectFile.open()) @@ -408,16 +408,19 @@ static QString createBinaryResourceFile(const QString &directory) projectFile.close(); const WorkingDirectoryChange wd(directory); - const QString binaryName = generateTemporaryFileName(); const QString projectFileName = QFileInfo(projectFile.fileName()).absoluteFilePath(); // 1. create the .qrc file - runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-project") - << QLatin1String("-o") << projectFileName); + if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-project") << QLatin1String("-o") + << projectFileName) != EXIT_SUCCESS) { + throw Error(QString::fromLatin1("Could not create rcc project file.")); + } // 2. create the binary resource file from the .qrc file - runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-binary") - << QLatin1String("-o") << binaryName << projectFileName); + if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-binary") << QLatin1String("-o") + << binaryName << projectFileName) != EXIT_SUCCESS) { + throw Error(QString::fromLatin1("Could not compile rcc project file.")); + } return binaryName; } @@ -467,6 +470,9 @@ static void printUsage() std::cout << " -r|--resources r1,.,rn include the given resource files into the binary" << std::endl; std::cout << " -v|--verbose Verbose output" << std::endl; + std::cout << " -rcc|--compile-resource Compiles the default resource and outputs the result into" + << std::endl; + std::cout << " 'update.rcc' in the current path." << std::endl; std::cout << std::endl; std::cout << "Packages are to be found in the current working directory and get listed as " "their names" << std::endl << std::endl; @@ -483,6 +489,9 @@ static void printUsage() std::cout << std::endl; std::cout << "Creates an installer for the SDK without qt and qt creator." << std::endl; std::cout << std::endl; + std::cout << "Example update.rcc:" << std::endl; + std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " + "-rcc" << std::endl; } void copyConfigData(const QString &configFile, const QString &targetDir) @@ -578,6 +587,7 @@ int main(int argc, char **argv) QStringList resources; QStringList filteredPackages; QInstallerTools::FilterType ftype = QInstallerTools::Exclude; + bool compileResource = false; const QStringList args = app.arguments().mid(1); for (QStringList::const_iterator it = args.begin(); it != args.end(); ++it) { @@ -663,6 +673,8 @@ int main(int argc, char **argv) } else if (*it == QLatin1String("--ignore-translations") || *it == QLatin1String("--ignore-invalid-packages")) { continue; + } else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) { + compileResource = true; } else { if (it->startsWith(QLatin1String("-"))) { return printErrorAndUsageAndExit(QString::fromLatin1("Error: Unknown option \"%1\" used. Maybe you " @@ -691,7 +703,7 @@ int main(int argc, char **argv) ftype = QInstallerTools::Include; } - if (target.isEmpty()) + if (target.isEmpty() && compileResource) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Target parameter missing.")); if (configFile.isEmpty()) @@ -722,11 +734,11 @@ int main(int argc, char **argv) if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) target += QLatin1String(".app"); #endif - { + if (!compileResource) { Input input; input.outputPath = target; input.installerExePath = templateBinary; - input.binaryResourcePath = createBinaryResourceFile(tmpMetaDir); + input.binaryResourcePath = createBinaryResourceFile(tmpMetaDir, generateTemporaryFileName()); input.binaryResources = createBinaryResourceFiles(resources); QInstallerTools::copyComponentData(packagesDirectory, tmpMetaDir, &packages); @@ -754,6 +766,9 @@ int main(int argc, char **argv) QFile::remove(input.binaryResourcePath); foreach (const QString &resource, input.binaryResources) QFile::remove(resource); + } else { + createBinaryResourceFile(tmpMetaDir, QDir::currentPath() + QLatin1String("/update.rcc")); + exitCode = EXIT_SUCCESS; } } catch (const Error &e) { std::cerr << "Caught exception: " << e.message() << std::endl; -- cgit v1.2.3