summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/installerfw.qdoc18
-rw-r--r--src/libs/installer/packagemanagergui.cpp8
-rw-r--r--tools/binarycreator/binarycreator.cpp44
-rw-r--r--tools/common/repositorygen.cpp634
-rw-r--r--tools/common/repositorygen.h6
-rw-r--r--tools/repogen/repogen.cpp30
6 files changed, 478 insertions, 262 deletions
diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc
index f387c1544..cf80de028 100644
--- a/doc/installerfw.qdoc
+++ b/doc/installerfw.qdoc
@@ -823,6 +823,11 @@
{package directory}.
Defaults to the current working directory.
\row
+ \li --repository directory
+ \li Use \c directory as the repository directory
+ with packages to repack.
+ This entry can be given multiple times.
+ \row
\li -n or --online-only
\li Compile without any component in the installer binary.
\row
@@ -854,6 +859,10 @@
\li Ignore component or package directories that do not have valid
metadata information (package.xml) to make testing faster.
\row
+ \li --ignore-invalid-repositories
+ \li Ignore repository directories that do not have valid
+ metadata information (Updates.xml) instead of aborting.
+ \row
\li -v or --verbose
\li Display debug output.
@@ -907,6 +916,9 @@
specify the location in the installer configuration file when creating an
installer for it.
+ You can use an existing repository to repack packages to another
+ repository or offline installer.
+
\section2 Summary of repogen Parameters
\table
@@ -918,6 +930,12 @@
\li Use \c directory as the \l{Package Directory Structure}
{package directory}. This is mandatory.
\row
+ \li --repository directory
+ \li Use \c directory as the repository directory
+ with packages to repack (not to confuse with the mandatory target
+ repository directory).
+ This entry can be given multiple times.
+ \row
\li repository directory
\li Target directory for the repository. During an initial installation, the directory
must not yet exist. When updating, the directory may exist and its contents may be
diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp
index 28a86be50..513b9d0e0 100644
--- a/src/libs/installer/packagemanagergui.cpp
+++ b/src/libs/installer/packagemanagergui.cpp
@@ -1275,19 +1275,19 @@ IntroductionPage::IntroductionPage(PackageManagerCore *core)
QWidget *widget = new QWidget(this);
QVBoxLayout *boxLayout = new QVBoxLayout(widget);
- m_packageManager = new QRadioButton(tr("Add or remove components"), this);
+ m_packageManager = new QRadioButton(tr("&Add or remove components"), this);
m_packageManager->setObjectName(QLatin1String("PackageManagerRadioButton"));
boxLayout->addWidget(m_packageManager);
m_packageManager->setChecked(core->isPackageManager());
connect(m_packageManager, &QAbstractButton::toggled, this, &IntroductionPage::setPackageManager);
- m_updateComponents = new QRadioButton(tr("Update components"), this);
+ m_updateComponents = new QRadioButton(tr("&Update components"), this);
m_updateComponents->setObjectName(QLatin1String("UpdaterRadioButton"));
boxLayout->addWidget(m_updateComponents);
m_updateComponents->setChecked(core->isUpdater());
connect(m_updateComponents, &QAbstractButton::toggled, this, &IntroductionPage::setUpdater);
- m_removeAllComponents = new QRadioButton(tr("Remove all components"), this);
+ m_removeAllComponents = new QRadioButton(tr("&Remove all components"), this);
m_removeAllComponents->setObjectName(QLatin1String("UninstallerRadioButton"));
boxLayout->addWidget(m_removeAllComponents);
m_removeAllComponents->setChecked(core->isUninstaller());
@@ -1612,7 +1612,7 @@ void IntroductionPage::entering()
showWidgets(false);
setMessage(QString());
setErrorMessage(QString());
- setButtonText(QWizard::CancelButton, tr("Quit"));
+ setButtonText(QWizard::CancelButton, tr("&Quit"));
m_progressBar->setValue(0);
m_progressBar->setRange(0, 0);
diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp
index e74f8a18c..b9497f533 100644
--- a/tools/binarycreator/binarycreator.cpp
+++ b/tools/binarycreator/binarycreator.cpp
@@ -599,6 +599,7 @@ int main(int argc, char **argv)
QString target;
QString configFile;
QStringList packagesDirectories;
+ QStringList repositoryDirectories;
bool onlineOnly = false;
bool offlineOnly = false;
QStringList resources;
@@ -622,6 +623,16 @@ int main(int argc, char **argv)
"specified location."));
}
packagesDirectories.append(*it);
+ } else if (*it == QLatin1String("--repository")) {
+ ++it;
+ if (it == args.end()) {
+ return printErrorAndUsageAndExit(QString::fromLatin1("Error: Repository parameter missing argument."));
+ }
+ if (QFileInfo(*it).exists()) {
+ repositoryDirectories.append(*it);
+ } else {
+ return printErrorAndUsageAndExit(QString::fromLatin1("Error: Only local filesystem repositories now supported."));
+ }
} else if (*it == QLatin1String("-e") || *it == QLatin1String("--exclude")) {
++it;
if (!filteredPackages.isEmpty())
@@ -734,8 +745,8 @@ int main(int argc, char **argv)
if (configFile.isEmpty())
return printErrorAndUsageAndExit(QString::fromLatin1("Error: No configuration file selected."));
- if (packagesDirectories.isEmpty())
- return printErrorAndUsageAndExit(QString::fromLatin1("Error: Package directory parameter missing."));
+ if (packagesDirectories.isEmpty() && repositoryDirectories.isEmpty())
+ return printErrorAndUsageAndExit(QString::fromLatin1("Error: Both Package directory and Repository parameters missing."));
qDebug() << "Parsed arguments, ok.";
@@ -753,14 +764,29 @@ int main(int argc, char **argv)
// Note: the order here is important
- // 1; create the list of available packages
- QInstallerTools::PackageInfoVector packages =
- QInstallerTools::createListOfPackages(packagesDirectories, &filteredPackages, ftype);
+ QInstallerTools::PackageInfoVector packages;
+
+ // 1; update the list of available compressed packages
+ if (!repositoryDirectories.isEmpty()) {
+ // 1.1; search packages
+ QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages(repositoryDirectories,
+ &filteredPackages, ftype);
+ // 1.2; add to common vector
+ packages.append(precompressedPackages);
+ }
- // 2; copy the packages data and setup the packages vector with the files we copied,
- // must happen before copying meta data because files will be compressed if
- // needed and meta data generation relies on this
- QInstallerTools::copyComponentData(packagesDirectories, tmpRepoDir, &packages);
+ // 2; update the list of available prepared packages
+ if (!packagesDirectories.isEmpty()) {
+ // 2.1; search packages
+ QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(packagesDirectories,
+ &filteredPackages, ftype);
+ // 2.2; copy the packages data and setup the packages vector with the files we copied,
+ // must happen before copying meta data because files will be compressed if
+ // needed and meta data generation relies on this
+ QInstallerTools::copyComponentData(packagesDirectories, tmpRepoDir, &preparedPackages);
+ // 2.3; add to common vector
+ packages.append(preparedPackages);
+ }
// 3; copy the meta data of the available packages, generate Updates.xml
QInstallerTools::copyMetaData(tmpMetaDir, tmpRepoDir, packages, settings
diff --git a/tools/common/repositorygen.cpp b/tools/common/repositorygen.cpp
index 4c7dba3b4..2942728c2 100644
--- a/tools/common/repositorygen.cpp
+++ b/tools/common/repositorygen.cpp
@@ -27,11 +27,13 @@
**************************************************************************/
#include "repositorygen.h"
+#include <constants.h>
#include <fileio.h>
#include <fileutils.h>
#include <errors.h>
#include <globals.h>
#include <lib7z_create.h>
+#include <lib7z_extract.h>
#include <lib7z_facade.h>
#include <lib7z_list.h>
#include <settings.h>
@@ -54,6 +56,8 @@ void QInstallerTools::printRepositoryGenOptions()
{
std::cout << " -p|--packages dir The directory containing the available packages." << std::endl;
std::cout << " This entry can be given multiple times." << std::endl;
+ std::cout << " --repository dir The directory containing the available repository." << std::endl;
+ std::cout << " This entry can be given multiple times." << std::endl;
std::cout << " -e|--exclude p1,...,pn Exclude the given packages." << std::endl;
std::cout << " -i|--include p1,...,pn Include the given packages and their dependencies" << std::endl;
@@ -61,6 +65,7 @@ void QInstallerTools::printRepositoryGenOptions()
std::cout << " --ignore-translations Do not use any translation" << std::endl;
std::cout << " --ignore-invalid-packages Ignore all invalid packages instead of aborting." << std::endl;
+ std::cout << " --ignore-invalid-repositories Ignore all invalid repositories instead of aborting." << std::endl;
}
QString QInstallerTools::makePathAbsolute(const QString &path)
@@ -154,220 +159,236 @@ void QInstallerTools::copyMetaData(const QString &_targetDir, const QString &met
}
foreach (const PackageInfo &info, packages) {
- if (!QDir(targetDir).mkpath(info.name))
- throw QInstaller::Error(QString::fromLatin1("Cannot create directory \"%1\".").arg(info.name));
-
- const QString packageXmlPath = QString::fromLatin1("%1/meta/package.xml").arg(info.directory);
- qDebug() << "Copy meta data for package" << info.name << "using" << packageXmlPath;
-
- QFile file(packageXmlPath);
- QInstaller::openForRead(&file);
-
- QString errMsg;
- int line = 0;
- int column = 0;
- QDomDocument packageXml;
- if (!packageXml.setContent(&file, &errMsg, &line, &column)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot parse \"%1\": line: %2, column: %3: %4 (%5)")
- .arg(QDir::toNativeSeparators(packageXmlPath)).arg(line).arg(column).arg(errMsg, info.name));
- }
+ if (info.metaFile.isEmpty() && info.metaNode.isEmpty()) {
+ if (!QDir(targetDir).mkpath(info.name))
+ throw QInstaller::Error(QString::fromLatin1("Cannot create directory \"%1\".").arg(info.name));
+
+ const QString packageXmlPath = QString::fromLatin1("%1/meta/package.xml").arg(info.directory);
+ qDebug() << "Copy meta data for package" << info.name << "using" << packageXmlPath;
+
+ QFile file(packageXmlPath);
+ QInstaller::openForRead(&file);
+
+ QString errMsg;
+ int line = 0;
+ int column = 0;
+ QDomDocument packageXml;
+ if (!packageXml.setContent(&file, &errMsg, &line, &column)) {
+ throw QInstaller::Error(QString::fromLatin1("Cannot parse \"%1\": line: %2, column: %3: %4 (%5)")
+ .arg(QDir::toNativeSeparators(packageXmlPath)).arg(line).arg(column).arg(errMsg, info.name));
+ }
- QDomElement update = doc.createElement(QLatin1String("PackageUpdate"));
- QDomNode nameElement = update.appendChild(doc.createElement(QLatin1String("Name")));
- nameElement.appendChild(doc.createTextNode(info.name));
-
- // list of current unused or later transformed tags
- QStringList blackList;
- blackList << QLatin1String("UserInterfaces") << QLatin1String("Translations") <<
- QLatin1String("Licenses") << QLatin1String("Name");
-
- bool foundDefault = false;
- bool foundVirtual = false;
- bool foundDisplayName = false;
- bool foundDownloadableArchives = false;
- bool foundCheckable = 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);
- const QString key = node.nodeName();
-
- if (key == QLatin1String("Default"))
- foundDefault = true;
- if (key == QLatin1String("Virtual"))
- foundVirtual = true;
- if (key == QLatin1String("DisplayName"))
- foundDisplayName = true;
- if (key == QLatin1String("DownloadableArchives"))
- foundDownloadableArchives = true;
- if (key == QLatin1String("Checkable"))
- foundCheckable = true;
- if (node.isComment() || blackList.contains(key))
- continue; // just skip comments and some tags...
-
- QDomElement element = doc.createElement(key);
- for (int j = 0; j < node.attributes().size(); ++j) {
- element.setAttribute(node.attributes().item(j).toAttr().name(),
- node.attributes().item(j).toAttr().value());
+ QDomElement update = doc.createElement(QLatin1String("PackageUpdate"));
+ QDomNode nameElement = update.appendChild(doc.createElement(QLatin1String("Name")));
+ nameElement.appendChild(doc.createTextNode(info.name));
+
+ // list of current unused or later transformed tags
+ QStringList blackList;
+ blackList << QLatin1String("UserInterfaces") << QLatin1String("Translations") <<
+ QLatin1String("Licenses") << QLatin1String("Name");
+
+ bool foundDefault = false;
+ bool foundVirtual = false;
+ bool foundDisplayName = false;
+ bool foundDownloadableArchives = false;
+ bool foundCheckable = 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);
+ const QString key = node.nodeName();
+
+ if (key == QLatin1String("Default"))
+ foundDefault = true;
+ if (key == QLatin1String("Virtual"))
+ foundVirtual = true;
+ if (key == QLatin1String("DisplayName"))
+ foundDisplayName = true;
+ if (key == QLatin1String("DownloadableArchives"))
+ foundDownloadableArchives = true;
+ if (key == QLatin1String("Checkable"))
+ foundCheckable = true;
+ if (node.isComment() || blackList.contains(key))
+ continue; // just skip comments and some tags...
+
+ QDomElement element = doc.createElement(key);
+ 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(node.toElement().text()));
}
- update.appendChild(element).appendChild(doc.createTextNode(node.toElement().text()));
- }
- if (foundDefault && foundVirtual) {
- throw QInstaller::Error(QString::fromLatin1("Error: <Default> and <Virtual> elements are "
- "mutually exclusive in file \"%1\".").arg(QDir::toNativeSeparators(packageXmlPath)));
- }
+ if (foundDefault && foundVirtual) {
+ throw QInstaller::Error(QString::fromLatin1("Error: <Default> and <Virtual> elements are "
+ "mutually exclusive in file \"%1\".").arg(QDir::toNativeSeparators(packageXmlPath)));
+ }
- if (foundDefault && foundCheckable) {
- throw QInstaller::Error(QString::fromLatin1("Error: <Default> and <Checkable>"
- "elements are mutually exclusive in file \"%1\".")
- .arg(QDir::toNativeSeparators(packageXmlPath)));
- }
+ if (foundDefault && foundCheckable) {
+ throw QInstaller::Error(QString::fromLatin1("Error: <Default> and <Checkable>"
+ "elements are mutually exclusive in file \"%1\".")
+ .arg(QDir::toNativeSeparators(packageXmlPath)));
+ }
- if (!foundDisplayName) {
- qWarning() << "No DisplayName tag found at" << info.name << ", using component Name instead.";
- QDomElement displayNameElement = doc.createElement(QLatin1String("DisplayName"));
- update.appendChild(displayNameElement).appendChild(doc.createTextNode(info.name));
- }
+ if (!foundDisplayName) {
+ qWarning() << "No DisplayName tag found at" << info.name << ", using component Name instead.";
+ QDomElement displayNameElement = doc.createElement(QLatin1String("DisplayName"));
+ update.appendChild(displayNameElement).appendChild(doc.createTextNode(info.name));
+ }
- // get the size of the data
- quint64 componentSize = 0;
- quint64 compressedComponentSize = 0;
-
- const QDir::Filters filters = QDir::Files | QDir::NoDotAndDotDot;
- 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() << "calculate size of directory" << dataDir.absolutePath();
- foreach (const QFileInfo &fi, entries) {
- try {
- if (fi.isDir()) {
- QDirIterator recursDirIt(fi.filePath(), QDirIterator::Subdirectories);
- while (recursDirIt.hasNext()) {
- recursDirIt.next();
- const quint64 size = QInstaller::fileSize(recursDirIt.fileInfo());
+ // get the size of the data
+ quint64 componentSize = 0;
+ quint64 compressedComponentSize = 0;
+
+ const QDir::Filters filters = QDir::Files | QDir::NoDotAndDotDot;
+ 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() << "calculate size of directory" << dataDir.absolutePath();
+ foreach (const QFileInfo &fi, entries) {
+ try {
+ if (fi.isDir()) {
+ QDirIterator recursDirIt(fi.filePath(), QDirIterator::Subdirectories);
+ while (recursDirIt.hasNext()) {
+ recursDirIt.next();
+ const quint64 size = QInstaller::fileSize(recursDirIt.fileInfo());
+ componentSize += size;
+ compressedComponentSize += size;
+ }
+ } else if (Lib7z::isSupportedArchive(fi.filePath())) {
+ // if it's an archive already, list its files and sum the uncompressed sizes
+ QFile archive(fi.filePath());
+ compressedComponentSize += archive.size();
+ QInstaller::openForRead(&archive);
+
+ 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 = QInstaller::fileSize(fi);
componentSize += size;
compressedComponentSize += size;
}
- } else if (Lib7z::isSupportedArchive(fi.filePath())) {
- // if it's an archive already, list its files and sum the uncompressed sizes
- QFile archive(fi.filePath());
- compressedComponentSize += archive.size();
- QInstaller::openForRead(&archive);
-
- 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 = QInstaller::fileSize(fi);
- componentSize += size;
- compressedComponentSize += size;
+ } catch (const QInstaller::Error &error) {
+ qDebug().noquote() << error.message();
+ } catch(...) {
+ // ignore, that's just about the sizes - and size doesn't matter, you know?
}
- } catch (const QInstaller::Error &error) {
- qDebug().noquote() << error.message();
- } catch(...) {
- // ignore, that's just about the sizes - and size doesn't matter, you know?
}
- }
- QDomElement fileElement = doc.createElement(QLatin1String("UpdateFile"));
- fileElement.setAttribute(QLatin1String("UncompressedSize"), componentSize);
- fileElement.setAttribute(QLatin1String("CompressedSize"), compressedComponentSize);
- // adding the OS attribute to be compatible with old sdks
- fileElement.setAttribute(QLatin1String("OS"), QLatin1String("Any"));
- update.appendChild(fileElement);
-
- root.appendChild(update);
-
- // copy script file
- const QString script = package.firstChildElement(QLatin1String("Script")).text();
- if (!script.isEmpty()) {
- QFile scriptFile(QString::fromLatin1("%1/meta/%2").arg(info.directory, script));
- if (!scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot open component script at \"%1\".")
- .arg(QDir::toNativeSeparators(scriptFile.fileName())));
- }
+ QDomElement fileElement = doc.createElement(QLatin1String("UpdateFile"));
+ fileElement.setAttribute(QLatin1String("UncompressedSize"), componentSize);
+ fileElement.setAttribute(QLatin1String("CompressedSize"), compressedComponentSize);
+ // adding the OS attribute to be compatible with old sdks
+ fileElement.setAttribute(QLatin1String("OS"), QLatin1String("Any"));
+ update.appendChild(fileElement);
+
+ root.appendChild(update);
+
+ // copy script file
+ const QString script = package.firstChildElement(QLatin1String("Script")).text();
+ if (!script.isEmpty()) {
+ QFile scriptFile(QString::fromLatin1("%1/meta/%2").arg(info.directory, script));
+ if (!scriptFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ throw QInstaller::Error(QString::fromLatin1("Cannot open component script at \"%1\".")
+ .arg(QDir::toNativeSeparators(scriptFile.fileName())));
+ }
- const QString scriptContent = QLatin1String("(function() {")
- + QString::fromUtf8(scriptFile.readAll())
- + QLatin1String(";"
- " if (typeof Component == \"undefined\")"
- " throw \"Missing Component constructor. Please check your script.\";"
- "})();");
-
- // if the user isn't aware of the downloadable archives value we will add it automatically later
- foundDownloadableArchives |= scriptContent.contains(QLatin1String("addDownloadableArchive"))
- || scriptContent.contains(QLatin1String("removeDownloadableArchive"));
-
- static QInstaller::ScriptEngine testScriptEngine;
- const QJSValue value = testScriptEngine.evaluate(scriptContent, scriptFile.fileName());
- if (value.isError()) {
- throw QInstaller::Error(QString::fromLatin1("Exception while loading component "
- "script at \"%1\": %2").arg(QDir::toNativeSeparators(scriptFile.fileName()),
- value.toString().isEmpty() ?
- QString::fromLatin1("Unknown error.") : value.toString()));
- }
+ const QString scriptContent = QLatin1String("(function() {")
+ + QString::fromUtf8(scriptFile.readAll())
+ + QLatin1String(";"
+ " if (typeof Component == \"undefined\")"
+ " throw \"Missing Component constructor. Please check your script.\";"
+ "})();");
+
+ // if the user isn't aware of the downloadable archives value we will add it automatically later
+ foundDownloadableArchives |= scriptContent.contains(QLatin1String("addDownloadableArchive"))
+ || scriptContent.contains(QLatin1String("removeDownloadableArchive"));
+
+ static QInstaller::ScriptEngine testScriptEngine;
+ const QJSValue value = testScriptEngine.evaluate(scriptContent, scriptFile.fileName());
+ if (value.isError()) {
+ throw QInstaller::Error(QString::fromLatin1("Exception while loading component "
+ "script at \"%1\": %2").arg(QDir::toNativeSeparators(scriptFile.fileName()),
+ value.toString().isEmpty() ?
+ QString::fromLatin1("Unknown error.") : value.toString()));
+ }
- const QString toLocation(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, script));
- copyWithException(scriptFile.fileName(), toLocation, QInstaller::scScript);
- }
+ const QString toLocation(QString::fromLatin1("%1/%2/%3").arg(targetDir, info.name, script));
+ copyWithException(scriptFile.fileName(), toLocation, QInstaller::scScript);
+ }
- // write DownloadableArchives tag if that is missed by the user
- if (!foundDownloadableArchives && !info.copiedFiles.isEmpty()) {
- QStringList realContentFiles;
- foreach (const QString &filePath, info.copiedFiles) {
- if (!filePath.endsWith(QLatin1String(".sha1"), Qt::CaseInsensitive)) {
- const QString fileName = QFileInfo(filePath).fileName();
- // remove unnecessary version string from filename and add it to the list
- realContentFiles.append(fileName.mid(info.version.count()));
+ // write DownloadableArchives tag if that is missed by the user
+ if (!foundDownloadableArchives && !info.copiedFiles.isEmpty()) {
+ QStringList realContentFiles;
+ foreach (const QString &filePath, info.copiedFiles) {
+ if (!filePath.endsWith(QLatin1String(".sha1"), Qt::CaseInsensitive)) {
+ const QString fileName = QFileInfo(filePath).fileName();
+ // remove unnecessary version string from filename and add it to the list
+ realContentFiles.append(fileName.mid(info.version.count()));
+ }
}
- }
- update.appendChild(doc.createElement(QLatin1String("DownloadableArchives"))).appendChild(doc
- .createTextNode(realContentFiles.join(QChar::fromLatin1(','))));
- }
+ update.appendChild(doc.createElement(QLatin1String("DownloadableArchives"))).appendChild(doc
+ .createTextNode(realContentFiles.join(QChar::fromLatin1(','))));
+ }
- // copy user interfaces
- 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 user interfaces
+ 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
- QStringList trFiles;
- if (!qApp->arguments().contains(QString::fromLatin1("--ignore-translations"))) {
- 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 translations
+ QStringList trFiles;
+ if (!qApp->arguments().contains(QString::fromLatin1("--ignore-translations"))) {
+ 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 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));
+ // copy license files
+ 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));
+ }
}
+ update.appendChild(package.firstChildElement(QLatin1String("Licenses")).cloneNode());
}
- update.appendChild(package.firstChildElement(QLatin1String("Licenses")).cloneNode());
+ } else {
+ // Extract metadata from archive
+ QFile metaFile(info.metaFile);
+ QInstaller::openForRead(&metaFile);
+ Lib7z::extractArchive(&metaFile, targetDir);
+
+ // Restore "PackageUpdate" node;
+ QDomDocument update;
+ if (!update.setContent(info.metaNode)) {
+ throw QInstaller::Error(QString::fromLatin1("Cannot restore \"PackageUpdate\" description for node %1").arg(info.name));
+ }
+
+ root.appendChild(update.documentElement());
}
}
+
doc.appendChild(root);
QFile targetUpdatesXml(targetDir + QLatin1String("/Updates.xml"));
@@ -484,6 +505,114 @@ PackageInfoVector QInstallerTools::createListOfPackages(const QStringList &packa
return dict;
}
+PackageInfoVector QInstallerTools::createListOfRepositoryPackages(const QStringList &repositoryDirectories,
+ QStringList *packagesToFilter, FilterType filterType)
+{
+ qDebug() << "Collecting information about available repository packages...";
+
+ bool ignoreInvalidRepositories = qApp->arguments().contains(QString::fromLatin1("--ignore-invalid-repositories"));
+
+ PackageInfoVector dict;
+ QFileInfoList entries;
+ foreach (const QString &repositoryDirectory, repositoryDirectories)
+ entries.append(QFileInfo(repositoryDirectory));
+ for (QFileInfoList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it) {
+
+ qDebug() << "Process repository" << it->fileName();
+
+ QFile file(QString::fromLatin1("%1/Updates.xml").arg(it->filePath()));
+
+ QFileInfo fileInfo(file);
+ if (!fileInfo.exists()) {
+ if (ignoreInvalidRepositories) {
+ qDebug() << "- skip invalid repository";
+ continue;
+ }
+ throw QInstaller::Error(QString::fromLatin1("Repository \"%1\" does not contain a update "
+ "description (Updates.xml is missing).").arg(QDir::toNativeSeparators(it->fileName())));
+ }
+ if (!file.open(QIODevice::ReadOnly)) {
+ qDebug() << "Cannot open Updates.xml for reading:" << file.errorString();
+ continue;
+ }
+
+ QString error;
+ QDomDocument doc;
+ if (!doc.setContent(&file, &error)) {
+ qDebug().nospace() << "Cannot fetch a valid version of Updates.xml from repository "
+ << it->fileName() << ": " << error;
+ continue;
+ }
+ file.close();
+
+ const QDomElement root = doc.documentElement();
+ if (root.tagName() != QLatin1String("Updates")) {
+ throw QInstaller::Error(QCoreApplication::translate("QInstaller",
+ "Invalid content in \"%1\".").arg(QDir::toNativeSeparators(file.fileName())));
+ }
+
+ const QDomNodeList children = root.childNodes();
+ for (int i = 0; i < children.count(); ++i) {
+ const QDomElement el = children.at(i).toElement();
+ if ((!el.isNull()) && (el.tagName() == QLatin1String("PackageUpdate"))) {
+ QInstallerTools::PackageInfo info;
+
+ QDomElement c1 = el.firstChildElement(QInstaller::scName);
+ if (!c1.isNull())
+ info.name = c1.text();
+ else
+ continue;
+ if (filterType == Exclude) {
+ // Check for current package in exclude list, if found, skip it
+ if (packagesToFilter->contains(info.name)) {
+ continue;
+ }
+ } else {
+ // Check for current package in include list, if not found, skip it
+ if (!packagesToFilter->contains(info.name))
+ continue;
+ }
+ c1 = el.firstChildElement(QInstaller::scVersion);
+ if (!c1.isNull())
+ info.version = c1.text();
+ else
+ continue;
+
+ info.directory = QString::fromLatin1("%1/%2").arg(it->filePath(), info.name);
+ info.metaFile = QString::fromLatin1("%1/%3%2").arg(info.directory,
+ QString::fromLatin1("meta.7z"), info.version);
+
+ const QDomNodeList c2 = el.childNodes();
+ for (int j = 0; j < c2.count(); ++j) {
+ if (c2.at(j).toElement().tagName() == QInstaller::scDependencies)
+ info.dependencies = c2.at(j).toElement().text()
+ .split(QInstaller::commaRegExp(), QString::SkipEmptyParts);
+ else if (c2.at(j).toElement().tagName() == QInstaller::scDownloadableArchives) {
+ QStringList names = c2.at(j).toElement().text()
+ .split(QInstaller::commaRegExp(), QString::SkipEmptyParts);
+ foreach (const QString &name, names) {
+ info.copiedFiles.append(QString::fromLatin1("%1/%3%2").arg(info.directory,
+ name, info.version));
+ info.copiedFiles.append(QString::fromLatin1("%1/%3%2.sha1").arg(info.directory,
+ name, info.version));
+ }
+ }
+ }
+ QString metaString;
+ {
+ QTextStream metaStream(&metaString);
+ el.save(metaStream, 0);
+ }
+ info.metaNode = metaString;
+ dict.push_back(info);
+ qDebug() << "- it provides the package" << info.name << " - " << info.version;
+ }
+ }
+ }
+
+ return dict;
+}
+
QHash<QString, QString> QInstallerTools::buildPathToVersionMapping(const PackageInfoVector &info)
{
QHash<QString, QString> map;
@@ -569,70 +698,83 @@ void QInstallerTools::copyComponentData(const QStringList &packageDirs, const QS
.arg(name));
}
- QStringList compressedFiles;
- QStringList filesToCompress;
- foreach (const QString &packageDir, packageDirs) {
- const QDir dataDir(QString::fromLatin1("%1/%2/data").arg(packageDir, name));
- foreach (const QString &entry, dataDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files)) {
- QFileInfo fileInfo(dataDir.absoluteFilePath(entry));
- if (fileInfo.isFile() && !fileInfo.isSymLink()) {
- const QString absoluteEntryFilePath = dataDir.absoluteFilePath(entry);
- if (Lib7z::isSupportedArchive(absoluteEntryFilePath)) {
- QFile tmp(absoluteEntryFilePath);
- QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, entry, info.version);
- qDebug() << "Copying archive from" << tmp.fileName() << "to" << target;
- if (!tmp.copy(target)) {
- throw QInstaller::Error(QString::fromLatin1("Cannot copy file \"%1\" to \"%2\": %3")
- .arg(QDir::toNativeSeparators(tmp.fileName()), QDir::toNativeSeparators(target), tmp.errorString()));
+ if (info.copiedFiles.isEmpty()) {
+ QStringList compressedFiles;
+ QStringList filesToCompress;
+ foreach (const QString &packageDir, packageDirs) {
+ const QDir dataDir(QString::fromLatin1("%1/%2/data").arg(packageDir, name));
+ foreach (const QString &entry, dataDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files)) {
+ QFileInfo fileInfo(dataDir.absoluteFilePath(entry));
+ if (fileInfo.isFile() && !fileInfo.isSymLink()) {
+ const QString absoluteEntryFilePath = dataDir.absoluteFilePath(entry);
+ if (Lib7z::isSupportedArchive(absoluteEntryFilePath)) {
+ QFile tmp(absoluteEntryFilePath);
+ QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, entry, info.version);
+ qDebug() << "Copying archive from" << tmp.fileName() << "to" << target;
+ if (!tmp.copy(target)) {
+ throw QInstaller::Error(QString::fromLatin1("Cannot copy file \"%1\" to \"%2\": %3")
+ .arg(QDir::toNativeSeparators(tmp.fileName()), QDir::toNativeSeparators(target), tmp.errorString()));
+ }
+ compressedFiles.append(target);
+ } else {
+ filesToCompress.append(absoluteEntryFilePath);
}
+ } else if (fileInfo.isDir()) {
+ qDebug() << "Compressing data directory" << entry;
+ QString target = QString::fromLatin1("%1/%3%2.7z").arg(namedRepoDir, entry, info.version);
+ Lib7z::createArchive(target, QStringList() << dataDir.absoluteFilePath(entry),
+ Lib7z::QTmpFile::No);
compressedFiles.append(target);
- } else {
- filesToCompress.append(absoluteEntryFilePath);
+ } else if (fileInfo.isSymLink()) {
+ filesToCompress.append(dataDir.absoluteFilePath(entry));
}
- } else if (fileInfo.isDir()) {
- qDebug() << "Compressing data directory" << entry;
- QString target = QString::fromLatin1("%1/%3%2.7z").arg(namedRepoDir, entry, info.version);
- Lib7z::createArchive(target, QStringList() << dataDir.absoluteFilePath(entry),
- Lib7z::QTmpFile::No);
- compressedFiles.append(target);
- } else if (fileInfo.isSymLink()) {
- filesToCompress.append(dataDir.absoluteFilePath(entry));
}
}
- }
- if (!filesToCompress.isEmpty()) {
- qDebug() << "Compressing files found in data directory:" << filesToCompress;
- QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, QLatin1String("content.7z"),
- info.version);
- Lib7z::createArchive(target, filesToCompress, Lib7z::QTmpFile::No);
- compressedFiles.append(target);
- }
+ if (!filesToCompress.isEmpty()) {
+ qDebug() << "Compressing files found in data directory:" << filesToCompress;
+ QString target = QString::fromLatin1("%1/%3%2").arg(namedRepoDir, QLatin1String("content.7z"),
+ info.version);
+ Lib7z::createArchive(target, filesToCompress, Lib7z::QTmpFile::No);
+ compressedFiles.append(target);
+ }
- foreach (const QString &target, compressedFiles) {
- (*infos)[i].copiedFiles.append(target);
-
- QFile archiveFile(target);
- QFile archiveHashFile(archiveFile.fileName() + QLatin1String(".sha1"));
-
- qDebug() << "Hash is stored in" << archiveHashFile.fileName();
- qDebug() << "Creating hash of archive" << archiveFile.fileName();
-
- try {
- QInstaller::openForRead(&archiveFile);
- const QByteArray hashOfArchiveData = QInstaller::calculateHash(&archiveFile,
- QCryptographicHash::Sha1).toHex();
- archiveFile.close();
-
- QInstaller::openForWrite(&archiveHashFile);
- archiveHashFile.write(hashOfArchiveData);
- qDebug() << "Generated sha1 hash:" << hashOfArchiveData;
- (*infos)[i].copiedFiles.append(archiveHashFile.fileName());
- archiveHashFile.close();
- } catch (const QInstaller::Error &/*e*/) {
- archiveFile.close();
- archiveHashFile.close();
- throw;
+ foreach (const QString &target, compressedFiles) {
+ (*infos)[i].copiedFiles.append(target);
+
+ QFile archiveFile(target);
+ QFile archiveHashFile(archiveFile.fileName() + QLatin1String(".sha1"));
+
+ qDebug() << "Hash is stored in" << archiveHashFile.fileName();
+ qDebug() << "Creating hash of archive" << archiveFile.fileName();
+
+ try {
+ QInstaller::openForRead(&archiveFile);
+ const QByteArray hashOfArchiveData = QInstaller::calculateHash(&archiveFile,
+ QCryptographicHash::Sha1).toHex();
+ archiveFile.close();
+
+ QInstaller::openForWrite(&archiveHashFile);
+ archiveHashFile.write(hashOfArchiveData);
+ qDebug() << "Generated sha1 hash:" << hashOfArchiveData;
+ (*infos)[i].copiedFiles.append(archiveHashFile.fileName());
+ archiveHashFile.close();
+ } catch (const QInstaller::Error &/*e*/) {
+ archiveFile.close();
+ archiveHashFile.close();
+ throw;
+ }
+ }
+ } else {
+ foreach (const QString &file, (*infos)[i].copiedFiles) {
+ QFileInfo fromInfo(file);
+ QFile from(file);
+ QString target = QString::fromLatin1("%1/%2").arg(namedRepoDir, fromInfo.fileName());
+ qDebug() << "Copying file from" << from.fileName() << "to" << target;
+ if (!from.copy(target)) {
+ throw QInstaller::Error(QString::fromLatin1("Cannot copy file \"%1\" to \"%2\": %3")
+ .arg(QDir::toNativeSeparators(from.fileName()), QDir::toNativeSeparators(target), from.errorString()));
+ }
}
}
}
diff --git a/tools/common/repositorygen.h b/tools/common/repositorygen.h
index 769f48729..ead9e15be 100644
--- a/tools/common/repositorygen.h
+++ b/tools/common/repositorygen.h
@@ -44,6 +44,8 @@ struct PackageInfo
QString directory;
QStringList dependencies;
QStringList copiedFiles;
+ QString metaFile;
+ QString metaNode;
};
typedef QVector<PackageInfo> PackageInfoVector;
@@ -58,6 +60,10 @@ void copyWithException(const QString &source, const QString &target, const QStri
PackageInfoVector createListOfPackages(const QStringList &packagesDirectories, QStringList *packagesToFilter,
FilterType ftype);
+
+PackageInfoVector createListOfRepositoryPackages(const QStringList &repositoryDirectories, QStringList *packagesToFilter,
+ FilterType filterType);
+
QHash<QString, QString> buildPathToVersionMapping(const PackageInfoVector &info);
void compressMetaDirectories(const QString &repoDir, const QString &baseDir,
diff --git a/tools/repogen/repogen.cpp b/tools/repogen/repogen.cpp
index 67184c49e..82ea752ca 100644
--- a/tools/repogen/repogen.cpp
+++ b/tools/repogen/repogen.cpp
@@ -95,6 +95,7 @@ int main(int argc, char** argv)
QStringList filteredPackages;
bool updateExistingRepository = false;
QStringList packagesDirectories;
+ QStringList repositoryDirectories;
QInstallerTools::FilterType filterType = QInstallerTools::Exclude;
bool remove = false;
bool updateExistingRepositoryWithNewComponents = false;
@@ -156,6 +157,19 @@ int main(int argc, char** argv)
packagesDirectories.append(args.first());
args.removeFirst();
+ } else if (args.first() == QLatin1String("--repository")) {
+ args.removeFirst();
+ if (args.isEmpty()) {
+ return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller",
+ "Error: Repository parameter missing argument"));
+ }
+
+ if (!QFileInfo(args.first()).exists()) {
+ return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller",
+ "Error: Only local filesystem repositories now supported"));
+ }
+ repositoryDirectories.append(args.first());
+ args.removeFirst();
} else if (args.first() == QLatin1String("--ignore-translations")
|| args.first() == QLatin1String("--ignore-invalid-packages")) {
args.removeFirst();
@@ -168,7 +182,7 @@ int main(int argc, char** argv)
}
}
- if (packagesDirectories.isEmpty() || (args.count() != 1)) {
+ if ((packagesDirectories.isEmpty() && repositoryDirectories.isEmpty()) || (args.count() != 1)) {
printUsage();
return 1;
}
@@ -190,8 +204,15 @@ int main(int argc, char** argv)
"Repository target directory \"%1\" already exists.").arg(QDir::toNativeSeparators(repositoryDir)));
}
- QInstallerTools::PackageInfoVector packages = QInstallerTools::createListOfPackages(packagesDirectories,
+ QInstallerTools::PackageInfoVector packages;
+
+ QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages(repositoryDirectories,
+ &filteredPackages, filterType);
+ packages.append(precompressedPackages);
+
+ QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(packagesDirectories,
&filteredPackages, filterType);
+ packages.append(preparedPackages);
if (updateExistingRepositoryWithNewComponents) {
QDomDocument doc;
@@ -251,7 +272,10 @@ int main(int argc, char** argv)
QTemporaryDir tmp;
tmp.setAutoRemove(false);
tmpMetaDir = tmp.path();
- QInstallerTools::copyComponentData(packagesDirectories, repositoryDir, &packages);
+ QStringList directories;
+ directories.append(packagesDirectories);
+ directories.append(repositoryDirectories);
+ QInstallerTools::copyComponentData(directories, repositoryDir, &packages);
QInstallerTools::copyMetaData(tmpMetaDir, repositoryDir, packages, QLatin1String("{AnyApplication}"),
QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION)));
QInstallerTools::compressMetaDirectories(tmpMetaDir, tmpMetaDir, pathToVersionMapping);