diff options
Diffstat (limited to 'tools')
16 files changed, 995 insertions, 919 deletions
diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp index 594686e61..80c083208 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; @@ -154,8 +148,14 @@ 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); @@ -175,7 +175,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; @@ -192,6 +195,8 @@ Q_UNUSED(settings) 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 +223,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 +320,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 +351,7 @@ Q_UNUSED(settings) qDebug() << "done." << mkdmgscript; } #endif - return 0; + return EXIT_SUCCESS; } QT_BEGIN_NAMESPACE @@ -469,90 +478,67 @@ static void printUsage() std::cout << 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 metapath = createTemporaryDirectory(); - generateMetaDataDirectory(metapath, packagesDir, packages, settings.applicationName(), - settings.applicationVersion()); + const QString sourceConfigFile = QFileInfo(configFile).absoluteFilePath(); + const QString targetConfigFile = targetDir + QLatin1String("/config.xml"); + QInstallerTools::copyWithException(sourceConfigFile, targetConfigFile, QLatin1String("configuration")); - const QString configCopy = metapath + QLatin1String("/installer-config"); - QInstaller::mkdir(configCopy); - QString absoluteConfigPath = QFileInfo(configFile).absolutePath(); + QFile configXml(targetConfigFile); + QInstaller::openForRead(&configXml, configXml.fileName()); - 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 + QDomDocument dom; + dom.setContent(&configXml); + configXml.close(); + + // 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) @@ -706,31 +692,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, + const Settings settings = Settings::fromFileAndPrefix(configFile, QFileInfo(configFile).absolutePath()); + QInstallerTools::PackageInfoVector packages = QInstallerTools::createListOfPackages(packagesDirectory, filteredPackages, ftype); - const QString metaDir = createMetaDataDirectory(packages, packagesDirectory, configFile); + 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; { Input input; input.outputPath = target; input.installerExePath = templateBinary; - input.binaryResourcePath = createBinaryResourceFile(metaDir); + input.binaryResourcePath = createBinaryResourceFile(tmpMetaDir); 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) { @@ -740,7 +732,7 @@ int main(int argc, char **argv) qDebug() << "Creating component info for" << info.name; foreach (const QString &archive, info.copiedArchives) { 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,7 +740,7 @@ int main(int argc, char **argv) } qDebug() << "Creating the binary"; - result = assemble(input, configFile); + exitCode = assemble(input, settings); // cleanup qDebug() << "Cleaning up..."; @@ -756,14 +748,12 @@ int main(int argc, char **argv) foreach (const QString &resource, input.binaryResources) QFile::remove(resource); } - 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; } diff --git a/tools/common/repositorygen.cpp b/tools/common/repositorygen.cpp index 1549fb896..4980082b4 100644 --- a/tools/common/repositorygen.cpp +++ b/tools/common/repositorygen.cpp @@ -42,6 +42,7 @@ #include <fileutils.h> #include <errors.h> +#include <globals.h> #include <lib7z_facade.h> #include <settings.h> #include <qinstallerglobal.h> @@ -72,6 +73,33 @@ void QInstallerTools::printRepositoryGenOptions() std::cout << " --ignore-invalid-packages Ignore all invalid packages instead of aborting." << std::endl; } +QString QInstallerTools::makePathAbsolute(const QString &path) +{ + if (QFileInfo(path).isRelative()) + return QDir::current().absoluteFilePath(path); + return path; +} + +void QInstallerTools::copyWithException(const QString &source, const QString &target, const QString &kind) +{ + qDebug() << QString::fromLatin1("Copying associated %1 file '%2'").arg(kind, source); + + const QFileInfo targetFileInfo(target); + if (!targetFileInfo.dir().exists()) + QInstaller::mkpath(targetFileInfo.absolutePath()); + + QFile sourceFile(source); + if (!sourceFile.copy(target)) { + qDebug() << "failed!\n"; + throw QInstaller::Error(QString::fromLatin1("Could not copy the %1 file from\n'%2' to '%3'\nError: " + "'%4'.").arg(kind, source, target, + /* in case of an existing target the error String does not show the file */ + (targetFileInfo.exists() ? QLatin1String("Target already exist.") : sourceFile.errorString()))); + } + + qDebug() << "done.\n"; +} + void QInstallerTools::compressPaths(const QStringList &paths, const QString &archivePath) { QFile archive(archivePath); @@ -79,91 +107,98 @@ void QInstallerTools::compressPaths(const QStringList &paths, const QString &arc Lib7z::createArchive(&archive, paths); } -void QInstallerTools::compressMetaDirectories(const QString &repoDir) +static QStringList copyFilesFromNode(const QString &parentNode, const QString &childNode, const QString &attr, + const QString &kind, const QDomNode &package, const PackageInfo &info, const QString &targetDir) { - QDir dir(repoDir); - const QStringList sub = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString &i, sub) { - QDir sd(dir); - sd.cd(i); - const QString absPath = sd.absolutePath(); - const QString fn = QLatin1String("meta.7z"); - const QString tmpTarget = repoDir + QLatin1String("/") +fn; - compressPaths(QStringList() << absPath, tmpTarget); - QFile tmp(tmpTarget); - const QString finalTarget = absPath + QLatin1String("/") + fn; - if (!tmp.rename(finalTarget)) { - throw QInstaller::Error(QString::fromLatin1("Could not move file from '%1' to '%2'").arg(tmpTarget, - finalTarget)); + QStringList copiedFiles; + const QDomNodeList nodes = package.firstChildElement(parentNode).childNodes(); + for (int i = 0; i < nodes.count(); ++i) { + const QDomNode node = nodes.at(i); + if (node.nodeName() != childNode) + continue; + + const QDir dir(QString::fromLatin1("%1/meta").arg(info.directory)); + const QString filter = attr.isEmpty() ? node.toElement().text() : node.toElement().attribute(attr); + const QStringList files = dir.entryList(QStringList(filter), QDir::Files); + if (files.isEmpty()) { + throw QInstaller::Error(QString::fromLatin1("Couldn't find any %1 matching '%2' " + "while copying %1 of '%3'.").arg(kind, filter, info.name)); + } + + foreach (const QString &file, files) { + const QString source(QString::fromLatin1("%1/meta/%2").arg(info.directory, file)); + const QString target(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, file)); + copyWithException(source, target, kind); + copiedFiles.append(file); } } + return copiedFiles; } -void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QString &dataDir, +void QInstallerTools::copyMetaData(const QString &_targetDir, const QString &metaDataDir, const PackageInfoVector &packages, const QString &appName, const QString &appVersion, const QString &redirectUpdateUrl) { - QString metapath = outDir; - if (QFileInfo(metapath).isRelative()) - metapath = QDir::cleanPath(QDir::current().absoluteFilePath(metapath)); - qDebug() << "Generating meta data..."; - - if (!QFile::exists(metapath)) - QInstaller::mkpath(metapath); + const QString targetDir = makePathAbsolute(_targetDir); + if (!QFile::exists(targetDir)) + QInstaller::mkpath(targetDir); QDomDocument doc; QDomElement root; - // use existing Updates.xml, if any - QFile existingUpdatesXml(QFileInfo(dataDir, QLatin1String("Updates.xml")).absoluteFilePath()); - if (!existingUpdatesXml.open(QIODevice::ReadOnly) || !doc.setContent(&existingUpdatesXml)) { + QFile existingUpdatesXml(QFileInfo(metaDataDir, QLatin1String("Updates.xml")).absoluteFilePath()); + if (existingUpdatesXml.open(QIODevice::ReadOnly) && doc.setContent(&existingUpdatesXml)) { + root = doc.documentElement(); + // remove entry for this component from existing Updates.xml, if found + foreach (const PackageInfo &info, packages) { + const QDomNodeList packageNodes = root.childNodes(); + for (int i = packageNodes.count() - 1; i >= 0; --i) { + const QDomNode node = packageNodes.at(i); + if (node.nodeName() != QLatin1String("PackageUpdate")) + continue; + if (node.firstChildElement(QLatin1String("Name")).text() != info.name) + continue; + root.removeChild(node); + } + } + existingUpdatesXml.close(); + // TODO: maybe we should replace or remove an existing redirect with the one given, if so + } else { root = doc.createElement(QLatin1String("Updates")); - root.appendChild(doc.createElement(QLatin1String("ApplicationName"))).appendChild( - doc.createTextNode(appName)); - root.appendChild(doc.createElement(QLatin1String("ApplicationVersion"))).appendChild( - doc.createTextNode(appVersion)); - root.appendChild(doc.createElement(QLatin1String("Checksum"))).appendChild( - doc.createTextNode(QLatin1String("true"))); + root.appendChild(doc.createElement(QLatin1String("ApplicationName"))).appendChild(doc + .createTextNode(appName)); + root.appendChild(doc.createElement(QLatin1String("ApplicationVersion"))).appendChild(doc + .createTextNode(appVersion)); + root.appendChild(doc.createElement(QLatin1String("Checksum"))).appendChild(doc + .createTextNode(QLatin1String("true"))); if (!redirectUpdateUrl.isEmpty()) { - root.appendChild(doc.createElement(QLatin1String("RedirectUpdateUrl"))).appendChild( - doc.createTextNode(redirectUpdateUrl)); + root.appendChild(doc.createElement(QLatin1String("RedirectUpdateUrl"))).appendChild(doc + .createTextNode(redirectUpdateUrl)); } - } else { - root = doc.documentElement(); } - for (PackageInfoVector::const_iterator it = packages.begin(); it != packages.end(); ++it) { - const QString packageXmlPath = QString::fromLatin1("%1/meta/package.xml").arg(it->directory); - qDebug() << QString::fromLatin1("\tGenerating meta data for package %1 using %2.").arg( - it->name, packageXmlPath); + foreach (const PackageInfo &info, packages) { + if (!QDir(targetDir).mkpath(info.name)) + throw QInstaller::Error(QString::fromLatin1("Could not create directory '%1'.").arg(info.name)); - // remove existing entry for this component from existing Updates.xml - const QDomNodeList packageNodes = root.childNodes(); - for (int i = 0; i < packageNodes.count(); ++i) { - const QDomNode node = packageNodes.at(i); - if (node.nodeName() != QLatin1String("PackageUpdate")) - continue; - if (node.firstChildElement(QLatin1String("Name")).text() != it->name) - continue; - root.removeChild(node); - --i; - } + const QString packageXmlPath = QString::fromLatin1("%1/meta/package.xml").arg(info.directory); + qDebug() << QString::fromLatin1("Copy meta data for package '%1' using '%2'.").arg(info.name, + packageXmlPath); - QDomDocument packageXml; QFile file(packageXmlPath); QInstaller::openForRead(&file, packageXmlPath); + QString errMsg; - int col = 0; int line = 0; - if (!packageXml.setContent(&file, &errMsg, &line, &col)) { + int column = 0; + QDomDocument packageXml; + if (!packageXml.setContent(&file, &errMsg, &line, &column)) { throw QInstaller::Error(QString::fromLatin1("Could not parse '%1': line: %2, column: %3: %4 (%5)") - .arg(packageXmlPath, QString::number(line), QString::number(col), errMsg, it->name)); + .arg(packageXmlPath).arg(line).arg(column).arg(errMsg, info.name)); } - const QDomNode package = packageXml.firstChildElement(QLatin1String("Package")); QDomElement update = doc.createElement(QLatin1String("PackageUpdate")); - QDomElement nameElement = doc.createElement(QLatin1String("Name")); - nameElement.appendChild(doc.createTextNode(it->name)); - update.appendChild(nameElement); + QDomNode nameElement = update.appendChild(doc.createElement(QLatin1String("Name"))); + nameElement.appendChild(doc.createTextNode(info.name)); // list of current unused or later transformed tags QStringList blackList; @@ -173,6 +208,7 @@ void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QSt bool foundDefault = false; bool foundVirtual = false; bool foundDisplayName = false; + const QDomNode package = packageXml.firstChildElement(QLatin1String("Package")); const QDomNodeList childNodes = package.childNodes(); for (int i = 0; i < childNodes.count(); ++i) { const QDomNode node = childNodes.at(i); @@ -187,13 +223,12 @@ void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QSt if (node.isComment() || blackList.contains(key)) continue; // just skip comments and some tags... - const QString value = node.toElement().text(); QDomElement element = doc.createElement(key); - for (int i = 0; i < node.attributes().size(); i++) { - element.setAttribute(node.attributes().item(i).toAttr().name(), - node.attributes().item(i).toAttr().value()); + for (int j = 0; j < node.attributes().size(); ++j) { + element.setAttribute(node.attributes().item(j).toAttr().name(), + node.attributes().item(j).toAttr().value()); } - update.appendChild(element).appendChild(doc.createTextNode(value)); + update.appendChild(element).appendChild(doc.createTextNode(node.toElement().text())); } if (foundDefault && foundVirtual) { @@ -204,8 +239,7 @@ void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QSt if (!foundDisplayName) { qWarning() << "No DisplayName tag found, using component Name instead."; QDomElement displayNameElement = doc.createElement(QLatin1String("DisplayName")); - displayNameElement.appendChild(doc.createTextNode(it->name)); - update.appendChild(displayNameElement); + update.appendChild(displayNameElement).appendChild(doc.createTextNode(info.name)); } // get the size of the data @@ -213,14 +247,11 @@ void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QSt quint64 compressedComponentSize = 0; const QDir::Filters filters = QDir::Files | QDir::NoDotAndDotDot; - const QDir cmpDataDir = QString::fromLatin1("%1/%2/data").arg(dataDir, it->name); - const QFileInfoList entries = cmpDataDir.exists() ? cmpDataDir.entryInfoList(filters | QDir::Dirs) - : QDir(QString::fromLatin1("%1/%2").arg(dataDir, it->name)).entryInfoList(filters); - + const QDir dataDir = QString::fromLatin1("%1/%2/data").arg(metaDataDir, info.name); + const QFileInfoList entries = dataDir.exists() ? dataDir.entryInfoList(filters | QDir::Dirs) + : QDir(QString::fromLatin1("%1/%2").arg(metaDataDir, info.name)).entryInfoList(filters); + qDebug() << QString::fromLatin1("calculate size of directory: %1").arg(dataDir.absolutePath()); foreach (const QFileInfo &fi, entries) { - if (fi.isHidden()) - continue; - try { if (fi.isDir()) { QDirIterator recursDirIt(fi.filePath(), QDirIterator::Subdirectories); @@ -233,18 +264,20 @@ void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QSt // if it's an archive already, list its files and sum the uncompressed sizes QFile archive(fi.filePath()); compressedComponentSize += archive.size(); - archive.open(QIODevice::ReadOnly); - const QVector< Lib7z::File > files = Lib7z::listArchive(&archive); - for (QVector< Lib7z::File >::const_iterator fileIt = files.begin(); - fileIt != files.end(); ++fileIt) { - componentSize += fileIt->uncompressedSize; - } + QInstaller::openForRead(&archive, archive.fileName()); + + QVector<Lib7z::File>::const_iterator fileIt; + const QVector<Lib7z::File> files = Lib7z::listArchive(&archive); + for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) + componentSize += fileIt->uncompressedSize; } else { // otherwise just add its size const quint64 size = fi.size(); componentSize += size; compressedComponentSize += size; } + } catch (const QInstaller::Error &error) { + qDebug() << error.message(); } catch(...) { // ignore, that's just about the sizes - and size doesn't matter, you know? } @@ -259,16 +292,11 @@ void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QSt root.appendChild(update); - if (!QDir(metapath).mkpath(it->name)) - throw QInstaller::Error(QString::fromLatin1("Could not create directory '%1'.").arg(it->name)); - - // copy scripts + // copy script file const QString script = package.firstChildElement(QLatin1String("Script")).text(); if (!script.isEmpty()) { - const QString fromLocation(QString::fromLatin1("%1/meta/%2").arg(it->directory, script)); - QString scriptContent; - QFile scriptFile(fromLocation); + QFile scriptFile(QString::fromLatin1("%1/meta/%2").arg(info.directory, script)); if (scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&scriptFile); scriptContent = in.readAll(); @@ -276,173 +304,75 @@ void QInstallerTools::generateMetaDataDirectory(const QString &outDir, const QSt static QScriptEngine testScriptEngine; testScriptEngine.evaluate(scriptContent, scriptFile.fileName()); if (testScriptEngine.hasUncaughtException()) { - throw QInstaller::Error(QString::fromLatin1("Exception while loading the component script: '%1'") + throw QInstaller::Error(QString::fromLatin1("Exception while loading component script: '%1'") .arg(QInstaller::uncaughtExceptionString(&testScriptEngine, scriptFile.fileName()))); } - // added the xml tag RequiresAdminRights to the xml if somewhere addElevatedOperation is used + // add RequiresAdminRights tag to xml if addElevatedOperation is used somewhere if (scriptContent.contains(QLatin1String("addElevatedOperation"))) { - QDomElement requiresAdminRightsElement = - doc.createElement(QLatin1String("RequiresAdminRights")); - requiresAdminRightsElement.appendChild(doc.createTextNode(QLatin1String("true"))); + QDomElement element = doc.createElement(QLatin1String("RequiresAdminRights")); + element.appendChild(doc.createTextNode(QLatin1String("true"))); } - qDebug() << "\tCopying associated script" << script << "into the meta package..."; - QString toLocation(QString::fromLatin1("%1/%2/%3").arg(metapath, it->name, script)); - if (!scriptFile.copy(toLocation)) { - qDebug() << "failed!"; - throw QInstaller::Error(QString::fromLatin1("Could not copy the script '%1' to its target location '%2'.") - .arg(fromLocation, toLocation)); - } else { - qDebug() << "\tdone."; - } + const QString toLocation(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, script)); + copyWithException(scriptFile.fileName(), toLocation, QLatin1String("script")); } // copy user interfaces - const QDomNodeList uiNodes = package.firstChildElement(QLatin1String("UserInterfaces")).childNodes(); - QStringList userinterfaces; - for (int i = 0; i < uiNodes.count(); ++i) { - const QDomNode node = uiNodes.at(i); - if (node.nodeName() != QLatin1String("UserInterface")) - continue; - - const QDir dir(QString::fromLatin1("%1/meta").arg(it->directory)); - const QStringList uis = dir.entryList(QStringList(node.toElement().text()), QDir::Files); - if (uis.isEmpty()) { - throw QInstaller::Error(QString::fromLatin1("Couldn't find any user interface matching '%1' while " - "copying user interfaces of '%2'.").arg(node.toElement().text(), it->name)); - } - - for (QStringList::const_iterator ui = uis.begin(); ui != uis.end(); ++ui) { - qDebug() << "\tCopying associated user interface" << *ui << "into the meta package..."; - userinterfaces.push_back(*ui); - if (!QFile::copy(QString::fromLatin1("%1/meta/%2").arg(it->directory, *ui), - QString::fromLatin1("%1/%2/%3").arg(metapath, it->name, *ui))) { - qDebug() << "failed!"; - throw QInstaller::Error(QString::fromLatin1("Could not copy the UI file '%1' to its target " - "location '%2'.").arg(*ui, it->name)); - } else { - qDebug() << "done"; - } - } - } - - if (!userinterfaces.isEmpty()) { - update.appendChild(doc.createElement(QLatin1String("UserInterfaces"))) - .appendChild(doc.createTextNode(userinterfaces.join(QChar::fromLatin1(',')))); + const QStringList uiFiles = copyFilesFromNode(QLatin1String("UserInterfaces"), + QLatin1String("UserInterface"), QString(), QLatin1String("user interface"), package, info, + targetDir); + if (!uiFiles.isEmpty()) { + update.appendChild(doc.createElement(QLatin1String("UserInterfaces"))).appendChild(doc + .createTextNode(uiFiles.join(QChar::fromLatin1(',')))); } // copy translations - const QDomNodeList qmNodes = package.firstChildElement(QLatin1String("Translations")).childNodes(); - QStringList translations; + QStringList trFiles; if (!qApp->arguments().contains(QString::fromLatin1("--ignore-translations"))) { - for (int i = 0; i < qmNodes.count(); ++i) { - const QDomNode node = qmNodes.at(i); - if (node.nodeName() != QLatin1String("Translation")) - continue; - - const QDir dir(QString::fromLatin1("%1/meta").arg(it->directory)); - const QStringList qms = dir.entryList(QStringList(node.toElement().text()), QDir::Files); - if (qms.isEmpty()) { - throw QInstaller::Error(QString::fromLatin1("Could not find any translation file matching '%1' " - "while copying translations of '%2'.").arg(node.toElement().text(), it->name)); - } - - for (QStringList::const_iterator qm = qms.begin(); qm != qms.end(); ++qm) { - qDebug() << "\tCopying associated translation" << *qm << "into the meta package..."; - translations.push_back(*qm); - if (!QFile::copy(QString::fromLatin1("%1/meta/%2").arg(it->directory, *qm), - QString::fromLatin1("%1/%2/%3").arg(metapath, it->name, *qm))) { - qDebug() << "failed!"; - throw QInstaller::Error(QString::fromLatin1("Could not copy the translation '%1' to its " - "target location '%2'.").arg(*qm, it->name)); - } else { - qDebug() << "done"; - } - } - } - - if (!translations.isEmpty()) { - update.appendChild(doc.createElement(QLatin1String("Translations"))) - .appendChild(doc.createTextNode(translations.join(QChar::fromLatin1(',')))); + trFiles = copyFilesFromNode(QLatin1String("Translations"), QLatin1String("Translation"), + QString(), QLatin1String("translation"), package, info, targetDir); + if (!trFiles.isEmpty()) { + update.appendChild(doc.createElement(QLatin1String("Translations"))).appendChild(doc + .createTextNode(trFiles.join(QChar::fromLatin1(',')))); } - } // copy license files - const QDomNodeList licenseNodes = package.firstChildElement(QLatin1String("Licenses")).childNodes(); - for (int i = 0; i < licenseNodes.count(); ++i) { - const QDomNode licenseNode = licenseNodes.at(i); - if (licenseNode.nodeName() == QLatin1String("License")) { - const QString &licenseFile = - licenseNode.toElement().attributeNode(QLatin1String("file")).value(); - const QString &sourceFile = - QString::fromLatin1("%1/meta/%2").arg(it->directory).arg(licenseFile); - if (!QFile::exists(sourceFile)) { - throw QInstaller::Error(QString::fromLatin1("Could not find any license matching '%1' while " - "copying license files of '%2'.").arg(licenseFile, it->name)); - } - - qDebug() << "\tCopying associated license file" << licenseFile << "into the meta package..."; - if (!QFile::copy(sourceFile, QString::fromLatin1("%1/%2/%3") - .arg(metapath, it->name, licenseFile))) { - qDebug() << "failed!"; - throw QInstaller::Error(QString::fromLatin1("Could not copy the license file '%1' to its " - "target location '%2'.").arg(licenseFile, it->name)); - } else { - qDebug() << "done."; - } - - // Translated License files - for (int j = 0; j < translations.size(); ++j) { - QFileInfo translationFile(translations.at(j)); - QFileInfo untranslated(licenseFile); - const QString &translatedLicenseFile = - QString::fromLatin1("%2_%3.%4").arg(untranslated.baseName(), - translationFile.baseName(), untranslated.completeSuffix()); - const QString &translatedSourceFile = - QString::fromLatin1("%1/meta/%2").arg(it->directory).arg(translatedLicenseFile); - if (!QFile::exists(translatedSourceFile)) { - qDebug() << "Could not find translated license file" << translatedSourceFile; - continue; - } - - qDebug() << "\tCopying associated license file" << translatedLicenseFile - << "into the meta package..."; - - if (!QFile::copy(translatedSourceFile, QString::fromLatin1("%1/%2/%3") - .arg(metapath, it->name, translatedLicenseFile))) { - qDebug() << "\tfailed!"; - } else { - qDebug() << "\tdone."; - } + const QStringList licenses = copyFilesFromNode(QLatin1String("Licenses"), QLatin1String("License"), + QLatin1String("file"), QLatin1String("license"), package, info, targetDir); + if (!licenses.isEmpty()) { + foreach (const QString &trFile, trFiles) { + // Copy translated license file based on the assumption that it will have the same base name + // as the original license plus the file name of an existing translation file without suffix. + foreach (const QString &license, licenses) { + const QFileInfo untranslated(license); + const QString translatedLicense = QString::fromLatin1("%2_%3.%4").arg(untranslated + .baseName(), QFileInfo(trFile).baseName(), untranslated.completeSuffix()); + // ignore copy failure, that's just about the translations + QFile::copy(QString::fromLatin1("%1/meta/%2").arg(info.directory).arg(translatedLicense), + QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, translatedLicense)); } } - } - - if (licenseNodes.count() > 0) update.appendChild(package.firstChildElement(QLatin1String("Licenses")).cloneNode()); + } } - doc.appendChild(root); - const QString updatesXmlFile = QFileInfo(metapath, QLatin1String("Updates.xml")).absoluteFilePath(); - QFile updatesXml(updatesXmlFile); - - QInstaller::openForWrite(&updatesXml, updatesXmlFile); - QInstaller::blockingWrite(&updatesXml, doc.toByteArray()); + QFile targetUpdatesXml(targetDir + QLatin1String("/Updates.xml")); + QInstaller::openForWrite(&targetUpdatesXml, targetUpdatesXml.fileName()); + QInstaller::blockingWrite(&targetUpdatesXml, doc.toByteArray()); } PackageInfoVector QInstallerTools::createListOfPackages(const QString &packagesDirectory, const QStringList &filteredPackages, FilterType filterType) { - qDebug() << "Collecting information about available packages..."; + qDebug() << "\nCollecting information about available packages..."; bool ignoreInvalidPackages = qApp->arguments().contains(QString::fromLatin1("--ignore-invalid-packages")); PackageInfoVector dict; - const QFileInfoList entries = QDir(packagesDirectory) - .entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + const QFileInfoList entries = QDir(packagesDirectory).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (QFileInfoList::const_iterator it = entries.begin(); it != entries.end(); ++it) { if (filterType == Exclude) { if (filteredPackages.contains(it->fileName())) @@ -451,14 +381,14 @@ PackageInfoVector QInstallerTools::createListOfPackages(const QString &packagesD if (!filteredPackages.contains(it->fileName())) continue; } - qDebug() << QString::fromLatin1("\tfound subdirectory '%1'").arg(it->fileName()); + qDebug() << QString::fromLatin1("found subdirectory '%1'").arg(it->fileName()); // because the filter is QDir::Dirs - filename means the name of the subdirectory if (it->fileName().contains(QLatin1Char('-'))) { if (ignoreInvalidPackages) continue; - throw QInstaller::Error(QString::fromLatin1("Component '%1' mustn't contain '-'. This is not allowed, because " - "dashes are used as the separator between the component name and the version number internally.") - .arg(it->fileName())); + throw QInstaller::Error(QString::fromLatin1("Component '%1' mustn't contain '-'. This is not " + "allowed, because dashes are used as the separator between the component name and the " + "version number internally.").arg(it->fileName())); } QFile file(QString::fromLatin1("%1/meta/package.xml").arg(it->filePath())); @@ -509,11 +439,11 @@ PackageInfoVector QInstallerTools::createListOfPackages(const QString &packagesD .arg(fileInfo.absoluteFilePath(), info.version)); } info.dependencies = packageElement.firstChildElement(QLatin1String("Dependencies")).text() - .split(QInstaller::scCommaRegExp, QString::SkipEmptyParts); + .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); info.directory = it->filePath(); dict.push_back(info); - qDebug() << QString::fromLatin1("\t- it provides the package %1 - %2").arg(name, info.version); + qDebug() << QString::fromLatin1("- it provides the package %1 - %2").arg(info.name, info.version); } if (dict.isEmpty()) @@ -582,8 +512,10 @@ void QInstallerTools::compressMetaDirectories(const QString &repoDir, const QStr const QByteArray sha1Sum = QInstaller::calculateHash(&tmp, QCryptographicHash::Sha1); writeSHA1ToNodeWithName(doc, elements, sha1Sum, path); const QString finalTarget = absPath + QLatin1String("/") + fn; - if (!tmp.rename(finalTarget)) - throw QInstaller::Error(QString::fromLatin1("Could not move '%1' to '%2'").arg(tmpTarget, finalTarget)); + if (!tmp.rename(finalTarget)) { + throw QInstaller::Error(QString::fromLatin1("Could not move '%1' to '%2'").arg(tmpTarget, + finalTarget)); + } } QInstaller::openForWrite(&existingUpdatesXml, existingUpdatesXml.fileName()); @@ -592,10 +524,10 @@ void QInstallerTools::compressMetaDirectories(const QString &repoDir, const QStr } void QInstallerTools::copyComponentData(const QString &packageDir, const QString &repoDir, - PackageInfoVector &infos) + PackageInfoVector *const infos) { - for (int i = 0; i < infos.count(); ++i) { - const PackageInfo info = infos.at(i); + for (int i = 0; i < infos->count(); ++i) { + const PackageInfo info = infos->at(i); const QString name = info.name; qDebug() << "Copying component data for" << name; @@ -618,8 +550,8 @@ void QInstallerTools::copyComponentData(const QString &packageDir, const QString qDebug() << QString::fromLatin1("Copying archive from '%1' to '%2'").arg(tmp.fileName(), target); if (!tmp.copy(target)) { - throw QInstaller::Error(QString::fromLatin1("Could not copy '%1' to '%2': %3").arg(tmp.fileName(), - target, tmp.errorString())); + throw QInstaller::Error(QString::fromLatin1("Could not copy '%1' to '%2': %3") + .arg(tmp.fileName(), target, tmp.errorString())); } compressedFiles.append(target); } else { @@ -644,7 +576,7 @@ void QInstallerTools::copyComponentData(const QString &packageDir, const QString } foreach (const QString &target, compressedFiles) { - infos[i].copiedArchives.append(target); + (*infos)[i].copiedArchives.append(target); QFile archiveFile(target); QFile archiveHashFile(archiveFile.fileName() + QLatin1String(".sha1")); @@ -661,7 +593,7 @@ void QInstallerTools::copyComponentData(const QString &packageDir, const QString QInstaller::openForWrite(&archiveHashFile, archiveHashFile.fileName()); archiveHashFile.write(hashOfArchiveData); qDebug() << "Generated sha1 hash:" << hashOfArchiveData; - infos[i].copiedArchives.append(archiveHashFile.fileName()); + (*infos)[i].copiedArchives.append(archiveHashFile.fileName()); archiveHashFile.close(); } catch (const QInstaller::Error &/*e*/) { archiveFile.close(); diff --git a/tools/common/repositorygen.h b/tools/common/repositorygen.h index 50349c8b6..49a81eb1d 100644 --- a/tools/common/repositorygen.h +++ b/tools/common/repositorygen.h @@ -48,7 +48,6 @@ namespace QInstallerTools { -void printRepositoryGenOptions(); struct PackageInfo { @@ -65,21 +64,22 @@ enum FilterType { Exclude }; +void printRepositoryGenOptions(); +QString makePathAbsolute(const QString &path); +void copyWithException(const QString &source, const QString &target, const QString &kind = QString()); + +PackageInfoVector createListOfPackages(const QString &packagesDirectory, const QStringList &filteredPackages, + FilterType ftype); QHash<QString, QString> buildPathToVersionMapping(const PackageInfoVector &info); -void compressMetaDirectories(const QString &repoDir); void compressPaths(const QStringList &paths, const QString &archivePath); void compressMetaDirectories(const QString &repoDir, const QString &baseDir, const QHash<QString, QString> &versionMapping); -void copyComponentData(const QString &packageDir, const QString &repoDir, PackageInfoVector &infos); - -void generateMetaDataDirectory(const QString &outDir, const QString &dataDir, - const PackageInfoVector &packages, const QString &appName, - const QString& appVersion, const QString &redirectUpdateUrl = QString()); +void copyMetaData(const QString &outDir, const QString &dataDir, const PackageInfoVector &packages, + const QString &appName, const QString& appVersion, const QString &redirectUpdateUrl = QString()); +void copyComponentData(const QString &packageDir, const QString &repoDir, PackageInfoVector *const infos); -PackageInfoVector createListOfPackages(const QString &packagesDirectory, const QStringList &filteredPackages, - FilterType ftype); } // namespace QInstallerTools diff --git a/tools/getrepositorycontent/domnodedebugstreamoperator.cpp b/tools/getrepositorycontent/domnodedebugstreamoperator.cpp new file mode 100644 index 000000000..511b4a224 --- /dev/null +++ b/tools/getrepositorycontent/domnodedebugstreamoperator.cpp @@ -0,0 +1,53 @@ +/************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#include "domnodedebugstreamoperator.h" + +QDebug operator<<(QDebug dbg, const QDomNode &domNode) +{ + if (domNode.isNull()) + return dbg << "domNode is Null"; + QString debugOutput; + QTextStream stream(&debugOutput); + domNode.save(stream, 4); + + return dbg << debugOutput; +} diff --git a/tools/getrepositorycontent/domnodedebugstreamoperator.h b/tools/getrepositorycontent/domnodedebugstreamoperator.h new file mode 100644 index 000000000..f48918f77 --- /dev/null +++ b/tools/getrepositorycontent/domnodedebugstreamoperator.h @@ -0,0 +1,51 @@ +/************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#ifndef DEBUGDOMNODE_H +#define DEBUGDOMNODE_H + +#include <QDebug> +#include <QDomNode> + +QDebug operator<<(QDebug dbg, const QDomNode &domNode); + + +#endif // DEBUGDOMNODE_H diff --git a/tools/getrepositorycontent/downloader.cpp b/tools/getrepositorycontent/downloader.cpp new file mode 100644 index 000000000..0eb19139a --- /dev/null +++ b/tools/getrepositorycontent/downloader.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "downloader.h" + +#include <fileutils.h> + +#include <QtNetwork/QNetworkProxy> + +class ProxyFactory : public KDUpdater::FileDownloaderProxyFactory +{ +public: + ProxyFactory() {} + + ProxyFactory *clone() const + { + return new ProxyFactory(); + } + + QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()) + { + return QNetworkProxyFactory::systemProxyForQuery(query); + } +}; + +Downloader::Downloader(const QUrl &source, const QString &target) + : QObject() + , m_source(source) + , m_target(target) + , m_fileDownloader(0) +{ + m_fileDownloader = KDUpdater::FileDownloaderFactory::instance().create(m_source.scheme(), this); + m_fileDownloader->setDownloadedFileName(target); + + if (m_fileDownloader) { + m_fileDownloader->setUrl(m_source); + m_fileDownloader->setProxyFactory(new ProxyFactory()); + + connect(m_fileDownloader, SIGNAL(downloadCanceled()), this, SLOT(downloadFinished())); + connect(m_fileDownloader, SIGNAL(downloadCompleted()), this, SLOT(downloadFinished())); + connect(m_fileDownloader, SIGNAL(downloadAborted(QString)), this, SLOT(downloadFinished(QString))); + + connect(m_fileDownloader, SIGNAL(downloadSpeed(qint64)), this, SLOT(downloadSpeed(qint64))); + connect(m_fileDownloader, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64))); + + m_fileDownloader->setAutoRemoveDownloadedFile(false); + } + +} + +void Downloader::downloadFinished(const QString &message) +{ + if (!message.isEmpty()) + qDebug() << "Error:" << message; + progressBar.setStatus(100, 100); + progressBar.update(); + printf("\n"); + emit finished(); +} + +void Downloader::downloadSpeed(qint64 speed) +{ + progressBar.setMessage(QString::fromLatin1("%1 /sec").arg(QInstaller::humanReadableSize(speed))); +} + +void Downloader::downloadProgress(qint64 bytesReceived, qint64 bytesToReceive) +{ + if (bytesReceived == 0 || bytesToReceive == 0) + return; + progressBar.setStatus(bytesReceived, bytesToReceive); + progressBar.update(); +} + +void Downloader::run() +{ + m_fileDownloader->download(); +} diff --git a/tools/repogenfromonlinerepo/downloadmanager.h b/tools/getrepositorycontent/downloader.h index 13cce7163..bb4631bb9 100644 --- a/tools/repogenfromonlinerepo/downloadmanager.h +++ b/tools/getrepositorycontent/downloader.h @@ -38,8 +38,13 @@ ** ****************************************************************************/ -#ifndef DOWNLOADMANAGER_H -#define DOWNLOADMANAGER_H +#ifndef DOWNLOADER_H +#define DOWNLOADER_H + +#include "textprogressbar.h" + +#include <kdupdaterfiledownloader.h> +#include <kdupdaterfiledownloaderfactory.h> #include <QFile> #include <QObject> @@ -48,37 +53,24 @@ #include <QUrl> #include <QNetworkAccessManager> -#include "textprogressbar.h" - -class DownloadManager: public QObject +class Downloader : public QObject { Q_OBJECT public: - DownloadManager(QObject *parent = 0); - - void append(const QUrl &url); - void append(const QStringList &urlList); - QString saveFileName(const QUrl &url); - + explicit Downloader(const QUrl &source, const QString &target); + void run(); signals: void finished(); - private slots: - void startNextDownload(); - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void downloadFinished(); - void downloadReadyRead(); + void downloadFinished(const QString &message = QString()); + void downloadSpeed(qint64 speed); + void downloadProgress(qint64 bytesReceived, qint64 bytesToReceive); private: - QNetworkAccessManager manager; - QQueue<QUrl> downloadQueue; - QNetworkReply *currentDownload; - QFile output; - QTime downloadTime; TextProgressBar progressBar; - - int downloadedCount; - int totalCount; + QUrl m_source; + QString m_target; + KDUpdater::FileDownloader *m_fileDownloader; }; -#endif +#endif // DOWNLOADER_H diff --git a/tools/getrepositorycontent/getrepositorycontent.pro b/tools/getrepositorycontent/getrepositorycontent.pro new file mode 100644 index 000000000..d3412c63a --- /dev/null +++ b/tools/getrepositorycontent/getrepositorycontent.pro @@ -0,0 +1,22 @@ +TEMPLATE = app +INCLUDEPATH += . .. +TARGET = getrepositorycontent + +include(../../installerfw.pri) + +QT -= gui +QT += network + +CONFIG += console +DESTDIR = $$IFW_APP_PATH + +SOURCES += main.cpp \ + textprogressbar.cpp \ + downloader.cpp \ + domnodedebugstreamoperator.cpp + +HEADERS += \ + textprogressbar.h \ + downloader.h \ + domnodedebugstreamoperator.h + diff --git a/tools/getrepositorycontent/main.cpp b/tools/getrepositorycontent/main.cpp new file mode 100644 index 000000000..66a2ec43f --- /dev/null +++ b/tools/getrepositorycontent/main.cpp @@ -0,0 +1,450 @@ +/************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#include "downloader.h" +#include "domnodedebugstreamoperator.h" + +#include <globals.h> +#include <init.h> +#include <fileutils.h> +#include <lib7z_facade.h> +#include <utils.h> + +#include <QCoreApplication> +#include <QFile> +#include <QUrl> +#include <QString> +#include <QDomDocument> +#include <QDomElement> +#include <QDomNodeList> +#include <QStringList> +#include <QDebug> +#include <QFileInfo> +#include <QDir> +#include <QDirIterator> +#include <QDebug> + +#include <iostream> + +static void printUsage() +{ + const QString appName = QFileInfo( QCoreApplication::applicationFilePath() ).fileName(); + std::cout << "Usage: " << qPrintable(appName) + << " --url <repository_url> --repository <empty_repository_dir> --packages <empty_packages_dir>" << std::endl; + std::cout << " --url URL to fetch all the content from." << std::endl; + std::cout << " --repository Target directory for the repository content." << std::endl; + std::cout << " --packages The packages target directory where it creates the needed content to create new installers or repositories." << std::endl; + std::cout << " --clean Removes all the content if there is an existing repository or packages dir" << std::endl; + + std::cout << "Example:" << std::endl; + std::cout << " " << qPrintable(appName) << " --url http://www.example.com/repository/" << + " --repository repository --packages packages" << std::endl; +} + +// this should be a new class which uses XmlStreamReader instead of DomDocument +// should be implicit shared, see repository class +// maybe we can use some code from persistentdata in qtcreator +class ComponentData { + public: + ComponentData() {} + ComponentData(const QString &/*xmlData*/) {} + + QVariant attributeValue(const QString &key, const QString &attribute, const QVariant &defaultValue = QVariant()) { + Q_UNUSED(key) + Q_UNUSED(attribute) + return defaultValue; + } + + QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) { + Q_UNUSED(defaultValue) + // just use the quick dirty hack added members + if (key == QLatin1String("Script")) + return m_script; + if (key == QLatin1String("Version")) + return m_version; + return QVariant(); + } + QString textValue(const QString &key, const QString &defaultValue = QString()) { + return value(key, defaultValue).toString(); + } + + // quick dirty hack added public members + public: + QDomDocument m_packageXml; + QStringList m_downloadDownloadableArchives; + QString m_script; + QString m_version; +}; + +static void downloadFile(const QUrl &source, const QString &target) +{ + QEventLoop downloadEventLoop; + Downloader downloader(source, target); + QObject::connect(&downloader, SIGNAL(finished()), &downloadEventLoop, SLOT(quit())); + downloader.run(); + downloadEventLoop.exec(); +} + +QHash<QString, ComponentData> downLoadRepository(const QString &repositoryUrl, const QString &repositoryTarget) +{ + const QString updatesXmlFileName = QLatin1String("Updates.xml"); + QHash<QString, ComponentData> componentDataHash; + + const QUrl updatesXmlUrl(QString::fromLatin1("%1/%2").arg(repositoryUrl, updatesXmlFileName)); + + downloadFile(updatesXmlUrl, QDir(repositoryTarget).filePath(updatesXmlFileName)); + + QFile updatesFile(QDir(repositoryTarget).filePath(updatesXmlFileName)); + if (!updatesFile.exists()) { + qDebug() << "could not download the file:" << updatesXmlUrl.toString(); + return componentDataHash; + } else + qDebug() << "file downloaded to location:" << QDir(repositoryTarget).filePath(updatesXmlFileName); + if (!updatesFile.open(QIODevice::ReadOnly)) { + qDebug() << QString::fromLatin1("Could not open Updates.xml for reading: %1").arg(updatesFile + .errorString()) ; + return componentDataHash; + } + + QStringList ignoreTagList; + ignoreTagList << QLatin1String("Name"); + ignoreTagList << QLatin1String("ReleaseDate"); + ignoreTagList << QLatin1String("SHA1"); + ignoreTagList << QLatin1String("UpdateFile"); + QStringList fileTagList; + fileTagList << QLatin1String("DownloadableArchives"); + + + QDomDocument updatesXml; + QString error; + int line = 0; + int column = 0; + if (!updatesXml.setContent( &updatesFile, &error, &line, &column)) { + qWarning() << QString::fromLatin1("Could not parse component index: %1:%2: %3") + .arg(QString::number(line), QString::number(column), error); + return componentDataHash; + } + + QDomNode packageUpdateDomNode = updatesXml.firstChildElement(QLatin1String("Updates")).firstChildElement( + QLatin1String("PackageUpdate")); + while (!packageUpdateDomNode.isNull()) { + + if (packageUpdateDomNode.nodeName() == QLatin1String("PackageUpdate")) { + QDomNode packageUpdateEntry = packageUpdateDomNode.firstChild(); + QString currentPackageName; + ComponentData currentComponentData; + // creating the package.xml for later use + QDomElement currentNewPackageElement = currentComponentData.m_packageXml.createElement( + QLatin1String("Package")); + while (!packageUpdateEntry.isNull()) { + // do name first before ignore filters the name out + if (packageUpdateEntry.nodeName() == QLatin1String("Name")) { + currentPackageName = packageUpdateEntry.toElement().text(); + } + if (ignoreTagList.contains(packageUpdateEntry.nodeName())) { + packageUpdateEntry = packageUpdateEntry.nextSibling(); + continue; + } + if (packageUpdateEntry.nodeName() == QLatin1String("Script")) { + currentComponentData.m_script = packageUpdateEntry.toElement().text(); + } + if (packageUpdateEntry.nodeName() == QLatin1String("Version")) { + currentComponentData.m_version = packageUpdateEntry.toElement().text(); + currentComponentData.m_downloadDownloadableArchives.append( + currentComponentData.m_version + QLatin1String("meta.7z")); + } + + if (packageUpdateEntry.nodeName() == QLatin1String("DownloadableArchives")) { + QStringList tDownloadList = packageUpdateEntry.toElement().text().split( + QInstaller::commaRegExp(), QString::SkipEmptyParts); + foreach (const QString &download, tDownloadList) { + currentComponentData.m_downloadDownloadableArchives.append( + currentComponentData.m_version + download); + currentComponentData.m_downloadDownloadableArchives.append( + currentComponentData.m_version + download + QLatin1String(".sha1")); + } + } + + currentNewPackageElement.appendChild(packageUpdateEntry.cloneNode(true)); + packageUpdateEntry = packageUpdateEntry.nextSibling(); + } + currentComponentData.m_packageXml.appendChild(currentNewPackageElement); + Q_ASSERT(!currentComponentData.m_packageXml.toString().isEmpty()); + componentDataHash.insert(currentPackageName, currentComponentData); + } else { + qWarning() << QString::fromLatin1("Unknown elment '%1'").arg(packageUpdateDomNode.nodeName(), + QFileInfo(updatesXmlFileName).absoluteFilePath()); + } + packageUpdateDomNode = packageUpdateDomNode.nextSibling(); + } + + QHashIterator<QString, ComponentData> itComponentData(componentDataHash); + while (itComponentData.hasNext()) { + itComponentData.next(); + QString componentDirectory = QDir(repositoryTarget).filePath(itComponentData.key()); + if (!QDir().mkpath(componentDirectory)) + qWarning() << "couldn't create:" << componentDirectory; + + foreach (const QString &download, itComponentData.value().m_downloadDownloadableArchives) { + const QString fileTarget(componentDirectory + QDir::separator() + download); + const QUrl downloadUrl(repositoryUrl + QLatin1String("/") + itComponentData.key() + QLatin1String("/") + download); + downloadFile(downloadUrl, fileTarget); + } + } + return componentDataHash; +} + +bool extractFile(const QString &source, const QString &target) +{ + if (!Lib7z::isSupportedArchive(source)) { + qWarning() << source << "is not a supported archive"; + } + + QFile archive(source); + if (archive.open(QIODevice::ReadOnly)) { + try { + Lib7z::extractArchive(&archive, target); + } catch (const Lib7z::SevenZipException& e) { + qWarning() << QString::fromLatin1("Error while extracting %1: %2.").arg(source, e.message()); + return false; + } catch (...) { + qWarning() << QString::fromLatin1("Unknown exception caught while extracting %1.").arg(source); + return false; + } + } else { + qWarning() << QString::fromLatin1("Could not open %1 for reading: %2.").arg( + target, archive.errorString()); + return false; + } + return true; +} + + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + // init installer to have the 7z lib initialized + QInstaller::init(); + // with the installer messagehandler we need to enable verbose to see QDebugs + QInstaller::setVerbose(true); + + QString repositoryUrl; + QString repositoryTarget; + QString packageDirectoryTarget; + bool clean = false; + QStringList args = app.arguments(); + QStringList::const_iterator itArgument = args.constBegin(); + itArgument++; // ignore the first one + if (itArgument == args.constEnd()) { + printUsage(); + return 0; + } + + for (; itArgument != args.constEnd(); ++itArgument) { + if (*itArgument == QString::fromLatin1("-h") || *itArgument == QString::fromLatin1("--help")) { + printUsage(); + return 0; + } else if (*itArgument == QString::fromLatin1("--clean")) { + clean = true; + } else if (*itArgument == QString::fromLatin1("-u") || *itArgument == QString::fromLatin1("--url")) { + ++itArgument; + if (itArgument == args.end()) { + printUsage(); + return -1; + } else { + repositoryUrl = *itArgument; + } + } else if (*itArgument == QString::fromLatin1("-r") || *itArgument == QString::fromLatin1("--repository")) { + ++itArgument; + if (itArgument == args.end()) { + printUsage(); + return -1; + } else { + repositoryTarget = *itArgument; + } + } else if (*itArgument == QString::fromLatin1("-p") || *itArgument == QString::fromLatin1("--packages")) { + ++itArgument; + if (itArgument == args.end()) { + printUsage(); + return -1; + } else { + packageDirectoryTarget = *itArgument; + } + } else { + qWarning() << QString::fromLatin1("Argument '%1' is unknown").arg(*itArgument); + printUsage(); + return 0; + } + } + if (repositoryTarget.isEmpty() || packageDirectoryTarget.isEmpty()) { + printUsage(); + return 0; + } else { + // resolve pathes + repositoryTarget = QFileInfo(repositoryTarget).absoluteFilePath(); + packageDirectoryTarget = QFileInfo(packageDirectoryTarget).absoluteFilePath(); + } + + foreach (const QString &target, QStringList() << repositoryTarget << packageDirectoryTarget) { + if (QFileInfo(target).exists()) { + if (clean) { + qDebug() << "removing directory:" << target; + QInstaller::removeDirectory(target, true); + } else if (!QDir(target).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()){ + qWarning() << QString::fromLatin1("The directory '%1' needs to be empty or just " + "add the --clean argument.").arg(target); + return EXIT_FAILURE; + } + } + + while (!QDir().mkpath(target)) { + qWarning() << QString::fromLatin1("Could not create %1").arg(target); + } + } + + QHash<QString, ComponentData> componentDataHash; + componentDataHash = downLoadRepository(repositoryUrl, repositoryTarget); + + // maybe in that case we should download the meta data to temp and + // get the downdloadable archives information from there later + if (packageDirectoryTarget.isEmpty()) + return EXIT_SUCCESS; + + QDirIterator itRepositoryFile(repositoryTarget, QDir::Files, QDirIterator::Subdirectories); + while (itRepositoryFile.hasNext()) { + QString currentFile = itRepositoryFile.next(); + + QString componentSubdirectoryName = itRepositoryFile.filePath(); + + QString normalizedRepositoryTarget = repositoryTarget; + normalizedRepositoryTarget.replace(QLatin1Char('\\'), QLatin1Char('/')); + + componentSubdirectoryName.remove(repositoryTarget); + componentSubdirectoryName.remove(normalizedRepositoryTarget); + + QString componentPackageDir = QFileInfo(packageDirectoryTarget + QDir::separator() + componentSubdirectoryName).absolutePath(); + QString absoluteSourceFilePath = itRepositoryFile.filePath(); + + if (currentFile.endsWith(QLatin1String("meta.7z"))) { + QString absolutTargetPath = QFileInfo( + packageDirectoryTarget + QDir::separator()).absolutePath(); + + extractFile(absoluteSourceFilePath, absolutTargetPath); + QInstaller::moveDirectoryContents(componentPackageDir, + componentPackageDir + QDir::separator() + QLatin1String("meta")); + } else if (!currentFile.endsWith(QLatin1String("Updates.xml")) && !currentFile.endsWith(QLatin1String(".sha1"))){ + QString pathToTarget = componentPackageDir + QDir::separator() + QLatin1String("data"); + QString target = QDir(pathToTarget).absoluteFilePath(itRepositoryFile.fileName()); + QDir().mkpath(pathToTarget); + QFile file; + if (!file.copy(absoluteSourceFilePath, target)) { + qWarning() << QString::fromLatin1("copy file %1 to %2 wasn't working %3").arg( + absoluteSourceFilePath, target, file.errorString()); + } + } + } + + + QHashIterator<QString, ComponentData> itComponentData(componentDataHash); + while (itComponentData.hasNext()) { + itComponentData.next(); + if (itComponentData.value().m_script.isEmpty()) + continue; + + QString componentScript = QFileInfo(QString::fromLatin1("%1/%2/meta/%3").arg( + packageDirectoryTarget, itComponentData.key(), itComponentData.value().m_script)).absoluteFilePath(); + + QString packagesXml = QFileInfo(QString::fromLatin1("%1/%2/meta/packages.xml").arg( + packageDirectoryTarget, itComponentData.key())).absoluteFilePath(); + + QFile packagesXmlFile(packagesXml); + + if (!packagesXmlFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning() << QString::fromLatin1("Failed to open '%1' for writing. %2").arg( + packagesXml, packagesXmlFile.errorString()); + return EXIT_FAILURE; + } + + if (itComponentData.value().m_packageXml.toString().isEmpty()) { + qWarning() << "No xml data found in component:" << itComponentData.key(); + return EXIT_FAILURE; + } + + QTextStream stream(&packagesXmlFile); + stream << itComponentData.value().m_packageXml.toString(4); + packagesXmlFile.close(); + + QString dataPackagesPath = QFileInfo(QString::fromLatin1("%1/%2/data").arg( + packageDirectoryTarget, itComponentData.key())).absoluteFilePath(); + QDir().mkpath(dataPackagesPath); + + QString dataRepositoryPath = QFileInfo(repositoryTarget + QDir::separator() + itComponentData.key()).absoluteFilePath(); + QDir().mkpath(dataRepositoryPath); + + QFile componentScriptFile(componentScript); + if (!componentScriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << QString::fromLatin1("Can not read %1 %2").arg(componentScript, componentScriptFile.errorString()); + continue; + } + + QString sevenZString; + QTextStream in(&componentScriptFile); + in.setCodec("UTF-8"); + while (!in.atEnd()) { + QString line = in.readLine(); + if (line.contains(QLatin1String(".7z"))) { + int firstPosition = line.indexOf(QLatin1String("\"")); + QString subString = line.right(line.count() - firstPosition - 1); //-1 means " + //qDebug() << subString; + int secondPosition = subString.indexOf(QLatin1String("\"")); + sevenZString = subString.left(secondPosition); + QUrl downloadUrl((QStringList() << repositoryUrl << itComponentData.key() << itComponentData.value().m_version + sevenZString).join(QLatin1String("/"))); + QString localRepositoryTarget = dataRepositoryPath + QLatin1Char('/') + itComponentData.value().m_version + sevenZString; + downloadFile(downloadUrl, localRepositoryTarget); + downloadFile(downloadUrl.toString() + QLatin1String(".sha1"), localRepositoryTarget + QLatin1String(".sha1")); + QFile::copy(localRepositoryTarget, dataPackagesPath + QLatin1Char('/') + sevenZString); + } + } + } + + return 0; +} diff --git a/tools/repogenfromonlinerepo/textprogressbar.cpp b/tools/getrepositorycontent/textprogressbar.cpp index 14faefd5e..14faefd5e 100644 --- a/tools/repogenfromonlinerepo/textprogressbar.cpp +++ b/tools/getrepositorycontent/textprogressbar.cpp diff --git a/tools/repogenfromonlinerepo/textprogressbar.h b/tools/getrepositorycontent/textprogressbar.h index 6f01f0c84..6f01f0c84 100644 --- a/tools/repogenfromonlinerepo/textprogressbar.h +++ b/tools/getrepositorycontent/textprogressbar.h diff --git a/tools/repogen/repogen.cpp b/tools/repogen/repogen.cpp index 1380e4ebf..84a7d918e 100644 --- a/tools/repogen/repogen.cpp +++ b/tools/repogen/repogen.cpp @@ -90,16 +90,10 @@ static int printErrorAndUsageAndExit(const QString &err) return 1; } -static QString makeAbsolute(const QString &path) -{ - QFileInfo fi(path); - if (fi.isAbsolute()) - return path; - return QDir::current().absoluteFilePath(path); -} - int main(int argc, char** argv) { + QString tmpMetaDir; + int exitCode = EXIT_FAILURE; try { QCoreApplication app(argc, argv); @@ -188,7 +182,7 @@ int main(int argc, char** argv) "exclusive!")); } - const QString repositoryDir = makeAbsolute(args.first()); + const QString repositoryDir = QInstallerTools::makePathAbsolute(args.first()); if (remove) QInstaller::removeDirectory(repositoryDir); @@ -199,7 +193,7 @@ int main(int argc, char** argv) QInstallerTools::PackageInfoVector packages = QInstallerTools::createListOfPackages(packagesDir, filteredPackages, filterType); - QHash<QString, QString> pathToVersionMapping = buildPathToVersionMapping(packages); + QHash<QString, QString> pathToVersionMapping = QInstallerTools::buildPathToVersionMapping(packages); foreach (const QInstallerTools::PackageInfo &package, packages) { const QFileInfo fi(repositoryDir, package.name); @@ -207,27 +201,27 @@ int main(int argc, char** argv) removeDirectory(fi.absoluteFilePath()); } - copyComponentData(packagesDir, repositoryDir, packages); - - TempDirDeleter tmpDeleter; - const QString metaTmp = createTemporaryDirectory(); - tmpDeleter.add(metaTmp); - - generateMetaDataDirectory(metaTmp, repositoryDir, packages, QLatin1String("{AnyApplication}"), + tmpMetaDir = QInstaller::createTemporaryDirectory(); + QInstallerTools::copyComponentData(packagesDir, repositoryDir, &packages); + QInstallerTools::copyMetaData(tmpMetaDir, repositoryDir, packages, QLatin1String("{AnyApplication}"), QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION)), redirectUpdateUrl); - QInstallerTools::compressMetaDirectories(metaTmp, metaTmp, pathToVersionMapping); + QInstallerTools::compressMetaDirectories(tmpMetaDir, tmpMetaDir, pathToVersionMapping); QDirIterator it(repositoryDir, QStringList(QLatin1String("Updates*.xml")), QDir::Files | QDir::CaseSensitive); while (it.hasNext()) { it.next(); QFile::remove(it.fileInfo().absoluteFilePath()); } - moveDirectoryContents(metaTmp, repositoryDir); - return 0; + QInstaller::moveDirectoryContents(tmpMetaDir, repositoryDir); + exitCode = EXIT_SUCCESS; } catch (const Lib7z::SevenZipException &e) { - std::cerr << "caught 7zip exception: " << e.message() << std::endl; + std::cerr << "Caught 7zip exception: " << e.message() << std::endl; } catch (const QInstaller::Error &e) { - std::cerr << "caught exception: " << e.message() << std::endl; + std::cerr << "Caught exception: " << e.message() << std::endl; + } catch (...) { + std::cerr << "Unknown exception caught" << std::endl; } - return 1; + + QInstaller::removeDirectory(tmpMetaDir, true); + return exitCode; } diff --git a/tools/repogenfromonlinerepo/downloadmanager.cpp b/tools/repogenfromonlinerepo/downloadmanager.cpp deleted file mode 100644 index ee4e9864f..000000000 --- a/tools/repogenfromonlinerepo/downloadmanager.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "downloadmanager.h" - -#include <QFileInfo> -#include <QNetworkRequest> -#include <QNetworkReply> -#include <QString> -#include <QStringList> -#include <QTimer> -#include <stdio.h> - -DownloadManager::DownloadManager(QObject *parent) - : QObject(parent), downloadedCount(0), totalCount(0) -{ -} - -void DownloadManager::append(const QStringList &urlList) -{ - foreach (QString url, urlList) - append(QUrl::fromEncoded(url.toLocal8Bit())); - - if (downloadQueue.isEmpty()) - QTimer::singleShot(0, this, SIGNAL(finished())); -} - -void DownloadManager::append(const QUrl &url) -{ - if (downloadQueue.isEmpty()) - QTimer::singleShot(0, this, SLOT(startNextDownload())); - - downloadQueue.enqueue(url); - ++totalCount; -} - -QString DownloadManager::saveFileName(const QUrl &url) -{ - QString path = url.path(); - QString basename = QFileInfo(path).fileName(); - - if (basename.isEmpty()) - basename = QLatin1String("download"); - - if (QFile::exists(basename)) { - // already exists, rename the old one - int i = 0; - while (QFile::exists(basename + QLatin1String(".old_") + QString::number(i))) - ++i; - - QFile::rename(basename, basename + QLatin1String(".old_") + QString::number(i)); - //basename += QString::number(i); - } - - return basename; -} - -void DownloadManager::startNextDownload() -{ - if (downloadQueue.isEmpty()) { - printf("%d/%d files downloaded successfully\n", downloadedCount, totalCount); - emit finished(); - return; - } - - QUrl url = downloadQueue.dequeue(); - - QString filename = saveFileName(url); - output.setFileName(filename); - if (!output.open(QIODevice::WriteOnly)) { - fprintf(stderr, "Problem opening save file '%s' for download '%s': %s\n", - qPrintable(filename), url.toEncoded().constData(), - qPrintable(output.errorString())); - - startNextDownload(); - return; // skip this download - } - - QNetworkRequest request(url); - currentDownload = manager.get(request); - connect(currentDownload, SIGNAL(downloadProgress(qint64,qint64)), - SLOT(downloadProgress(qint64,qint64))); - connect(currentDownload, SIGNAL(finished()), - SLOT(downloadFinished())); - connect(currentDownload, SIGNAL(readyRead()), - SLOT(downloadReadyRead())); - - // prepare the output - printf("Downloading %s...\n", url.toEncoded().constData()); - downloadTime.start(); -} - -void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) -{ - progressBar.setStatus(bytesReceived, bytesTotal); - - // calculate the download speed - double speed = bytesReceived * 1000.0 / downloadTime.elapsed(); - QString unit; - if (speed < 1024) { - unit = QLatin1String("bytes/sec"); - } else if (speed < 1024*1024) { - speed /= 1024; - unit = QLatin1String("kB/s"); - } else { - speed /= 1024*1024; - unit = QLatin1String("MB/s"); - } - - progressBar.setMessage(QString::fromLatin1("%1 %2").arg(speed, 3, 'f', 1).arg(unit)); - progressBar.update(); -} - -void DownloadManager::downloadFinished() -{ - progressBar.clear(); - output.close(); - - if (currentDownload->error()) { - // download failed - fprintf(stderr, "Failed: %s\n", qPrintable(currentDownload->errorString())); - } else { - printf("Succeeded.\n"); - ++downloadedCount; - } - - currentDownload->deleteLater(); - startNextDownload(); -} - -void DownloadManager::downloadReadyRead() -{ - output.write(currentDownload->readAll()); -} diff --git a/tools/repogenfromonlinerepo/main.cpp b/tools/repogenfromonlinerepo/main.cpp deleted file mode 100644 index 12023d495..000000000 --- a/tools/repogenfromonlinerepo/main.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Installer Framework. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -**************************************************************************/ -#include "downloadmanager.h" - -#include <QtCore/QCoreApplication> -#include <QFile> -#include <QString> -#include <QDomDocument> -#include <QDomElement> -#include <QDomNodeList> -#include <QStringList> -#include <QDebug> -#include <QFileInfo> -#include <QDir> -#include <iostream> - -static void printUsage() -{ - const QString appName = QFileInfo( QCoreApplication::applicationFilePath() ).fileName(); - std::cout << "Usage: " << qPrintable(appName) << "--url <repository_url>" << std::endl; - std::cout << std::endl; - std::cout << "Example:" << std::endl; - std::cout << " " << qPrintable(appName) << " someDirectory foobar.7z" << std::endl; -} - - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - - QString repoUrl = QLatin1String("http://www.forum.nokia.com/nokiaqtsdkrepository/oppdatering/windows/" - "online_ndk_repo"); - - QStringList args = app.arguments(); - for( QStringList::const_iterator it = args.constBegin(); it != args.constEnd(); ++it ) - { - if( *it == QString::fromLatin1( "-h" ) || *it == QString::fromLatin1( "--help" ) ) - { - printUsage(); - return 0; - } - else if( *it == QString::fromLatin1( "-u" ) || *it == QString::fromLatin1( "--url" ) ) - { - ++it; - if( it == args.end() ) { -// printUsage(); -// return -1; - } else { - repoUrl = *it; - } - } - } - - QEventLoop downloadEventLoop; - - DownloadManager downloadManager; - -// get Updates.xml to get to know what we can download - downloadManager.append(QUrl(repoUrl + QLatin1String("/Updates.xml"))); - QObject::connect( &downloadManager, SIGNAL( finished() ), &downloadEventLoop, SLOT( quit() ) ); - downloadEventLoop.exec(); -// END - get Updates.xml to get to know what we can download - - QFile batchFile(QLatin1String("download.bat")); - if (!batchFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qDebug() << "can not open " << QFileInfo(batchFile).absoluteFilePath(); - return app.exec(); - } - - QTextStream batchFileOut(&batchFile); - - const QString updatesXmlPath = QLatin1String("Updates.xml"); - - Q_ASSERT( !updatesXmlPath.isEmpty() ); - Q_ASSERT( QFile::exists( updatesXmlPath ) ); - - QFile updatesFile( updatesXmlPath ); - if ( !updatesFile.open( QIODevice::ReadOnly ) ) { - //qDebug() << QString::fromLatin1("Could not open Updates.xml for reading: %1").arg( updatesFile - // .errorString() ) ; - return app.exec(); - } - - QDomDocument doc; - QString err; - int line = 0; - int col = 0; - if ( !doc.setContent( &updatesFile, &err, &line, &col ) ) { - //qDebug() << QString::fromLatin1("Could not parse component index: %1:%2: %3") - // .arg(QString::number(line), QString::number( col ), err ); - return app.exec(); - } - - const QDomElement root = doc.documentElement(); - const QDomNodeList children = root.childNodes(); - for ( int i = 0; i < children.count(); ++i ) { - //qDebug() << children.count(); - QString packageName; - QString packageDisplayName; - QString packageDescription; - QString packageUpdateText; - QString packageVersion; - QString packageReleaseDate; - QString packageHash; - QString packageUserinterfacesAsString; - QString packageInstallPriority; - QString packageScript; - QString packageDependencies; - QString packageForcedInstallation; - bool packageIsVirtual = false; - QString sevenZString; - const QDomElement el = children.at( i ).toElement(); - if ( el.isNull() ) - continue; - if ( el.tagName() == QLatin1String("PackageUpdate") ) { - const QDomNodeList c2 = el.childNodes(); - - for ( int j = 0; j < c2.count(); ++j ) { - if ( c2.at( j ).toElement().tagName() == QLatin1String("Name") ) - packageName = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("DisplayName") ) - packageDisplayName = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("Description") ) - packageDescription = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("UpdateText") ) - packageUpdateText = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("Version") ) - packageVersion = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("ReleaseDate") ) - packageReleaseDate = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("SHA1") ) - packageHash = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("UserInterfaces") ) - packageUserinterfacesAsString = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("Script") ) - packageScript = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("Dependencies") ) - packageDependencies = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("ForcedInstallation") ) - packageForcedInstallation = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("InstallPriority") ) - packageInstallPriority = c2.at( j ).toElement().text(); - else if ( c2.at( j ).toElement().tagName() == QLatin1String("Virtual") && c2.at( j ) - .toElement().text() == QLatin1String("true")) { - packageIsVirtual = true; - } - } - } - if (packageName.isEmpty()) { - continue; - } - - if ( !packageScript.isEmpty() ) { - // get Updates.xml to get to know what we can download - downloadManager.append(QUrl(repoUrl + QLatin1String("/") + packageName + QLatin1String("/") - + packageScript)); - QObject::connect( &downloadManager, SIGNAL( finished() ), &downloadEventLoop, SLOT( quit() ) ); - downloadEventLoop.exec(); - // END - get Updates.xml to get to know what we can download - - QString localScriptFileName = packageScript; - Q_ASSERT( QFile::exists( localScriptFileName ) ); - - QFile file(localScriptFileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - //qDebug() << localScriptFileName << " was not readable"; - continue; - } - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine(); - if (line.contains(QLatin1String(".7z"))) { - int firstPosition = line.indexOf(QLatin1String("\"")); - QString subString = line.right(line.count() - firstPosition - 1); //-1 means " - //qDebug() << subString; - int secondPosition = subString.indexOf(QLatin1String("\"")); - sevenZString = subString.left(secondPosition); - //qDebug() << sevenZString; - break; - } - } - file.remove(); - } - QStringList packageUserinterfaces = packageUserinterfacesAsString.split(QLatin1String(",")); - packageUserinterfaces.removeAll(QString()); - packageUserinterfaces.removeAll(QLatin1String("")); - - QStringList fileList; - - //fileList << packageVersion + sevenZString; - foreach(const QString file, packageUserinterfaces) { - if(!file.isEmpty()) { - fileList << file; - }/* else { - qDebug() << "There is something wrong with the userinterface string list."; - return a.exec(); - }*/ - } - if(!packageScript.isEmpty()) { - fileList << packageScript; - } - - QFile packagesXml( QString( QCoreApplication::applicationDirPath() + QLatin1String("/") - + packageName + QLatin1String(".xml"))); - packagesXml.open( QIODevice::WriteOnly ); - QTextStream packageAsXmlStream( &packagesXml ); - packageAsXmlStream << QLatin1String("<?xml version=\"1.0\"?>" ) << endl; - packageAsXmlStream << QLatin1String("<Package>" ) << endl; - packageAsXmlStream << QString::fromLatin1(" <DisplayName>%1</DisplayName>").arg(packageDisplayName) - << endl; - - if (!packageDescription.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <Description>%1</Description>" ) - .arg(packageDescription) << endl; - } - - if (!packageUpdateText.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <UpdateText>%1</UpdateText>" ) - .arg(packageUpdateText) << endl; - } - - if (!packageVersion.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <Version>%1</Version>" ) - .arg(packageVersion) << endl; - } - - if (!packageReleaseDate.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <ReleaseDate>%1</ReleaseDate>" ) - .arg(packageReleaseDate) << endl; - } - packageAsXmlStream << QString::fromLatin1(" <Name>%1</Name>" ).arg(packageName) << endl; - - if (!packageScript.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <Script>%1</Script>" ).arg(packageScript) << endl; - } - - if (packageIsVirtual) { - packageAsXmlStream << QString::fromLatin1(" <Virtual>true</Virtual>" ) << endl; - } - - if (!packageInstallPriority.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <InstallPriority>%1</InstallPriority>" ) - .arg(packageInstallPriority) << endl; - } - if (!packageDependencies.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <Dependencies>%1</Dependencies>" ) - .arg(packageDependencies) << endl; - } - - if (!packageForcedInstallation.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <ForcedInstallation>%1</ForcedInstallation>" ) - .arg(packageForcedInstallation) << endl; - } - - if (!packageUserinterfaces.isEmpty()) { - packageAsXmlStream << QString::fromLatin1(" <UserInterfaces>" ) << endl; - foreach(const QString userInterfaceFile, packageUserinterfaces) { - packageAsXmlStream << QString::fromLatin1(" <UserInterface>%1</UserInterface>" ) - .arg(userInterfaceFile) << endl; - } - packageAsXmlStream << QString::fromLatin1(" </UserInterfaces>" ) << endl; - } - packageAsXmlStream << QString::fromLatin1("</Package>" ) << endl; - - batchFileOut << "rem download line BEGIN =============================================\n"; - - batchFileOut << "mkdir " << packageName << "\\meta\n"; - batchFileOut << "move " << QDir::toNativeSeparators(QFileInfo(packagesXml).absoluteFilePath()) << " " << packageName << "\\meta\\package.xml\n"; - if (!sevenZString.isEmpty()) { - batchFileOut << "mkdir " << packageName << "\\data\n"; - batchFileOut << "cd " << packageName << "\\data\n"; - batchFileOut << "wget " << repoUrl << "/" << packageName << "/" << QString(packageVersion + sevenZString) << " -O " << sevenZString << "\n"; - batchFileOut << "cd ..\\..\n"; - } - batchFileOut << "cd " << packageName << "\\meta\n"; - foreach(const QString file, fileList) { - batchFileOut << "wget " << repoUrl << "/" << packageName << "/" << file << "\n"; - } - batchFileOut << "cd ..\\..\n"; - - batchFileOut << "rem download line END =============================================\n"; - } //for ( int i = 0; i < children.count(); ++i ) { - - if ( children.count() == 0 ) { - qDebug() << "no packages found"; - return app.exec(); - } else { - qDebug() << "found packages and wrote batch file"; - } - - - return 0; -} diff --git a/tools/repogenfromonlinerepo/repogenfromonlinerepo.pro b/tools/repogenfromonlinerepo/repogenfromonlinerepo.pro deleted file mode 100644 index 0c11efa36..000000000 --- a/tools/repogenfromonlinerepo/repogenfromonlinerepo.pro +++ /dev/null @@ -1,19 +0,0 @@ -TEMPLATE = app -INCLUDEPATH += . .. -TARGET = repogenfromonlinerepo - -include(../../installerfw.pri) - -QT -= gui -QT += network - -CONFIG += console -CONFIG -= app_bundle -DESTDIR = $$IFW_APP_PATH - -SOURCES += main.cpp \ - downloadmanager.cpp \ - textprogressbar.cpp - -HEADERS += downloadmanager.h \ - textprogressbar.h diff --git a/tools/tools.pro b/tools/tools.pro index 51cc5eae6..34b980f92 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -9,7 +9,7 @@ SUBDIRS += \ EXTRASUBDIRS = \ extractbinarydata \ repocompare \ - repogenfromonlinerepo + getrepositorycontent include(../installerfw.pri) |