summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorkh1 <karsten.heimrich@digia.com>2014-08-29 12:56:06 +0200
committerKarsten Heimrich <karsten.heimrich@digia.com>2014-09-04 10:41:53 +0200
commit77b1e168202e8781ddfe5c06fc1ceaea5934e855 (patch)
treeffcd3040a42ffd5086b34a034d042b0d65143aa3 /src
parente9e26f11d78def8ad8cb8f1864c61d88e3a1f0be (diff)
Split and implement new installer base, update checker.
Based on the former patches, split the installer base into its own class. Use the new binary content read functions. Adjust uses to match the new classes. Adjust installer base /update checker signature and inheritance. Remove all now superfluous functions from binary content. Core engine instantiates the operations now, makes reading and writing more generic. Move product key check into QInstaller namespace. Make use of the new command line parser. Change-Id: I00aff79085b69ce627906881b43f374681ea7e91 Reviewed-by: Kai Koehne <kai.koehne@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/libs/installer/binarycontent.cpp311
-rw-r--r--src/libs/installer/binarycontent.h24
-rw-r--r--src/libs/installer/packagemanagercore.cpp4
-rw-r--r--src/libs/installer/packagemanagercore.h5
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp19
-rw-r--r--src/libs/installer/packagemanagercore_p.h2
-rw-r--r--src/libs/installer/productkeycheck.cpp4
-rw-r--r--src/libs/installer/productkeycheck.h15
-rw-r--r--src/sdk/installerbase.cpp546
-rw-r--r--src/sdk/installerbase.h70
-rw-r--r--src/sdk/main.cpp193
-rw-r--r--src/sdk/sdk.pro14
-rw-r--r--src/sdk/sdkapp.h87
-rw-r--r--src/sdk/updatechecker.cpp114
-rw-r--r--src/sdk/updatechecker.h11
15 files changed, 655 insertions, 764 deletions
diff --git a/src/libs/installer/binarycontent.cpp b/src/libs/installer/binarycontent.cpp
index 6280134d9..25032177b 100644
--- a/src/libs/installer/binarycontent.cpp
+++ b/src/libs/installer/binarycontent.cpp
@@ -41,16 +41,9 @@
#include "binarycontent.h"
-#include "binaryformat.h"
-#include "binaryformatenginehandler.h"
#include "errors.h"
#include "fileio.h"
#include "fileutils.h"
-#include "kdupdaterupdateoperationfactory.h"
-#include "utils.h"
-
-#include <QFile>
-#include <QResource>
namespace QInstaller {
@@ -101,124 +94,6 @@ qint64 BinaryContent::findMagicCookie(QFile *in, quint64 magicCookie)
}
/*!
- \internal
- Registers the resource found at \a segment within \a file into the Qt resource system.
-*/
-static QByteArray addResourceFromBinary(QFile* file, const Range<qint64> &segment)
-{
- if (segment.length() <= 0)
- return 0;
-
- if (!file->seek(segment.start())) {
- throw Error(QCoreApplication::translate("BinaryContent",
- "Could not seek to in-binary resource. (offset: %1, length: %2)")
- .arg(QString::number(segment.start()), QString::number(segment.length())));
- }
-
- QByteArray ba = QInstaller::retrieveData(file, segment.length());
- if (!QResource::registerResource((const uchar*) ba.constData(), QLatin1String(":/metadata"))) {
- throw Error(QCoreApplication::translate("BinaryContent",
- "Could not register in-binary resource."));
- }
- return ba;
-}
-
-
-// -- Private
-
-class BinaryContent::Private : public QSharedData
-{
-public:
- Private();
- explicit Private(const QString &path);
- Private(const Private &other);
- ~Private();
-
- qint64 m_magicMarker;
- qint64 m_dataBlockStart;
-
- QSharedPointer<QFile> m_appBinary;
- QSharedPointer<QFile> m_binaryDataFile;
-
- QList<Operation *> m_performedOperations;
- QList<QPair<QString, QString> > m_performedOperationsData;
-
- QVector<QByteArray> m_resourceMappings;
- QVector<Range<qint64> > m_metadataResourceSegments;
-};
-
-
-BinaryContent::Private::Private()
- : m_magicMarker(Q_INT64_C(0))
- , m_dataBlockStart(Q_INT64_C(0))
- , m_appBinary(0)
- , m_binaryDataFile(0)
-{}
-
-BinaryContent::Private::Private(const QString &path)
- : m_magicMarker(Q_INT64_C(0))
- , m_dataBlockStart(Q_INT64_C(0))
- , m_appBinary(new QFile(path))
- , m_binaryDataFile(0)
-{}
-
-BinaryContent::Private::Private(const Private &other)
- : QSharedData(other)
- , m_magicMarker(other.m_magicMarker)
- , m_dataBlockStart(other.m_dataBlockStart)
- , m_appBinary(other.m_appBinary)
- , m_binaryDataFile(other.m_binaryDataFile)
- , m_performedOperations(other.m_performedOperations)
- , m_performedOperationsData(other.m_performedOperationsData)
- , m_resourceMappings(other.m_resourceMappings)
- , m_metadataResourceSegments(other.m_metadataResourceSegments)
-{}
-
-BinaryContent::Private::~Private()
-{
- foreach (const QByteArray &rccData, m_resourceMappings)
- QResource::unregisterResource((const uchar*) rccData.constData(), QLatin1String(":/metadata"));
- m_resourceMappings.clear();
-}
-
-
-// -- BinaryContent
-
-BinaryContent::BinaryContent()
- : d(new Private)
-{}
-
-BinaryContent::~BinaryContent()
-{}
-
-BinaryContent::BinaryContent(const QString &path)
- : d(new Private(path))
-{}
-
-BinaryContent::BinaryContent(const BinaryContent &rhs)
- : d(rhs.d)
-{}
-
-BinaryContent &BinaryContent::operator=(const BinaryContent &rhs)
-{
- if (this != &rhs)
- d = rhs.d;
- return *this;
-}
-
-/*!
- Reads binary content stored in the passed application binary. Maps the embedded resources into
- memory and instantiates performed operations if available.
-*/
-BinaryContent BinaryContent::readAndRegisterFromBinary(const QString &path)
-{
- BinaryContent c = BinaryContent::readFromBinary(path);
- c.registerEmbeddedQResources();
- c.registerPerformedOperations();
- return c;
-}
-
-/*!
* \class QInstaller::BinaryContent
*
* BinaryContent handles binary information embedded into executables.
@@ -288,41 +163,6 @@ BinaryContent BinaryContent::readAndRegisterFromBinary(const QString &path)
* \endverbatim
*/
-BinaryContent BinaryContent::readFromBinary(const QString &path)
-{
- BinaryContent c(path);
-
- // Try to read the binary layout of the calling application. We need to figure out
- // if we are in installer or an unistaller (maintenance, package manager, updater) binary.
- QInstaller::openForRead(c.d->m_appBinary.data());
- quint64 cookiePos = findMagicCookie(c.d->m_appBinary.data(), BinaryContent::MagicCookie);
- if (!c.d->m_appBinary->seek(cookiePos - sizeof(qint64))) { // seek to read the marker
- throw Error(QCoreApplication::translate("BinaryContent",
- "Could not seek to %1 to read the magic marker.").arg(cookiePos - sizeof(qint64)));
- }
- const qint64 magicMarker = QInstaller::retrieveInt64(c.d->m_appBinary.data());
-
- if (magicMarker != MagicInstallerMarker) {
- // We are not an installer, so we need to read the data from the .dat file.
-
- QFileInfo fi(path);
- QString bundlePath; // On OSX it's not inside the bundle, deserves TODO.
- if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath))
- fi.setFile(bundlePath);
-
- c.d->m_binaryDataFile.reset(new QFile(fi.absolutePath() + QLatin1Char('/') + fi.baseName()
- + QLatin1String(".dat")));
- QInstaller::openForRead(c.d->m_binaryDataFile.data());
- readBinaryData(c, c.d->m_binaryDataFile, binaryLayout(c.d->m_binaryDataFile.data(),
- BinaryContent::MagicCookieDat));
- } else {
- // We are an installer, all data is appended to our binary itself.
- readBinaryData(c, c.d->m_appBinary, binaryLayout(c.d->m_appBinary.data(),
- BinaryContent::MagicCookie));
- }
- return c;
-}
-
/* static */
BinaryLayout BinaryContent::binaryLayout(QFile *file, quint64 magicCookie)
{
@@ -370,157 +210,6 @@ BinaryLayout BinaryContent::binaryLayout(QFile *file, quint64 magicCookie)
return layout;
}
-/* static */
-void BinaryContent::readBinaryData(BinaryContent &content, const QSharedPointer<QFile> &file,
- const BinaryLayout &layout)
-{
- content.d->m_magicMarker = layout.magicMarker;
- content.d->m_metadataResourceSegments = layout.metadataResourceSegments;
-
- const qint64 dataBlockStart = layout.endOfData - layout.dataBlockSize;
- const qint64 operationsStart = layout.operationsStart + dataBlockStart;
- if (!file->seek(operationsStart))
- throw Error(QCoreApplication::translate("BinaryContent", "Could not seek to operation list."));
-
- const qint64 operationsCount = QInstaller::retrieveInt64(file.data());
- qDebug() << "Number of operations:" << operationsCount;
-
- for (int i = 0; i < operationsCount; ++i) {
- const QString name = QInstaller::retrieveString(file.data());
- const QString data = QInstaller::retrieveString(file.data());
- content.d->m_performedOperationsData.append(qMakePair(name, data));
- }
-
- // seek to the position of the resource collections segment info
- const qint64 resourceOffsetAndLengtSize = 2 * sizeof(qint64);
- const qint64 resourceSectionSize = resourceOffsetAndLengtSize * layout.resourceCount;
- qint64 offset = layout.endOfData - layout.indexSize - resourceSectionSize
- - resourceOffsetAndLengtSize;
- if (!file->seek(offset)) {
- throw Error(QCoreApplication::translate("BinaryContent",
- "Could not seek to read the resource collection segment info."));
- }
-
- offset = QInstaller::retrieveInt64(file.data()) + dataBlockStart;
- if (!file->seek(offset)) {
- throw Error(QCoreApplication::translate("BinaryContent", "Could not seek to start "
- "position of resource collection block."));
- }
-
- ResourceCollectionManager collectionManager;
- collectionManager.read(file, dataBlockStart);
- BinaryFormatEngineHandler::instance()->registerResources(collectionManager.collections());
-
- if (!QInstaller::isVerbose())
- return;
-
- const QList<ResourceCollection> collections = collectionManager.collections();
- qDebug() << "Number of resource collections loaded:" << collections.count();
- foreach (const ResourceCollection &collection, collections) {
- const QList<QSharedPointer<Resource> > resources = collection.resources();
- qDebug() << collection.name().data() << "loaded...";
- QStringList resourcesWithSize;
- foreach (const QSharedPointer<Resource> &resource, resources) {
- resourcesWithSize.append(QString::fromLatin1("%1 - %2")
- .arg(QString::fromUtf8(resource->name()), humanReadableSize(resource->size())));
- }
- if (!resourcesWithSize.isEmpty()) {
- qDebug() << " - " << resources.count() << "resources: "
- << qPrintable(resourcesWithSize.join(QLatin1String("; ")));
- }
- }
-}
-
-/*!
- Registers already performed operations.
-*/
-int BinaryContent::registerPerformedOperations()
-{
- if (d->m_performedOperations.count() > 0)
- return d->m_performedOperations.count();
-
- for (int i = 0; i < d->m_performedOperationsData.count(); ++i) {
- const QPair<QString, QString> opPair = d->m_performedOperationsData.at(i);
- QScopedPointer<Operation> op(KDUpdater::UpdateOperationFactory::instance().create(opPair.first));
- if (op.isNull()) {
- qWarning() << QString::fromLatin1("Failed to load unknown operation %1").arg(opPair.first);
- continue;
- }
-
- if (!op->fromXml(opPair.second)) {
- qWarning() << "Failed to load XML for operation:" << opPair.first;
- continue;
- }
- d->m_performedOperations.append(op.take());
- }
- return d->m_performedOperations.count();
-}
-
-/*!
- Returns the operations performed during installation. Returns an empty list if no operations
- are instantiated, performed or the binary is the installer application.
-*/
-OperationList BinaryContent::performedOperations() const
-{
- return d->m_performedOperations;
-}
-
-/*!
- Returns the magic marker found in the binary. Returns 0 if no marker has been found.
-*/
-qint64 BinaryContent::magicMarker() const
-{
- return d->m_magicMarker;
-}
-
-/*!
- Registers the Qt resources embedded in this binary.
-*/
-int BinaryContent::registerEmbeddedQResources()
-{
- if (d->m_resourceMappings.count() > 0)
- return d->m_resourceMappings.count();
-
- const bool hasBinaryDataFile = !d->m_binaryDataFile.isNull();
- QFile *const data = hasBinaryDataFile ? d->m_binaryDataFile.data() : d->m_appBinary.data();
- if (data != 0 && !data->isOpen() && !data->open(QIODevice::ReadOnly)) {
- throw Error(QCoreApplication::translate("BinaryContent", "Could not open binary %1: %2")
- .arg(data->fileName(), data->errorString()));
- }
-
- foreach (const Range<qint64> &i, d->m_metadataResourceSegments)
- d->m_resourceMappings.append(addResourceFromBinary(data, i));
-
- d->m_appBinary.clear();
- if (hasBinaryDataFile)
- d->m_binaryDataFile.clear();
-
- return d->m_resourceMappings.count();
-}
-
-/*!
- Registers the passed file as default resource content. If the embedded resources are already
- mapped into memory, it will replace the first with the new content.
-*/
-void BinaryContent::registerAsDefaultQResource(const QString &path)
-{
- QFile resource(path);
- bool success = resource.open(QIODevice::ReadOnly);
- if (success && (d->m_resourceMappings.count() > 0)) {
- success = QResource::unregisterResource((const uchar*) d->m_resourceMappings.first()
- .constData(), QLatin1String(":/metadata"));
- if (success)
- d->m_resourceMappings.remove(0);
- }
-
- if (success) {
- d->m_resourceMappings.prepend(addResourceFromBinary(&resource,
- Range<qint64>::fromStartAndEnd(0, resource.size())));
- } else {
- qWarning() << QString::fromLatin1("Could not register '%1' as default resource.").arg(path);
- }
-}
-
void BinaryContent::readBinaryContent(const QSharedPointer<QFile> &in,
ResourceCollection *metaResources, QList<OperationBlob> *operations,
ResourceCollectionManager *manager, qint64 *magicMarker, quint64 magicCookie)
diff --git a/src/libs/installer/binarycontent.h b/src/libs/installer/binarycontent.h
index edbf54f07..2efe3d0fc 100644
--- a/src/libs/installer/binarycontent.h
+++ b/src/libs/installer/binarycontent.h
@@ -69,6 +69,7 @@ struct BinaryLayout
class INSTALLER_EXPORT BinaryContent
{
public:
+ // the marker to distinguish what kind of binary
static const qint64 MagicInstallerMarker = 0x12023233UL;
static const qint64 MagicUninstallerMarker = 0x12023234UL;
@@ -79,24 +80,9 @@ public:
static const quint64 MagicCookie = 0xc2630a1c99d668f8LL; // binary
static const quint64 MagicCookieDat = 0xc2630a1c99d668f9LL; // data
- BinaryContent();
- ~BinaryContent();
-
- BinaryContent(const BinaryContent &rhs);
- BinaryContent &operator=(const BinaryContent &rhs);
-
- static BinaryContent readFromBinary(const QString &path);
- static BinaryContent readAndRegisterFromBinary(const QString &path);
static qint64 findMagicCookie(QFile *file, quint64 magicCookie);
static BinaryLayout binaryLayout(QFile *file, quint64 magicCookie);
- int registerPerformedOperations();
- OperationList performedOperations() const;
-
- qint64 magicMarker() const;
- int registerEmbeddedQResources();
- void registerAsDefaultQResource(const QString &path);
-
static void readBinaryContent(const QSharedPointer<QFile> &in,
ResourceCollection *metaResources,
QList<OperationBlob> *operations,
@@ -110,14 +96,6 @@ public:
const ResourceCollectionManager &manager,
qint64 magicMarker,
quint64 magicCookie);
-private:
- explicit BinaryContent(const QString &path);
- static void readBinaryData(BinaryContent &content, const QSharedPointer<QFile> &file,
- const BinaryLayout &layout);
-
-private:
- class Private;
- QSharedDataPointer<Private> d;
};
} // namespace QInstaller
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index ad14a137e..6abfdb81c 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -749,8 +749,8 @@ PackageManagerCore::PackageManagerCore()
qRegisterMetaType<QInstaller::PackageManagerCore::WizardPage>("QInstaller::PackageManagerCore::WizardPage");
}
-PackageManagerCore::PackageManagerCore(qint64 magicmaker, const OperationList &performedOperations)
- : d(new PackageManagerCorePrivate(this, magicmaker, performedOperations))
+PackageManagerCore::PackageManagerCore(qint64 magicmaker, const QList<OperationBlob> &operations)
+ : d(new PackageManagerCorePrivate(this, magicmaker, operations))
{
qRegisterMetaType<QInstaller::PackageManagerCore::Status>("QInstaller::PackageManagerCore::Status");
qRegisterMetaType<QInstaller::PackageManagerCore::WizardPage>("QInstaller::PackageManagerCore::WizardPage");
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index b3c5013cc..d8bcc86a6 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.h
@@ -41,6 +41,7 @@
#ifndef PACKAGEMANAGERCORE_H
#define PACKAGEMANAGERCORE_H
+#include "binaryformat.h"
#include "repository.h"
#include "qinstallerglobal.h"
@@ -72,8 +73,8 @@ class INSTALLER_EXPORT PackageManagerCore : public QObject
Q_PROPERTY(int status READ status NOTIFY statusChanged)
public:
- explicit PackageManagerCore();
- explicit PackageManagerCore(qint64 magicmaker, const OperationList &oldOperations = OperationList());
+ PackageManagerCore();
+ PackageManagerCore(qint64 magicmaker, const QList<OperationBlob> &ops);
~PackageManagerCore();
// status
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index b2d7d7d83..c9cd458a6 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -203,7 +203,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
}
PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker,
- const OperationList &performedOperations)
+ const QList<OperationBlob> &performedOperations)
: m_updateFinder(0)
, m_updaterApplication(new DummyConfigurationInterface)
, m_status(PackageManagerCore::Unfinished)
@@ -212,7 +212,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_launchedAsRoot(AdminAuthorization::hasAdminRights())
, m_completeUninstall(false)
, m_needToWriteMaintenanceTool(false)
- , m_performedOperationsOld(performedOperations)
, m_dependsOnLocalInstallerBinary(false)
, m_core(core)
, m_updates(false)
@@ -228,6 +227,22 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_guiObject(0)
, m_remoteFileEngineHandler(new RemoteFileEngineHandler)
{
+ foreach (const OperationBlob &operation, performedOperations) {
+ QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance()
+ .create(operation.name));
+ if (op.isNull()) {
+ qWarning() << QString::fromLatin1("Failed to load unknown operation %1")
+ .arg(operation.name);
+ continue;
+ }
+
+ if (!op->fromXml(operation.xml)) {
+ qWarning() << "Failed to load XML for operation:" << operation.name;
+ continue;
+ }
+ m_performedOperationsOld.append(op.take());
+ }
+
// Creates and initializes a remote client, makes us get admin rights for QFile, QSettings
// and QProcess operations. Init needs to called before we can get the real authorization key.
int port = 30000 + qrand() % 1000;
diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h
index 3b2655276..29da8cb54 100644
--- a/src/libs/installer/packagemanagercore_p.h
+++ b/src/libs/installer/packagemanagercore_p.h
@@ -106,7 +106,7 @@ public:
explicit PackageManagerCorePrivate(PackageManagerCore *core);
explicit PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker,
- const OperationList &performedOperations);
+ const QList<OperationBlob> &performedOperations);
~PackageManagerCorePrivate();
static bool isProcessRunning(const QString &name, const QList<ProcessInfo> &processes);
diff --git a/src/libs/installer/productkeycheck.cpp b/src/libs/installer/productkeycheck.cpp
index 232dbb719..46a568625 100644
--- a/src/libs/installer/productkeycheck.cpp
+++ b/src/libs/installer/productkeycheck.cpp
@@ -30,6 +30,8 @@
#include "productkeycheck.h"
#include "packagemanagercore.h"
+namespace QInstaller {
+
class ProductKeyCheckPrivate
{
};
@@ -91,3 +93,5 @@ QList<int> ProductKeyCheck::registeredPages() const
{
return QList<int>();
}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/productkeycheck.h b/src/libs/installer/productkeycheck.h
index 3df747f37..02e8a76a5 100644
--- a/src/libs/installer/productkeycheck.h
+++ b/src/libs/installer/productkeycheck.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (c) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (c) 2013-2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Installer Framework
@@ -35,18 +35,18 @@
#include <QString>
namespace QInstaller{
- class PackageManagerCore;
- class Repository;
-}
-
+class PackageManagerCore;
class ProductKeyCheckPrivate;
+class Repository;
class INSTALLER_EXPORT ProductKeyCheck
{
+ Q_DISABLE_COPY(ProductKeyCheck)
+
public:
~ProductKeyCheck();
static ProductKeyCheck *instance();
- void init(QInstaller::PackageManagerCore *core);
+ void init(PackageManagerCore *core);
// was validLicense
bool hasValidKey();
@@ -67,7 +67,8 @@ public:
private:
ProductKeyCheck();
ProductKeyCheckPrivate *const d;
- Q_DISABLE_COPY(ProductKeyCheck)
};
+} // namespace QInstaller
+
#endif // PRODUCTKEYCHECK_H
diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp
index 73831bed1..4d13339cd 100644
--- a/src/sdk/installerbase.cpp
+++ b/src/sdk/installerbase.cpp
@@ -39,417 +39,263 @@
**
**************************************************************************/
-#include "console.h"
+#include "constants.h"
+#include "commandlineparser.h"
+#include "installerbase.h"
#include "installerbasecommons.h"
-#include "sdkapp.h"
#include "tabcontroller.h"
-#include "updatechecker.h"
-#include <binarycontent.h>
+#include <binaryformatenginehandler.h>
+#include <copydirectoryoperation.h>
#include <errors.h>
#include <init.h>
+#include <kdupdaterupdateoperations.h>
#include <messageboxhandler.h>
+#include <packagemanagercore.h>
+#include <qprocesswrapper.h>
#include <productkeycheck.h>
-#include <remoteserver.h>
#include <settings.h>
#include <utils.h>
-#include <kdselfrestarter.h>
#include <kdrunoncechecker.h>
#include <kdupdaterfiledownloaderfactory.h>
-#include <QCommandLineParser>
#include <QDirIterator>
-#include <QNetworkProxyFactory>
+#include <QTemporaryFile>
#include <QTranslator>
#include <iostream>
-#define QUOTE_(x) #x
-#define QUOTE(x) QUOTE_(x)
-#define VERSION "IFW Version: \"" QUOTE(IFW_VERSION) "\""
-#define BUILDDATE "Build date: " QUOTE(__DATE__)
-#define SHA "Installer Framework SHA1: \"" QUOTE(_GIT_SHA1_) "\""
-static const char PLACEHOLDER[32] = "MY_InstallerCreateDateTime_MY";
-
-using namespace QInstaller;
-
-static QStringList repositories(const QString &list)
+InstallerBase::InstallerBase(int &argc, char *argv[])
+ : SDKApp<QApplication>(argc, argv)
+ , m_core(0)
{
- const QStringList items = list.split(QLatin1Char(','), QString::SkipEmptyParts);
- foreach (const QString &item, items)
- qDebug() << "Adding custom repository:" << item;
- return items;
+ QInstaller::init(); // register custom operations
}
-// -- main
-
-int main(int argc, char *argv[])
+InstallerBase::~InstallerBase()
{
-// increase maximum numbers of file descriptors
-#if defined (Q_OS_OSX)
- struct rlimit rl;
- getrlimit(RLIMIT_NOFILE, &rl);
- rl.rlim_cur = qMin((rlim_t)OPEN_MAX, rl.rlim_max);
- setrlimit(RLIMIT_NOFILE, &rl);
-#endif
-
- qsrand(QDateTime::currentDateTime().toTime_t());
-
- QCommandLineParser parser;
- QCommandLineOption help = parser.addHelpOption();
-
- QCommandLineOption version(QLatin1String("version"),
- QLatin1String("Displays version information."));
- parser.addOption(version);
-
- QCommandLineOption verbose(QStringList() << QLatin1String("v") << QLatin1String("verbose"),
- QLatin1String("Verbose mode. Prints out more information."));
- parser.addOption(verbose);
-
- QCommandLineOption proxy(QLatin1String("proxy"),
- QLatin1String("Use system proxy on Windows and OS X. This option has no effect on Linux."));
- parser.addOption(proxy);
-
- QCommandLineOption script(QLatin1String("script"),
- QLatin1String("Execute the script given as argument."), QLatin1String("file"));
- parser.addOption(script);
-
- QCommandLineOption checkUpdates(QLatin1String("checkupdates"),
- QLatin1String("Check for updates and return an XML description."));
- parser.addOption(checkUpdates);
-
- QCommandLineOption updater(QLatin1String("updater"),
- QLatin1String("Start application in updater mode."));
- parser.addOption(updater);
-
- QCommandLineOption pkgManager(QLatin1String("manage-packages"),
- QLatin1String("Start application in package manager mode."));
- parser.addOption(pkgManager);
-
- QCommandLineOption noForce(QLatin1String("no-force-installations"),
- QLatin1String("Allow deselection of components that are marked as forced."));
- parser.addOption(noForce);
-
- QCommandLineOption showVirtuals(QLatin1String("show-virtual-components"),
- QLatin1String("Show virtual components in installer and package manager."));
- parser.addOption(showVirtuals);
-
- QCommandLineOption offlineRepo(QLatin1String("create-offline-repository"), QLatin1String(
- "Create a local repository inside the installation directory. This option has no effect "
- "on online installer's"));
- parser.addOption(offlineRepo);
-
- QCommandLineOption addRepo(QLatin1String("addRepository"),
- QLatin1String("Add a local or remote repository to the list of user defined repositories."),
- QLatin1String("URI,..."));
- parser.addOption(addRepo);
-
- QCommandLineOption addTmpRepo(QLatin1String("addTempRepository"), QLatin1String(
- "Add a local or remote repository to the list of temporary available repositories."),
- QLatin1String("URI,..."));
- parser.addOption(addTmpRepo);
-
- QCommandLineOption setTmpRepo(QLatin1String("setTempRepository"),
- QLatin1String("Set a local or remote repository as temporary repository, it is the only "
- "one used during fetch.\nNote: URI must be prefixed with the protocol, i.e. file:///, "
- "https://, http:// or ftp://."), QLatin1String("URI,..."));
- parser.addOption(setTmpRepo);
-
- QCommandLineOption startServer(QLatin1String("startserver"), QLatin1String("Starts the "
- "application as headless process waiting for commands to execute."),
- QLatin1String("port,key"));
- parser.addOption(startServer);
-
- parser.addPositionalArgument(QLatin1String("Key=Value"),
- QLatin1String("Key Value pair to be set."));
-
- // We need to start either a command line application or a GUI application. Since we
- // fail doing so at least on Linux while parsing the argument using a core application
- // object and later starting the GUI application, we now parse the arguments first.
- parser.parse(QInstaller::parseCommandLineArgs(argc, argv));
-
- QStringList mutually;
- if (parser.isSet(checkUpdates))
- mutually << checkUpdates.names();
- if (parser.isSet(updater))
- mutually << updater.names();
- if (parser.isSet(pkgManager))
- mutually << pkgManager.names();
-
- if (parser.isSet(help) || parser.isSet(version) || (mutually.count() > 1)) {
- Console c;
- QCoreApplication app(argc, argv);
-
- if (parser.isSet(version)) {
- std::cout << VERSION << std::endl << BUILDDATE << std::endl << SHA << std::endl;
- const QDateTime dateTime = QDateTime::fromString(QLatin1String(PLACEHOLDER),
- QLatin1String("yyyy-MM-dd - HH:mm:ss"));
- if (dateTime.isValid())
- std::cout << "Installer creation time: " << PLACEHOLDER << std::endl;
- return EXIT_SUCCESS;
- }
-
- if (mutually.count() > 1) {
- std::cerr << qPrintable(QString::fromLatin1("The following options are mutually "
- "exclusive: %1.").arg(mutually.join(QLatin1String(", ")))) << std::endl;
- }
+ delete m_core;
+}
- std::cout << qPrintable(parser.helpText()) << std::endl;
- return parser.isSet(help) ? EXIT_SUCCESS : EXIT_FAILURE;
+int InstallerBase::run()
+{
+ KDRunOnceChecker runCheck(QLatin1String("lockmyApp1234865.lock"));
+ if (runCheck.isRunning(KDRunOnceChecker::ProcessList)
+ || runCheck.isRunning(KDRunOnceChecker::Lockfile)) {
+ QInstaller::MessageBoxHandler::information(0, QLatin1String("AlreadyRunning"),
+ QString::fromLatin1("Waiting for %1").arg(qAppName()),
+ QString::fromLatin1("Another %1 instance is already running. Wait "
+ "until it finishes, close it, or restart your system.").arg(qAppName()));
+ return EXIT_FAILURE;
}
- if (parser.isSet(startServer)) {
- const QString argument = parser.value(startServer);
- const QString port = argument.section(QLatin1Char(','), 0, 0);
- const QString key = argument.section(QLatin1Char(','), 1, 1);
-
- QStringList missing;
- if (port.isEmpty())
- missing << QLatin1String("Port");
- if (key.isEmpty())
- missing << QLatin1String("Key");
-
- SDKApp<QCoreApplication> app(argc, argv);
- if (missing.count()) {
- Console c;
- std::cerr << qPrintable(QString::fromLatin1("Missing argument(s) for option "
- "'startserver': %2").arg(missing.join(QLatin1String(", ")))) << std::endl;
- std::cout << qPrintable(parser.helpText()) << std::endl;
- return EXIT_FAILURE;
- }
-
- RemoteServer *server = new RemoteServer;
- QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()));
- server->init(port.toInt(), QHostAddress::LocalHost, Protocol::Mode::Release);
- server->setAuthorizationKey(key);
- server->start();
- return app.exec();
+ QString fileName = datFile(binaryFile());
+ quint64 cookie = QInstaller::BinaryContent::MagicCookieDat;
+ if (fileName.isEmpty()) {
+ fileName = binaryFile();
+ cookie = QInstaller::BinaryContent::MagicCookie;
}
- try {
- QScopedPointer<Console> console;
- if (parser.isSet(verbose)) {
- console.reset(new Console);
- QInstaller::setVerbose(parser.isSet(verbose));
- }
-
- // On Windows we need the console window from above, we are a GUI application.
- const QStringList unknownOptionNames = parser.unknownOptionNames();
- if (!unknownOptionNames.isEmpty()) {
- const QString options = unknownOptionNames.join(QLatin1String(", "));
- std::cerr << "Unknown option: " << qPrintable(options) << std::endl;
- }
+ QSharedPointer<QFile> binary(new QFile(fileName));
+ QInstaller::openForRead(binary.data());
+
+ qint64 magicMarker;
+ QInstaller::ResourceCollection resources;
+ QInstaller::ResourceCollectionManager manager;
+ QList<QInstaller::OperationBlob> oldOperations;
+ QInstaller::BinaryContent::readBinaryContent(binary, &resources, &oldOperations, &manager,
+ &magicMarker, cookie);
+
+ if (QInstaller::isVerbose()) {
+ using namespace std;
+ cout << "Language:" << QLocale().uiLanguages().value(0,
+ QLatin1String("No UI language set")).constData() << endl;
+ cout << "Arguments: " << arguments().join(QLatin1String(", ")).constData() << endl;
+ }
- if (parser.isSet(proxy)) {
- // Make sure we honor the system's proxy settings
-#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
- QUrl proxyUrl(QString::fromLatin1(qgetenv("http_proxy")));
- if (proxyUrl.isValid()) {
- QNetworkProxy proxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyUrl.port(),
- proxyUrl.userName(), proxyUrl.password());
- QNetworkProxy::setApplicationProxy(proxy);
- }
-#else
- QNetworkProxyFactory::setUseSystemConfiguration(true);
-#endif
- }
+ registerMetaResources(resources); // the base class will unregister the resources
+ QInstaller::BinaryFormatEngineHandler::instance()->registerResources(manager.collections());
- if (parser.isSet(checkUpdates))
- return UpdateChecker().check(argc, argv);
+ if (QInstaller::isVerbose())
+ dumpResourceTree();
- SDKApp<QApplication> app(argc, argv);
- KDRunOnceChecker runCheck(QLatin1String("lockmyApp1234865.lock"));
+ // instantiate the installer we are actually going to use
+ m_core = new QInstaller::PackageManagerCore(magicMarker, oldOperations);
+ QInstaller::ProductKeyCheck::instance()->init(m_core);
- if (runCheck.isRunning(KDRunOnceChecker::ProcessList)
- || runCheck.isRunning(KDRunOnceChecker::Lockfile)) {
- QInstaller::MessageBoxHandler::information(0, QLatin1String("AlreadyRunning"),
- QString::fromLatin1("Waiting for %1").arg(qAppName()),
- QString::fromLatin1("Another %1 instance is already running. Wait "
- "until it finishes, close it, or restart your system.").arg(qAppName()));
- return EXIT_FAILURE;
- }
+ // We can close the binary file if we are an online installer or no installer at all, cause no
+ // embedded archives exist inside the component index. Keeps the .dat file unlocked on Windows.
+ if ((!m_core->isInstaller()) || (!m_core->isOfflineOnly()))
+ binary->close();
- const KDSelfRestarter restarter(argc, argv);
- QInstaller::init(); // register custom operations
+ CommandLineParser parser;
+ parser.parse(arguments());
- if (QInstaller::isVerbose()) {
- qDebug() << VERSION;
- qDebug() << "Arguments:" << app.arguments();
- qDebug() << "Language: " << QLocale().uiLanguages().value(0,
- QLatin1String("No UI language set"));
- }
+ QString controlScript;
+ if (parser.isSet(QLatin1String(CommandLineOptions::Script))) {
+ controlScript = parser.value(QLatin1String(CommandLineOptions::Script));
+ if (!QFileInfo(controlScript).exists())
+ throw QInstaller::Error(QLatin1String("Script file does not exist."));
+ }
- BinaryContent content = BinaryContent::readAndRegisterFromBinary(app.binaryFile());
+ if (parser.isSet(QLatin1String(CommandLineOptions::Proxy))) {
+ m_core->settings().setProxyType(QInstaller::Settings::SystemProxy);
+ KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory());
+ }
- // instantiate the installer we are actually going to use
- PackageManagerCore core(content.magicMarker(), content.performedOperations());
- ProductKeyCheck::instance()->init(&core);
+ if (parser.isSet(QLatin1String(CommandLineOptions::ShowVirtualComponents))) {
+ QFont f;
+ f.setItalic(true);
+ QInstaller::PackageManagerCore::setVirtualComponentsFont(f);
+ QInstaller::PackageManagerCore::setVirtualComponentsVisible(true);
+ }
- QString controlScript;
- if (parser.isSet(script)) {
- controlScript = parser.value(script);
- if (!QFileInfo(controlScript).exists())
- throw Error(QLatin1String("Script file does not exist."));
- }
+ if (parser.isSet(QLatin1String(CommandLineOptions::Updater))) {
+ if (m_core->isInstaller())
+ throw QInstaller::Error(QLatin1String("Cannot start installer binary as updater."));
+ m_core->setUpdater();
+ }
- if (parser.isSet(proxy)) {
- core.settings().setProxyType(QInstaller::Settings::SystemProxy);
- KDUpdater::FileDownloaderFactory::instance().setProxyFactory(core.proxyFactory());
- }
+ if (parser.isSet(QLatin1String(CommandLineOptions::ManagePackages))) {
+ if (m_core->isInstaller())
+ throw QInstaller::Error(QLatin1String("Cannot start installer binary as package manager."));
+ m_core->setPackageManager();
+ }
- if (parser.isSet(showVirtuals)) {
- QFont f;
- f.setItalic(true);
- PackageManagerCore::setVirtualComponentsFont(f);
- PackageManagerCore::setVirtualComponentsVisible(true);
- }
+ if (parser.isSet(QLatin1String(CommandLineOptions::AddRepository))) {
+ const QStringList repoList = repositories(parser
+ .value(QLatin1String(CommandLineOptions::AddRepository)));
+ if (repoList.isEmpty())
+ throw QInstaller::Error(QLatin1String("Empty repository list for option 'addRepository'."));
+ m_core->addUserRepositories(repoList);
+ }
- if (parser.isSet(updater)) {
- if (core.isInstaller())
- throw Error(QLatin1String("Cannot start installer binary as updater."));
- core.setUpdater();
- }
+ if (parser.isSet(QLatin1String(CommandLineOptions::AddTmpRepository))) {
+ const QStringList repoList = repositories(parser
+ .value(QLatin1String(CommandLineOptions::AddTmpRepository)));
+ if (repoList.isEmpty())
+ throw QInstaller::Error(QLatin1String("Empty repository list for option 'addTempRepository'."));
+ m_core->setTemporaryRepositories(repoList, false);
+ }
- if (parser.isSet(pkgManager)) {
- if (core.isInstaller())
- throw Error(QLatin1String("Cannot start installer binary as package manager."));
- core.setPackageManager();
- }
+ if (parser.isSet(QLatin1String(CommandLineOptions::SetTmpRepository))) {
+ const QStringList repoList = repositories(parser
+ .value(QLatin1String(CommandLineOptions::SetTmpRepository)));
+ if (repoList.isEmpty())
+ throw QInstaller::Error(QLatin1String("Empty repository list for option 'setTempRepository'."));
+ m_core->setTemporaryRepositories(repoList, true);
+ }
- if (parser.isSet(addRepo)) {
- const QStringList repoList = repositories(parser.value(addRepo));
- if (repoList.isEmpty())
- throw Error(QLatin1String("Empty repository list for option 'addRepository'."));
- core.addUserRepositories(repoList);
+ QInstaller::PackageManagerCore::setNoForceInstallation(parser
+ .isSet(QLatin1String(CommandLineOptions::NoForceInstallation)));
+ QInstaller::PackageManagerCore::setCreateLocalRepositoryFromBinary(parser
+ .isSet(QLatin1String(CommandLineOptions::CreateOfflineRepository)));
+
+ QHash<QString, QString> params;
+ const QStringList positionalArguments = parser.positionalArguments();
+ foreach (const QString &argument, positionalArguments) {
+ if (argument.contains(QLatin1Char('='))) {
+ const QString name = argument.section(QLatin1Char('='), 0, 0);
+ const QString value = argument.section(QLatin1Char('='), 1, 1);
+ params.insert(name, value);
+ m_core->setValue(name, value);
}
+ }
- if (parser.isSet(addTmpRepo)) {
- const QStringList repoList = repositories(parser.value(addTmpRepo));
- if (repoList.isEmpty())
- throw Error(QLatin1String("Empty repository list for option 'addTempRepository'."));
- core.setTemporaryRepositories(repoList, false);
+ const QString directory = QLatin1String(":/translations");
+ const QStringList translations = m_core->settings().translations();
+
+ // install the default Qt translator
+ QScopedPointer<QTranslator> translator(new QTranslator(QCoreApplication::instance()));
+ foreach (const QLocale locale, QLocale().uiLanguages()) {
+ // As there is no qt_en.qm, we simply end the search when the next
+ // preferred language is English.
+ if (locale.language() == QLocale::English)
+ break;
+ if (translator->load(locale, QLatin1String("qt"), QString::fromLatin1("_"), directory)) {
+ QCoreApplication::instance()->installTranslator(translator.take());
+ break;
}
+ }
- if (parser.isSet(setTmpRepo)) {
- const QStringList repoList = repositories(parser.value(setTmpRepo));
- if (repoList.isEmpty())
- throw Error(QLatin1String("Empty repository list for option 'setTempRepository'."));
- core.setTemporaryRepositories(repoList, true);
- }
+ translator.reset(new QTranslator(QCoreApplication::instance()));
+ // install English translation as fallback so that correct license button text is used
+ if (translator->load(QLatin1String("en_us"), directory))
+ QCoreApplication::instance()->installTranslator(translator.take());
- PackageManagerCore::setNoForceInstallation(parser.isSet(noForce));
- PackageManagerCore::setCreateLocalRepositoryFromBinary(parser.isSet(offlineRepo));
-
- QHash<QString, QString> params;
- const QStringList positionalArguments = parser.positionalArguments();
- foreach (const QString &argument, positionalArguments) {
- if (argument.contains(QLatin1Char('='))) {
- const QString name = argument.section(QLatin1Char('='), 0, 0);
- const QString value = argument.section(QLatin1Char('='), 1, 1);
- params.insert(name, value);
- core.setValue(name, value);
+ if (translations.isEmpty()) {
+ translator.reset(new QTranslator(QCoreApplication::instance()));
+ foreach (const QLocale locale, QLocale().uiLanguages()) {
+ if (translator->load(locale, QLatin1String(""), QLatin1String(""), directory)) {
+ QCoreApplication::instance()->installTranslator(translator.take());
+ break;
}
}
-
- // this needs to happen after we parse the arguments, but before we use the actual resources
- const QString newDefaultResource = core.value(QString::fromLatin1("DefaultResourceReplacement"));
- if (!newDefaultResource.isEmpty())
- content.registerAsDefaultQResource(newDefaultResource);
-
- if (QInstaller::isVerbose()) {
- qDebug() << "Resource tree:";
- QDirIterator it(QLatin1String(":/"), QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden,
- QDirIterator::Subdirectories);
- while (it.hasNext()) {
- const QString path = it.next();
- if (path.startsWith(QLatin1String(":/trolltech"))
- || path.startsWith(QLatin1String(":/qt-project.org"))) {
- continue;
- }
- qDebug() << " " << path.toUtf8().constData();
- }
+ } else {
+ foreach (const QString &translation, translations) {
+ translator.reset(new QTranslator(QCoreApplication::instance()));
+ if (translator->load(translation, QLatin1String(":/translations")))
+ QCoreApplication::instance()->installTranslator(translator.take());
}
+ }
- const QString directory = QLatin1String(":/translations");
- const QStringList translations = core.settings().translations();
+ //create the wizard GUI
+ TabController controller(0);
+ controller.setManager(m_core);
+ controller.setManagerParams(params);
+ controller.setControlScript(controlScript);
- // install the default Qt translator
- QScopedPointer<QTranslator> translator(new QTranslator(&app));
- foreach (const QLocale locale, QLocale().uiLanguages()) {
- // As there is no qt_en.qm, we simply end the search when the next
- // preferred language is English.
- if (locale.language() == QLocale::English)
- break;
- if (translator->load(locale, QLatin1String("qt"), QString::fromLatin1("_"), directory)) {
- app.installTranslator(translator.take());
- break;
- }
- }
+ if (m_core->isInstaller())
+ controller.setGui(new InstallerGui(m_core));
+ else
+ controller.setGui(new MaintenanceGui(m_core));
- translator.reset(new QTranslator(&app));
- // install English translation as fallback so that correct license button text is used
- if (translator->load(QLatin1String("en_us"), directory))
- app.installTranslator(translator.take());
-
- if (translations.isEmpty()) {
- translator.reset(new QTranslator(&app));
- foreach (const QLocale locale, QLocale().uiLanguages()) {
- if (translator->load(locale, QLatin1String(""), QLatin1String(""), directory)) {
- app.installTranslator(translator.take());
- break;
- }
- }
- } else {
- foreach (const QString &translation, translations) {
- translator.reset(new QTranslator(&app));
- if (translator->load(translation, QLatin1String(":/translations")))
- app.installTranslator(translator.take());
- }
- }
+ QInstaller::PackageManagerCore::Status status =
+ QInstaller::PackageManagerCore::Status(controller.init());
+ if (status != QInstaller::PackageManagerCore::Success)
+ return status;
- //create the wizard GUI
- TabController controller(0);
- controller.setManager(&core);
- controller.setManagerParams(params);
- controller.setControlScript(controlScript);
+ const int result = QCoreApplication::instance()->exec();
+ if (result != 0)
+ return result;
- if (core.isInstaller()) {
- controller.setGui(new InstallerGui(&core));
- } else {
- controller.setGui(new MaintenanceGui(&core));
- }
+ if (m_core->finishedWithSuccess())
+ return QInstaller::PackageManagerCore::Success;
- PackageManagerCore::Status status = PackageManagerCore::Status(controller.init());
- if (status != PackageManagerCore::Success)
+ status = m_core->status();
+ switch (status) {
+ case QInstaller::PackageManagerCore::Success:
return status;
- const int result = app.exec();
- if (result != 0)
- return result;
+ case QInstaller::PackageManagerCore::Canceled:
+ return status;
- if (core.finishedWithSuccess())
- return PackageManagerCore::Success;
+ default:
+ break;
+ }
+ return QInstaller::PackageManagerCore::Failure;
+}
- status = core.status();
- switch (status) {
- case PackageManagerCore::Success:
- return status;
- case PackageManagerCore::Canceled:
- return status;
+// -- private
- default:
- break;
- }
- return PackageManagerCore::Failure;
- } catch(const Error &e) {
- std::cerr << qPrintable(e.message()) << std::endl;
- } catch (const std::exception &e) {
- std::cerr << e.what() << std::endl;
- } catch(...) {
- std::cerr << "Unknown error, aborting." << std::endl;
+void InstallerBase::dumpResourceTree() const
+{
+ std::cout << "Resource tree:" << std::endl;
+ QDirIterator it(QLatin1String(":/"), QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden,
+ QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ if (it.next().startsWith(QLatin1String(":/qt-project.org")))
+ continue;
+ std::cout << " " << it.filePath().constData() << std::endl;
}
+}
- return PackageManagerCore::Failure;
+QStringList InstallerBase::repositories(const QString &list) const
+{
+ const QStringList items = list.split(QLatin1Char(','), QString::SkipEmptyParts);
+ foreach (const QString &item, items)
+ std::cout << "Adding custom repository:" << item.constData() << std::endl;
+ return items;
}
diff --git a/src/sdk/installerbase.h b/src/sdk/installerbase.h
new file mode 100644
index 000000000..b241d9988
--- /dev/null
+++ b/src/sdk/installerbase.h
@@ -0,0 +1,70 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 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 INSTALLERBASE_H
+#define INSTALLERBASE_H
+
+#include "sdkapp.h"
+
+namespace QInstaller {
+ class PackageManagerCore;
+}
+
+class InstallerBase : public SDKApp<QApplication>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(InstallerBase)
+
+public:
+ InstallerBase(int &argc, char *argv[]);
+ ~InstallerBase();
+
+ int run();
+
+private:
+ void dumpResourceTree() const;
+ QStringList repositories(const QString &list) const;
+
+private:
+ QInstaller::PackageManagerCore *m_core;
+};
+
+#endif // INSTALLERBASE_H
diff --git a/src/sdk/main.cpp b/src/sdk/main.cpp
new file mode 100644
index 000000000..5dc32b3bc
--- /dev/null
+++ b/src/sdk/main.cpp
@@ -0,0 +1,193 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 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 "console.h"
+#include "constants.h"
+#include "commandlineparser.h"
+#include "installerbase.h"
+#include "sdkapp.h"
+#include "updatechecker.h"
+
+#include <errors.h>
+#include <kdselfrestarter.h>
+#include <remoteserver.h>
+#include <utils.h>
+
+#include <QCommandLineParser>
+#include <QDateTime>
+#include <QHostAddress>
+#include <QNetworkProxyFactory>
+
+#include <iostream>
+
+#define QUOTE_(x) #x
+#define QUOTE(x) QUOTE_(x)
+#define VERSION "IFW Version: \"" QUOTE(IFW_VERSION) "\""
+#define BUILDDATE "Build date: " QUOTE(__DATE__)
+#define SHA "Installer Framework SHA1: \"" QUOTE(_GIT_SHA1_) "\""
+static const char PLACEHOLDER[32] = "MY_InstallerCreateDateTime_MY";
+
+int main(int argc, char *argv[])
+{
+ // increase maximum numbers of file descriptors
+#if defined (Q_OS_OSX)
+ struct rlimit rl;
+ getrlimit(RLIMIT_NOFILE, &rl);
+ rl.rlim_cur = qMin((rlim_t) OPEN_MAX, rl.rlim_max);
+ setrlimit(RLIMIT_NOFILE, &rl);
+#endif
+
+ qsrand(QDateTime::currentDateTime().toTime_t());
+
+ // We need to start either a command line application or a GUI application. Since we
+ // fail doing so at least on Linux while parsing the argument using a core application
+ // object and later starting the GUI application, we now parse the arguments first.
+ CommandLineParser parser;
+ parser.parse(QInstaller::parseCommandLineArgs(argc, argv));
+
+ QStringList mutually;
+ if (parser.isSet(QLatin1String(CommandLineOptions::CheckUpdates)))
+ mutually << QLatin1String(CommandLineOptions::CheckUpdates);
+ if (parser.isSet(QLatin1String(CommandLineOptions::Updater)))
+ mutually << QLatin1String(CommandLineOptions::Updater);
+ if (parser.isSet(QLatin1String(CommandLineOptions::ManagePackages)))
+ mutually << QLatin1String(CommandLineOptions::ManagePackages);
+
+ const bool help = parser.isSet(QLatin1String(CommandLineOptions::HelpShort))
+ || parser.isSet(QLatin1String(CommandLineOptions::HelpLong));
+ if (help || parser.isSet(QLatin1String(CommandLineOptions::Version)) || mutually.count()) {
+ Console c;
+ QCoreApplication app(argc, argv);
+
+ if (parser.isSet(QLatin1String(CommandLineOptions::Version))) {
+ std::cout << VERSION << std::endl << BUILDDATE << std::endl << SHA << std::endl;
+ const QDateTime dateTime = QDateTime::fromString(QLatin1String(PLACEHOLDER),
+ QLatin1String("yyyy-MM-dd - HH:mm:ss"));
+ if (dateTime.isValid())
+ std::cout << "Installer creation time: " << PLACEHOLDER << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if (mutually.count() > 1) {
+ std::cerr << qPrintable(QString::fromLatin1("The following options are mutually "
+ "exclusive: %1.").arg(mutually.join(QLatin1String(", ")))) << std::endl;
+ }
+
+ std::cout << qPrintable(parser.helpText()) << std::endl;
+ return help ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+
+ if (parser.isSet(QLatin1String(CommandLineOptions::StartServer))) {
+ const QString argument = parser.value(QLatin1String(CommandLineOptions::StartServer));
+ const QString port = argument.section(QLatin1Char(','), 0, 0);
+ const QString key = argument.section(QLatin1Char(','), 1, 1);
+
+ QStringList missing;
+ if (port.isEmpty())
+ missing << QLatin1String("Port");
+ if (key.isEmpty())
+ missing << QLatin1String("Key");
+
+ SDKApp<QCoreApplication> app(argc, argv);
+ if (missing.count()) {
+ Console c;
+ std::cerr << qPrintable(QString::fromLatin1("Missing argument(s) for option "
+ "'startserver': %2").arg(missing.join(QLatin1String(", ")))) << std::endl;
+ std::cout << qPrintable(parser.helpText()) << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ QInstaller::RemoteServer *server = new QInstaller::RemoteServer;
+ QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()));
+ server->init(port.toInt(), QHostAddress::LocalHost, QInstaller::Protocol::Mode::Release);
+ server->setAuthorizationKey(key);
+ server->start();
+ return app.exec();
+ }
+
+ try {
+ QScopedPointer<Console> console;
+ if (parser.isSet(QLatin1String(CommandLineOptions::VerboseShort))
+ || parser.isSet(QLatin1String(CommandLineOptions::VerboseLong))) {
+ console.reset(new Console);
+ QInstaller::setVerbose(true);
+ }
+
+ // On Windows we need the console window from above, we are a GUI application.
+ const QStringList unknownOptionNames = parser.unknownOptionNames();
+ if (!unknownOptionNames.isEmpty()) {
+ const QString options = unknownOptionNames.join(QLatin1String(", "));
+ std::cerr << "Unknown option: " << qPrintable(options) << std::endl;
+ }
+
+ if (parser.isSet(QLatin1String(CommandLineOptions::Proxy))) {
+ // Make sure we honor the system's proxy settings
+#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
+ QUrl proxyUrl(QString::fromLatin1(qgetenv("http_proxy")));
+ if (proxyUrl.isValid()) {
+ QNetworkProxy proxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyUrl.port(),
+ proxyUrl.userName(), proxyUrl.password());
+ QNetworkProxy::setApplicationProxy(proxy);
+ }
+#else
+ QNetworkProxyFactory::setUseSystemConfiguration(true);
+#endif
+ }
+
+ if (parser.isSet(QLatin1String(CommandLineOptions::CheckUpdates)))
+ return UpdateChecker(argc, argv).check();
+
+ if (QInstaller::isVerbose())
+ std::cout << VERSION << std::endl << BUILDDATE << std::endl << SHA << std::endl;
+
+ const KDSelfRestarter restarter(argc, argv);
+ return InstallerBase(argc, argv).run();
+
+ } catch (const QInstaller::Error &e) {
+ std::cerr << qPrintable(e.message()) << std::endl;
+ } catch (const std::exception &e) {
+ std::cerr << e.what() << std::endl;
+ } catch (...) {
+ std::cerr << "Unknown exception caught." << std::endl;
+ }
+
+ return EXIT_FAILURE;
+}
diff --git a/src/sdk/sdk.pro b/src/sdk/sdk.pro
index 25aed1b1a..c13576518 100644
--- a/src/sdk/sdk.pro
+++ b/src/sdk/sdk.pro
@@ -112,13 +112,19 @@ HEADERS += \
settingsdialog.h \
console.h \
sdkapp.h \
- updatechecker.h
-
-SOURCES = installerbase.cpp \
+ updatechecker.h \
+ installerbase.h \
+ constants.h \
+ commandlineparser.h
+
+SOURCES = \
+ main.cpp \
+ installerbase.cpp \
tabcontroller.cpp \
installerbasecommons.cpp \
settingsdialog.cpp \
- updatechecker.cpp
+ updatechecker.cpp \
+ commandlineparser.cpp
win32 {
# Force to overwrite the default manifest file with our own extended version.
diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h
index f0095e3bf..a00e2d0e8 100644
--- a/src/sdk/sdkapp.h
+++ b/src/sdk/sdkapp.h
@@ -42,12 +42,16 @@
#ifndef SDKAPP_H
#define SDKAPP_H
-#include <QApplication>
+#include <binarycontent.h>
+#include <binaryformat.h>
+#include <fileio.h>
+#include <fileutils.h>
-#ifdef Q_OS_OSX
+#include <QApplication>
+#include <QBuffer>
#include <QDir>
#include <QFileInfo>
-#endif
+#include <QResource>
template<class T>
class SDKApp : public T
@@ -58,8 +62,14 @@ public:
{
}
- ~SDKApp()
+ virtual ~SDKApp()
{
+ using namespace QInstaller;
+ foreach (const QSharedPointer<Resource> &resource, resourceMappings.resources()) {
+ resource->open(); // ignore error here, either we opened it or it is opened
+ QResource::unregisterResource((const uchar *) resource->readAll().constData(),
+ QLatin1String(":/metadata"));
+ }
}
bool notify(QObject *receiver, QEvent *event)
@@ -74,6 +84,15 @@ public:
return false;
}
+ /*!
+ Returns the installer/ maintenance tool binary. In case of an installer this will be the
+ installer binary itself, which contains the binary layout and the binary content. In case
+ of an maintenance tool, it will return a binary that has just a binary layout append.
+
+ Note on OSX: For compatibility reason this function will return the a .dat file located
+ inside the resource folder in the application bundle, as on OSX the binary layout can not
+ be appended to the actual installer/ maintenance tool binary itself because of signing.
+ */
QString binaryFile() const
{
QString binaryFile = QCoreApplication::applicationFilePath();
@@ -84,10 +103,68 @@ public:
QDir resourcePath(QFileInfo(binaryFile).dir());
resourcePath.cdUp();
resourcePath.cd(QLatin1String("Resources"));
- binaryFile = resourcePath.filePath(QLatin1String("installer.dat"));
+ return resourcePath.filePath(QLatin1String("installer.dat"));
#endif
return binaryFile;
}
+
+ /*!
+ Returns the corresponding .dat file for a given installer/ maintenance tool binary or an
+ empty string if it fails to find one.
+ */
+ QString datFile(const QString &binaryFile) const
+ {
+ QFile file(binaryFile);
+ QInstaller::openForRead(&file);
+ const quint64 cookiePos = QInstaller::BinaryContent::findMagicCookie(&file,
+ QInstaller::BinaryContent::MagicCookie);
+ if (!file.seek(cookiePos - sizeof(qint64))) // seek to read the marker
+ return QString(); // ignore error, we will fail later
+
+ const qint64 magicMarker = QInstaller::retrieveInt64(&file);
+ if (magicMarker == QInstaller::BinaryContent::MagicUninstallerMarker) {
+ QFileInfo fi(binaryFile);
+ QString bundlePath;
+ if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath))
+ fi.setFile(bundlePath);
+ return fi.absoluteDir().filePath(fi.baseName() + QLatin1String(".dat"));
+ }
+ return QString();
+ }
+
+ QInstaller::ResourceCollection registeredMetaResources()
+ {
+ return resourceMappings;
+ }
+
+ void registerMetaResources(const QInstaller::ResourceCollection &resources)
+ {
+ foreach (const QSharedPointer<QInstaller::Resource> &resource, resources.resources()) {
+ const bool isOpen = resource->isOpen();
+ if ((!isOpen) && (!resource->open()))
+ continue;
+
+ if (!resource->seek(0))
+ continue;
+
+ const QByteArray ba = resource->readAll();
+ if (ba.isEmpty())
+ continue;
+
+ if (QResource::registerResource((const uchar*) ba.data(), QLatin1String(":/metadata"))) {
+ using namespace QInstaller;
+ QSharedPointer<QBuffer> buffer(new QBuffer);
+ buffer->setData(ba); // set the buffers internal data
+ resourceMappings.appendResource(QSharedPointer<Resource>(new Resource(buffer)));
+ }
+
+ if (!isOpen) // If we reach that point, either the resource was opened already...
+ resource->close(); // or we did open it and have to close it again.
+ }
+ }
+
+private:
+ QInstaller::ResourceCollection resourceMappings;
};
#endif // SDKAPP_H
diff --git a/src/sdk/updatechecker.cpp b/src/sdk/updatechecker.cpp
index 60587942e..2ebe39b92 100644
--- a/src/sdk/updatechecker.cpp
+++ b/src/sdk/updatechecker.cpp
@@ -40,11 +40,9 @@
**************************************************************************/
#include "updatechecker.h"
-#include "sdkapp.h"
-#include <binarycontent.h>
+#include <binaryformatenginehandler.h>
#include <component.h>
-#include <constants.h>
#include <errors.h>
#include <init.h>
#include <kdrunoncechecker.h>
@@ -55,57 +53,65 @@
#include <iostream>
-int UpdateChecker::check(int argc, char *argv[])
+UpdateChecker::UpdateChecker(int &argc, char *argv[])
+ : SDKApp<QCoreApplication>(argc, argv)
{
- try {
- SDKApp<QCoreApplication> app(argc, argv);
-
- KDRunOnceChecker runCheck((QLatin1String("lockmyApp15021976.lock")));
- if (runCheck.isRunning(KDRunOnceChecker::Lockfile))
- throw QInstaller::Error(QLatin1String("An instance is already checking for updates."));
-
- QInstaller::init(); // register custom operations
-
- const QInstaller::BinaryContent content =
- QInstaller::BinaryContent::readAndRegisterFromBinary(app.binaryFile());
- if (content.magicMarker() != QInstaller::BinaryContent::MagicInstallerMarker)
- throw QInstaller::Error(QLatin1String("Installers cannot check for updates."));
-
- QInstaller::PackageManagerCore core(QInstaller::BinaryContent::MagicUpdaterMarker, content
- .performedOperations());
- ProductKeyCheck::instance()->init(&core);
- QInstaller::PackageManagerCore::setVirtualComponentsVisible(true);
-
- if (!core.fetchRemotePackagesTree())
- throw QInstaller::Error(core.error());
-
- const QList<QInstaller::Component *> components = core.updaterComponents();
- if (components.isEmpty())
- throw QInstaller::Error(QLatin1String("There are currently no updates available."));
-
- QDomDocument doc;
- QDomElement root = doc.createElement(QLatin1String("updates"));
- doc.appendChild(root);
-
- foreach (QInstaller::Component *component, components) {
- QDomElement update = doc.createElement(QLatin1String("update"));
- update.setAttribute(QLatin1String("name"),
- component->value(QInstaller::scDisplayName));
- update.setAttribute(QLatin1String("version"),
- component->value(QInstaller::scRemoteVersion));
- update.setAttribute(QLatin1String("size"),
- component->value(QInstaller::scUncompressedSize));
- root.appendChild(update);
- }
-
- std::cout << qPrintable(doc.toString(4)) << std::endl;
- return EXIT_SUCCESS;
- } catch (const QInstaller::Error &e) {
- std::cerr << qPrintable(e.message()) << std::endl;
- } catch (const std::exception &e) {
- std::cerr << e.what() << std::endl;
- } catch (...) {
- std::cerr << "Unknown exception caught." << std::endl;
+ QInstaller::init(); // register custom operations
+}
+
+int UpdateChecker::check()
+{
+ KDRunOnceChecker runCheck((QLatin1String("lockmyApp15021976.lock")));
+ if (runCheck.isRunning(KDRunOnceChecker::Lockfile))
+ throw QInstaller::Error(QLatin1String("An instance is already checking for updates."));
+
+ QString fileName = datFile(binaryFile());
+ quint64 cookie = QInstaller::BinaryContent::MagicCookieDat;
+ if (fileName.isEmpty()) {
+ fileName = binaryFile();
+ cookie = QInstaller::BinaryContent::MagicCookie;
}
- return EXIT_FAILURE;
+
+ QSharedPointer<QFile> binary(new QFile(fileName));
+ QInstaller::openForRead(binary.data());
+
+ qint64 magicMarker;
+ QInstaller::ResourceCollection resources;
+ QList<QInstaller::OperationBlob> operations;
+ QInstaller::ResourceCollectionManager manager;
+ QInstaller::BinaryContent::readBinaryContent(binary, &resources, &operations, &manager,
+ &magicMarker, cookie);
+
+ if (magicMarker != QInstaller::BinaryContent::MagicInstallerMarker)
+ throw QInstaller::Error(QLatin1String("Installers cannot check for updates."));
+
+ registerMetaResources(resources); // the base class will unregister the resources
+
+ // instantiate the installer we are actually going to use
+ QInstaller::PackageManagerCore core(QInstaller::BinaryContent::MagicUpdaterMarker, operations);
+ QInstaller::BinaryFormatEngineHandler::instance()->registerResources(manager.collections());
+ QInstaller::PackageManagerCore::setVirtualComponentsVisible(true);
+ QInstaller::ProductKeyCheck::instance()->init(&core);
+
+ if (!core.fetchRemotePackagesTree())
+ throw QInstaller::Error(core.error());
+
+ const QList<QInstaller::Component *> components = core.updaterComponents();
+ if (components.isEmpty())
+ throw QInstaller::Error(QLatin1String("There are currently no updates available."));
+
+ QDomDocument doc;
+ QDomElement root = doc.createElement(QLatin1String("updates"));
+ doc.appendChild(root);
+
+ foreach (QInstaller::Component *component, components) {
+ QDomElement update = doc.createElement(QLatin1String("update"));
+ update.setAttribute(QLatin1String("name"), component->value(QInstaller::scDisplayName));
+ update.setAttribute(QLatin1String("version"), component->value(QInstaller::scRemoteVersion));
+ update.setAttribute(QLatin1String("size"), component->value(QInstaller::scUncompressedSize));
+ root.appendChild(update);
+ }
+
+ std::cout << qPrintable(doc.toString(4)) << std::endl;
+ return EXIT_SUCCESS;
}
diff --git a/src/sdk/updatechecker.h b/src/sdk/updatechecker.h
index 504e97604..19b34e29b 100644
--- a/src/sdk/updatechecker.h
+++ b/src/sdk/updatechecker.h
@@ -42,11 +42,16 @@
#ifndef UPDATECHECKER_H
#define UPDATECHECKER_H
-class UpdateChecker
+#include "sdkapp.h"
+
+class UpdateChecker : public SDKApp<QCoreApplication>
{
+ Q_OBJECT
+ Q_DISABLE_COPY(UpdateChecker)
+
public:
- UpdateChecker() {}
- int check(int argc, char *argv[]);
+ UpdateChecker(int &argc, char *argv[]);
+ int check();
};
#endif // UPDATECHECKER_H