diff options
Diffstat (limited to 'tools/binarycreator/binarycreator.cpp')
-rw-r--r-- | tools/binarycreator/binarycreator.cpp | 250 |
1 files changed, 132 insertions, 118 deletions
diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp index 594686e61..8589192bb 100644 --- a/tools/binarycreator/binarycreator.cpp +++ b/tools/binarycreator/binarycreator.cpp @@ -46,6 +46,7 @@ #include <errors.h> #include <fileutils.h> #include <init.h> +#include <repository.h> #include <settings.h> #include <utils.h> @@ -113,15 +114,8 @@ static void chmod755(const QString &absolutFilePath) } #endif -static int assemble(Input input, const QString &configFile) +static int assemble(Input input, const QInstaller::Settings &settings) { - const QString configDir = QFileInfo(configFile).canonicalPath(); - const QInstaller::Settings &settings = QInstaller::Settings::fromFileAndPrefix(configFile, configDir); - -#ifdef Q_OS_LINUX -Q_UNUSED(settings) -#endif - #ifdef Q_OS_MAC if (QFileInfo(input.installerExePath).isBundle()) { const QString bundle = input.installerExePath; @@ -144,8 +138,11 @@ Q_UNUSED(settings) if (isBundle) { // output should be a bundle const QFileInfo fi(input.outputPath); + + const QString contentsResourcesPath = fi.filePath() + QLatin1String("/Contents/Resources/"); + QInstaller::mkpath(fi.filePath() + QLatin1String("/Contents/MacOS")); - QInstaller::mkpath(fi.filePath() + QLatin1String("/Contents/Resources")); + QInstaller::mkpath(contentsResourcesPath); { QFile pkgInfo(fi.filePath() + QLatin1String("/Contents/PkgInfo")); @@ -154,10 +151,20 @@ Q_UNUSED(settings) pkgInfoStream << QLatin1String("APPL????") << endl; } - const QString iconFile = QFile::exists(settings.icon()) ? settings.icon() - : QString::fromLatin1(":/resources/default_icon_mac.icns"); + QString iconFile; + if (QFile::exists(settings.installerApplicationIcon())) { + iconFile = settings.installerApplicationIcon(); + } else { + iconFile = QFile::exists(settings.icon()) ? settings.icon() + : QString::fromLatin1(":/resources/default_icon_mac.icns"); + } + const QString iconTargetFile = fi.completeBaseName() + QLatin1String(".icns"); - QFile::copy(iconFile, fi.filePath() + QLatin1String("/Contents/Resources/") + iconTargetFile); + QFile::copy(iconFile, contentsResourcesPath + iconTargetFile); + if (QDir(qApp->applicationDirPath() + QLatin1String("/qt_menu.nib")).exists()) { + copyDirectoryContents(qApp->applicationDirPath() + QLatin1String("/qt_menu.nib"), + contentsResourcesPath + QLatin1String("/qt_menu.nib")); + } QFile infoPList(fi.filePath() + QLatin1String("/Contents/Info.plist")); infoPList.open(QIODevice::WriteOnly); @@ -175,7 +182,10 @@ Q_UNUSED(settings) plistStream << QLatin1String(" <key>CFBundleGetInfoString</key>") << endl; #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) - plistStream << QLatin1String(" <string>") << QLatin1String(QUOTE(IFW_VERSION)) << ("</string>") << endl; + plistStream << QLatin1String(" <string>") << QLatin1String(QUOTE(IFW_VERSION)) << ("</string>") + << endl; +#undef QUOTE +#undef QUOTE_ plistStream << QLatin1String(" <key>CFBundleSignature</key>") << endl; plistStream << QLatin1String(" <string> ???? </string>") << endl; plistStream << QLatin1String(" <key>CFBundleExecutable</key>") << endl; @@ -184,14 +194,18 @@ Q_UNUSED(settings) plistStream << QLatin1String(" <key>CFBundleIdentifier</key>") << endl; plistStream << QLatin1String(" <string>com.yourcompany.installerbase</string>") << endl; plistStream << QLatin1String(" <key>NOTE</key>") << endl; - plistStream << QLatin1String(" <string>This file was generated by Qt/QMake.</string>") + plistStream << QLatin1String(" <string>This file was generated by Qt Installer Framework.</string>") << endl; + plistStream << QLatin1String(" <key>NSPrincipalClass</key>") << endl; + plistStream << QLatin1String(" <string>NSApplication</string>") << endl; plistStream << QLatin1String("</dict>") << endl; plistStream << QLatin1String("</plist>") << endl; input.outputPath = QString::fromLatin1("%1/Contents/MacOS/%2").arg(input.outputPath) .arg(fi.completeBaseName()); } +#elif defined(Q_OS_LINUX) + Q_UNUSED(settings) #endif QTemporaryFile file(input.outputPath); @@ -218,9 +232,13 @@ Q_UNUSED(settings) #if defined(Q_OS_WIN) // setting the windows icon must happen before we append our binary data - otherwise they get lost :-/ - if (QFile::exists(settings.icon())) { + if (QFile::exists(settings.installerApplicationIcon())) { // no error handling as this is not fatal - setApplicationIcon(tempFile, settings.icon()); + setApplicationIcon(tempFile, settings.installerApplicationIcon()); + } else { + if (QFile::exists(settings.icon())) { + setApplicationIcon(tempFile, settings.icon()); + } } #elif defined(Q_OS_MAC) if (isBundle) { @@ -311,14 +329,14 @@ Q_UNUSED(settings) } catch (const Error &e) { qCritical("Error occurred while assembling the installer: %s", qPrintable(e.message())); QFile::remove(tempFile); - return 1; + return EXIT_FAILURE; } if (!out.commit(KDSaveFile::OverwriteExistingFile)) { qCritical("Could not write installer to %s: %s", qPrintable(out.fileName()), qPrintable(out.errorString())); QFile::remove(tempFile); - return 1; + return EXIT_FAILURE; } #ifndef Q_OS_WIN chmod755(out.fileName()); @@ -342,7 +360,7 @@ Q_UNUSED(settings) qDebug() << "done." << mkdmgscript; } #endif - return 0; + return EXIT_SUCCESS; } QT_BEGIN_NAMESPACE @@ -384,7 +402,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()) @@ -392,16 +410,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; } @@ -451,6 +472,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; @@ -462,97 +486,77 @@ static void printUsage() std::cout << std::endl; std::cout << "Example (online installer):" << std::endl; std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory " - "-e com.nokia.sdk.qt,com.nokia.qtcreator -t installerbase" << suffix << " SDKInstaller" + "-e org.qt-project.sdk.qt,org.qt-project.qtcreator -t installerbase" << suffix << " SDKInstaller" << suffix << std::endl; 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; } -static QString createMetaDataDirectory(const QInstallerTools::PackageInfoVector &packages, - const QString &packagesDir, const QString &configFile) +void copyConfigData(const QString &configFile, const QString &targetDir) { - const QInstaller::Settings &settings = QInstaller::Settings::fromFileAndPrefix(configFile, QString()); + qDebug() << "Begin to copy configuration file and data."; + + const QString sourceConfigFile = QFileInfo(configFile).absoluteFilePath(); + const QString targetConfigFile = targetDir + QLatin1String("/config.xml"); + QInstallerTools::copyWithException(sourceConfigFile, targetConfigFile, QLatin1String("configuration")); - const QString metapath = createTemporaryDirectory(); - generateMetaDataDirectory(metapath, packagesDir, packages, settings.applicationName(), - settings.applicationVersion()); + QFile configXml(targetConfigFile); + QInstaller::openForRead(&configXml, configXml.fileName()); - const QString configCopy = metapath + QLatin1String("/installer-config"); - QInstaller::mkdir(configCopy); - QString absoluteConfigPath = QFileInfo(configFile).absolutePath(); + QDomDocument dom; + dom.setContent(&configXml); + configXml.close(); - QDirIterator it(absoluteConfigPath, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); - while (it.hasNext()) { - const QString next = it.next(); - if (next.contains(QLatin1String("/."))) // skip files that are in directories starting with a point + // iterate over all child elements, searching for relative file names + const QDomNodeList children = dom.documentElement().childNodes(); + const QString sourceConfigFilePath = QFileInfo(sourceConfigFile).absolutePath(); + for (int i = 0; i < children.count(); ++i) { + QDomElement domElement = children.at(i).toElement(); + if (domElement.isNull()) continue; - qDebug() << "\tFound configuration file: " << next; - const QFileInfo sourceFileInfo(next); - const QString source = sourceFileInfo.absoluteFilePath(); - QFileInfo targetFileInfo(configCopy, QFileInfo(next).fileName()); - - if (QFileInfo(next).fileName() == QFileInfo(configFile).fileName()) - targetFileInfo.setFile(configCopy, QLatin1String("config.xml")); - - const QDir targetDir = targetFileInfo.dir(); - if (!targetDir.exists()) - QInstaller::mkpath(targetFileInfo.absolutePath()); - const QString target = targetFileInfo.absoluteFilePath(); - - if (!QFile::copy(source, target)) - throw Error(QString::fromLatin1("Could not copy %1.").arg(source)); - - if (sourceFileInfo.fileName() == QFileInfo(configFile).fileName()) { - QFile configXml(targetDir.filePath(QLatin1String("config.xml"))); - configXml.open(QIODevice::ReadOnly); - QDomDocument dom; - dom.setContent(&configXml); - configXml.close(); - - // iterate over all child elements, searching for relative file names - const QDomNodeList children = dom.documentElement().childNodes(); - for (int i = 0; i < children.count(); ++i) { - QDomElement el = children.at(i).toElement(); - if (el.isNull()) - continue; - - QFileInfo fi(absoluteConfigPath, el.text()); + const QString tagName = domElement.tagName(); + const QString elementText = domElement.text(); + qDebug() << QString::fromLatin1("Read dom element: <%1>%2</%1>.").arg(tagName, elementText); + + QString newName = domElement.text().replace(QRegExp(QLatin1String("\\\\|/|\\.|:")), + QLatin1String("_")); + + QString targetFile; + QFileInfo elementFileInfo; + if (tagName == QLatin1String("Icon") || tagName == QLatin1String("InstallerApplicationIcon")) { #if defined(Q_OS_MAC) - const QFileInfo fiIcon(absoluteConfigPath, el.text() + QLatin1String(".icns")); + const QString suffix = QLatin1String(".icns"); #elif defined(Q_OS_WIN) - const QFileInfo fiIcon(absoluteConfigPath, el.text() + QLatin1String(".ico")); + const QString suffix = QLatin1String(".ico"); #else - const QFileInfo fiIcon(absoluteConfigPath, el.text() + QLatin1String(".png")); + const QString suffix = QLatin1String(".png"); #endif - if (!fi.exists() && fiIcon.exists()) - fi = fiIcon; - - if (!fi.exists() || fi.absolutePath() == QFileInfo(configFile).dir().absolutePath()) - continue; - - if (fi.isDir()) - continue; + elementFileInfo = QFileInfo(sourceConfigFilePath, elementText + suffix); + targetFile = targetDir + QLatin1Char('/') + newName + suffix; + } else { + elementFileInfo = QFileInfo(sourceConfigFilePath, elementText); + const QString suffix = elementFileInfo.completeSuffix(); + if (!suffix.isEmpty()) + newName.append(QLatin1Char('.') + suffix); + targetFile = targetDir + QLatin1Char('/') + newName; + } + if (!elementFileInfo.exists() || elementFileInfo.isDir()) + continue; - const QString newName = el.text().replace(QRegExp(QLatin1String("\\\\|/|\\.")), - QLatin1String("_")); + domElement.replaceChild(dom.createTextNode(newName), domElement.firstChild()); + QInstallerTools::copyWithException(elementFileInfo.absoluteFilePath(), targetFile, tagName); + } - if (!QFile::exists(targetDir.absoluteFilePath(newName))) { - if (!QFile::copy(fi.absoluteFilePath(), targetDir.absoluteFilePath(newName))) - throw Error(QString::fromLatin1("Could not copy %1.").arg(el.text())); - } - el.removeChild(el.firstChild()); - el.appendChild(dom.createTextNode(newName)); - } + QInstaller::openForWrite(&configXml, configXml.fileName()); + QTextStream stream(&configXml); + dom.save(stream, 4); - openForWrite(&configXml, configXml.fileName()); - QTextStream stream(&configXml); - dom.save(stream, 4); - qDebug() << "\tdone."; - } - } - return metapath; + qDebug() << "done.\n"; } static int printErrorAndUsageAndExit(const QString &err) @@ -585,6 +589,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) { @@ -670,6 +675,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 " @@ -694,11 +701,11 @@ int main(int argc, char **argv) } if (onlineOnly) { - filteredPackages.append(QLatin1String("XXXXXXXXXXXXXXXXX_online_XXXXXXXXXXXXXXXXX")); + filteredPackages.append(QLatin1String("X_fake_filter_component_for_online_only_installer_X")); ftype = QInstallerTools::Include; } - if (target.isEmpty()) + if (target.isEmpty() && !compileResource) return printErrorAndUsageAndExit(QString::fromLatin1("Error: Target parameter missing.")); if (configFile.isEmpty()) @@ -706,31 +713,37 @@ int main(int argc, char **argv) qDebug() << "Parsed arguments, ok."; + int exitCode = EXIT_FAILURE; + const QString tmpMetaDir = QInstaller::createTemporaryDirectory(); try { - QInstallerTools::PackageInfoVector packages = createListOfPackages(packagesDirectory, - filteredPackages, ftype); - const QString metaDir = createMetaDataDirectory(packages, packagesDirectory, configFile); + const Settings settings = Settings::fromFileAndPrefix(configFile, QFileInfo(configFile).absolutePath()); + QInstallerTools::PackageInfoVector packages = QInstallerTools::createListOfPackages(packagesDirectory, + &filteredPackages, ftype); + QInstallerTools::copyMetaData(tmpMetaDir, packagesDirectory, packages, settings.applicationName(), + settings.applicationVersion()); + + copyConfigData(configFile, tmpMetaDir + QLatin1String("/installer-config")); { - QSettings confInternal(metaDir + QLatin1String("/config/config-internal.ini") + QSettings confInternal(tmpMetaDir + QLatin1String("/config/config-internal.ini") , QSettings::IniFormat); + // assume offline installer if there are no repositories + offlineOnly |= settings.repositories().isEmpty(); confInternal.setValue(QLatin1String("offlineOnly"), offlineOnly); } #if defined(Q_OS_MAC) // on mac, we enforce building a bundle - if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) { + if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) target += QLatin1String(".app"); - } #endif - int result = EXIT_FAILURE; - { + if (!compileResource) { Input input; input.outputPath = target; input.installerExePath = templateBinary; - input.binaryResourcePath = createBinaryResourceFile(metaDir); + input.binaryResourcePath = createBinaryResourceFile(tmpMetaDir, generateTemporaryFileName()); input.binaryResources = createBinaryResourceFiles(resources); - QInstallerTools::copyComponentData(packagesDirectory, metaDir, packages); + QInstallerTools::copyComponentData(packagesDirectory, tmpMetaDir, &packages); // now put the packages into the components section of the binary foreach (const QInstallerTools::PackageInfo &info, packages) { @@ -738,9 +751,9 @@ int main(int argc, char **argv) comp.setName(info.name.toUtf8()); qDebug() << "Creating component info for" << info.name; - foreach (const QString &archive, info.copiedArchives) { + foreach (const QString &archive, info.copiedFiles) { const QSharedPointer<Archive> arch(new Archive(archive)); - qDebug() << QString::fromLatin1("\tAppending %1 (%2)").arg(archive, + qDebug() << QString::fromLatin1("Appending %1 (%2)").arg(archive, humanReadableSize(arch->size())); comp.appendArchive(arch); } @@ -748,22 +761,23 @@ int main(int argc, char **argv) } qDebug() << "Creating the binary"; - result = assemble(input, configFile); + exitCode = assemble(input, settings); // cleanup qDebug() << "Cleaning up..."; QFile::remove(input.binaryResourcePath); foreach (const QString &resource, input.binaryResources) QFile::remove(resource); + } else { + createBinaryResourceFile(tmpMetaDir, QDir::currentPath() + QLatin1String("/update.rcc")); + exitCode = EXIT_SUCCESS; } - removeDirectory(metaDir, true); - return result; } catch (const Error &e) { - std::cerr << "caught exception: " << e.message() << std::endl; - return EXIT_FAILURE; + std::cerr << "Caught exception: " << e.message() << std::endl; } catch (...) { std::cerr << "Unknown exception caught" << std::endl; - return EXIT_FAILURE; } - return EXIT_FAILURE; + + QInstaller::removeDirectory(tmpMetaDir, true); + return exitCode; } |