Introduce developer tool.

Supports dump binary content, run operation and update existing
binary with new installer base. The support for starting with
binary data of a different installer got dropped completely, use
update and run instead.

Change-Id: I41073d0bfc9a4c4da18fbb9f49fd3e65bb54b501
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
kh1 2014-07-11 15:26:35 +02:00 committed by Karsten Heimrich
parent e6390254c6
commit 2a364e7135
11 changed files with 794 additions and 209 deletions

View File

@ -71,7 +71,6 @@ HEADERS += packagemanagercore.h \
downloadarchivesjob.h \
init.h \
updater.h \
operationrunner.h \
adminauthorization.h \
elevatedexecuteoperation.h \
fakestopprocessforupdateoperation.h \
@ -153,7 +152,6 @@ SOURCES += packagemanagercore.cpp \
downloadarchivesjob.cpp \
init.cpp \
updater.cpp \
operationrunner.cpp \
elevatedexecuteoperation.cpp \
fakestopprocessforupdateoperation.cpp \
lazyplaintextedit.cpp \

View File

@ -1,185 +0,0 @@
/**************************************************************************
**
** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#include "operationrunner.h"
#include "errors.h"
#include "init.h"
#include "packagemanagercore.h"
#include "utils.h"
#include "kdupdaterupdateoperationfactory.h"
#include <iostream>
namespace {
class OutputHandler : public QObject
{
Q_OBJECT
public slots:
void drawItToCommandLine(const QString &outPut)
{
std::cout << qPrintable(outPut) << std::endl;
}
};
}
using namespace QInstaller;
using namespace QInstallerCreator;
OperationRunner::OperationRunner()
: m_core(0)
{
m_path = QCoreApplication::applicationFilePath();
#ifdef Q_OS_OSX
QDir resourcePath(QFileInfo(m_path).dir());
resourcePath.cdUp();
resourcePath.cd(QLatin1String("Resources"));
m_path = resourcePath.filePath(QLatin1String("installer.dat"));
#endif
}
OperationRunner::OperationRunner(const QString &path)
: m_core(0)
, m_path(path)
{
}
OperationRunner::~OperationRunner()
{
delete m_core;
}
bool OperationRunner::init()
{
try {
QInstaller::init();
m_bc = BinaryContent::readAndRegisterFromBinary(m_path);
m_core = new PackageManagerCore(m_bc.magicMarker(), m_bc.performedOperations());
} catch (const Error &e) {
std::cerr << qPrintable(e.message()) << std::endl;
return false;
} catch (...) {
return false;
}
return true;
}
void OperationRunner::setVerbose(bool verbose)
{
QInstaller::setVerbose(verbose);
}
int OperationRunner::runOperation(const QStringList &arguments)
{
if (!init()) {
qDebug() << "Could not init the package manager core - without this not all operations are working "
"as expected.";
}
bool isPerformType = arguments.contains(QLatin1String("--runoperation"));
bool isUndoType = arguments.contains(QLatin1String("--undooperation"));
if ((!isPerformType && !isUndoType) || (isPerformType && isUndoType)) {
std::cerr << "wrong arguments are used, cannot run this operation";
return EXIT_FAILURE;
}
QStringList argumentList;
if (isPerformType)
argumentList = arguments.mid(arguments.indexOf(QLatin1String("--runoperation")) + 1);
else
argumentList = arguments.mid(arguments.indexOf(QLatin1String("--undooperation")) + 1);
try {
const QString operationName = argumentList.takeFirst();
KDUpdater::UpdateOperation* const operation = KDUpdater::UpdateOperationFactory::instance()
.create(operationName);
if (!operation) {
std::cerr << "Can not find the operation: " << qPrintable(operationName) << std::endl;
return EXIT_FAILURE;
}
OutputHandler myOutPutHandler;
QObject *const operationObject = dynamic_cast<QObject *>(operation);
if (operationObject != 0) {
const QMetaObject *const mo = operationObject->metaObject();
if (mo->indexOfSignal(QMetaObject::normalizedSignature("outputTextChanged(QString)")) > -1) {
QObject::connect(operationObject, SIGNAL(outputTextChanged(QString)),
&myOutPutHandler, SLOT(drawItToCommandLine(QString)));
}
}
operation->setValue(QLatin1String("installer"), QVariant::fromValue(m_core));
operation->setArguments(argumentList);
bool readyPerformed = false;
if (isPerformType)
readyPerformed = operation->performOperation();
if (isUndoType)
readyPerformed = operation->undoOperation();
std::cout << "========================================" << std::endl;
if (readyPerformed) {
std::cout << "Operation was successfully performed." << std::endl;
} else {
std::cerr << "There was a problem while performing the operation: "
<< qPrintable(operation->errorString()) << std::endl;
return EXIT_FAILURE;
}
} catch (const QInstaller::Error &e) {
std::cerr << qPrintable(e.message()) << std::endl;
return EXIT_FAILURE;
} catch (...) {
std::cerr << "Caught unknown exception" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#include "operationrunner.moc"

View File

@ -0,0 +1,147 @@
/**************************************************************************
**
** 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 "binarydump.h"
#include <copydirectoryoperation.h>
#include <errors.h>
#include <fileio.h>
#include <QDirIterator>
#include <QDomDocument>
#include <iostream>
int BinaryDump::dump(const QInstallerCreator::ComponentIndex &index, const QString &target)
{
QDir targetDir(QFileInfo(target).absoluteFilePath());
if (targetDir.exists()) {
if (!targetDir.entryList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty()) {
std::cerr << qPrintable(QString::fromLatin1("Target directory '%1' already exists and "
"is not empty.").arg(targetDir.path())) << std::endl;
return EXIT_FAILURE;
}
} else {
if (!QDir().mkpath(targetDir.path())) {
std::cerr << qPrintable(QString::fromLatin1("Could not create '%1'.").arg(targetDir
.path())) << std::endl;
return EXIT_FAILURE;
}
}
QInstaller::CopyDirectoryOperation copyMetadata;
copyMetadata.setArguments(QStringList() << QLatin1String(":/")
<< (targetDir.path() + QLatin1Char('/'))); // Add "/" at the end to make operation work.
if (!copyMetadata.performOperation()) {
std::cerr << qPrintable(copyMetadata.errorString()) << std::endl;
return EXIT_FAILURE;
}
if (!targetDir.cd(QLatin1String("metadata"))) {
std::cerr << qPrintable(QString::fromLatin1("Could not switch to '%1/metadata'.")
.arg(targetDir.path())) << std::endl;
return EXIT_FAILURE;
}
int result = EXIT_FAILURE;
try {
QFile updatesXml(targetDir.filePath(QLatin1String("Updates.xml")));
QInstaller::openForRead(&updatesXml);
QString error;
QDomDocument doc;
if (!doc.setContent(&updatesXml, &error)) {
throw QInstaller::Error(QString::fromLatin1("Could not read: '%1'. %2").arg(updatesXml
.fileName(), error));
}
QHash<QString, QString> versionMap;
const QDomElement root = doc.documentElement();
const QDomNodeList rootChildNodes = root.childNodes();
for (int i = 0; i < rootChildNodes.count(); ++i) {
const QDomElement element = rootChildNodes.at(i).toElement();
if (element.isNull())
continue;
QString name, version;
if (element.tagName() == QLatin1String("PackageUpdate")) {
const QDomNodeList elementChildNodes = element.childNodes();
for (int j = 0; j < elementChildNodes.count(); ++j) {
const QDomElement e = elementChildNodes.at(j).toElement();
if (e.tagName() == QLatin1String("Name"))
name = e.text();
else if (e.tagName() == QLatin1String("Version"))
version = e.text();
}
versionMap.insert(name, version);
}
}
QDirIterator it(targetDir, QDirIterator::Subdirectories);
while (it.hasNext() && !it.next().isEmpty()) {
if (!it.fileInfo().isDir())
continue;
const QString fileName = it.fileName();
QInstallerCreator::Component c = index.componentByName(fileName.toUtf8());
if (c.archives().count() <= 0)
continue;
typedef QSharedPointer<QInstallerCreator::Archive> Archive;
QVector<Archive> archives = c.archives();
foreach (const Archive &archive, archives) {
if (!archive->open(QIODevice::ReadOnly))
continue; // TODO: should we throw here?
QFile target(targetDir.filePath(fileName) + QDir::separator()
+ QString::fromUtf8(archive->name()));
QInstaller::openForWrite(&target);
archive->copyData(&target); // copy the 7z files into the target directory
}
}
result = EXIT_SUCCESS;
} catch (const QInstaller::Error &error) {
std::cerr << qPrintable(error.message()) << std::endl;
} catch (...) {
std::cerr << "Unknown exception caught." << std::endl;
}
return result;
}

View File

@ -0,0 +1,56 @@
/**************************************************************************
**
** 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 BINARYDUMP_H
#define BINARYDUMP_H
#include <binaryformat.h>
class BinaryDump
{
Q_DISABLE_COPY(BinaryDump)
public:
BinaryDump() {}
int dump(const QInstallerCreator::ComponentIndex &index, const QString &target);
};
#endif // BINARYDUMP_H

View File

@ -0,0 +1,167 @@
/**************************************************************************
**
** 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 "binaryreplace.h"
#include <copyfiletask.h>
#include <downloadfiletask.h>
#include <errors.h>
#include <fileio.h>
#include <fileutils.h>
#include <lib7z_facade.h>
#include <QFutureWatcher>
#include <iostream>
BinaryReplace::BinaryReplace(const QInstaller::BinaryLayout &layout)
: m_binaryLayout(layout)
{}
int BinaryReplace::replace(const QString &source, const QString &target)
{
const QUrl url = QUrl::fromUserInput(source);
QFutureWatcher<QInstaller::FileTaskResult> taskWatcher;
if (url.isLocalFile()) {
taskWatcher.setFuture(QtConcurrent::run(&QInstaller::CopyFileTask::doTask,
new QInstaller::CopyFileTask(QInstaller::FileTaskItem(url.toLocalFile()))));
} else {
taskWatcher.setFuture(QtConcurrent::run(&QInstaller::DownloadFileTask::doTask,
new QInstaller::DownloadFileTask(QInstaller::FileTaskItem(url.toString()))));
}
bool result = EXIT_FAILURE;
try {
taskWatcher.waitForFinished(); // throws on error
const QFuture<QInstaller::FileTaskResult> future = taskWatcher.future();
if (future.resultCount() <= 0)
return result;
QString newInstallerBasePath = future.result().target();
if (Lib7z::isSupportedArchive(newInstallerBasePath)) {
QFile archive(newInstallerBasePath);
if (archive.open(QIODevice::ReadOnly)) {
try {
Lib7z::extractArchive(&archive, QDir::tempPath());
const QVector<Lib7z::File> files = Lib7z::listArchive(&archive);
newInstallerBasePath = QDir::tempPath() + QLatin1Char('/') + files.value(0)
.path;
result = EXIT_SUCCESS;
} catch (const Lib7z::SevenZipException& e) {
std::cerr << qPrintable(QString::fromLatin1("Error while extracting '%1': %2.")
.arg(newInstallerBasePath, e.message())) << std::endl;
} catch (...) {
std::cerr << qPrintable(QString::fromLatin1("Unknown exception caught while "
"extracting '%1'.").arg(newInstallerBasePath)) << std::endl;
}
} else {
std::cerr << qPrintable(QString::fromLatin1("Could not open '%1' for reading: %2.")
.arg(newInstallerBasePath, archive.errorString())) << std::endl;
}
if (!archive.remove()) {
std::cerr << qPrintable(QString::fromLatin1("Could not delete file '%1': %2.")
.arg(newInstallerBasePath, archive.errorString())) << std::endl;
}
if (result != EXIT_SUCCESS)
return result;
}
result = EXIT_FAILURE;
try {
QFile installerBaseNew(newInstallerBasePath);
#ifndef Q_OS_OSX
QFile installerBaseOld(target);
QInstaller::openForAppend(&installerBaseNew);
installerBaseNew.seek(installerBaseNew.size());
if (m_binaryLayout.magicMarker == QInstaller::MagicInstallerMarker) {
QInstaller::openForRead(&installerBaseOld);
installerBaseOld.seek(m_binaryLayout.metadataResourceSegments.first().start());
QInstaller::appendData(&installerBaseNew, &installerBaseOld, installerBaseOld
.size() - installerBaseOld.pos());
installerBaseOld.close();
} else {
QInstaller::appendInt64(&installerBaseNew, 0);
QInstaller::appendInt64(&installerBaseNew, 4 * sizeof(qint64));
QInstaller::appendInt64(&installerBaseNew, QInstaller::MagicUninstallerMarker);
QInstaller::appendInt64(&installerBaseNew, QInstaller::MagicCookie);
}
installerBaseNew.close();
#else
QString bundlePath;
QInstaller::isInBundle(target, &bundlePath);
QFile installerBaseOld(QDir(bundlePath).filePath(bundlePath
+ QLatin1String("/Contents/MacOS/") + QFileInfo(bundlePath).completeBaseName()));
#endif
installerBaseNew.setPermissions(installerBaseOld.permissions());
QFile backup(installerBaseOld.fileName() + QLatin1String(".bak"));
if (backup.exists() && (!backup.remove())) {
std::cerr << qPrintable(QString::fromLatin1("Could not delete '%1'. %2")
.arg(backup.fileName(), backup.errorString())) << std::endl;
}
const QString oldBasePath = installerBaseOld.fileName();
if (!installerBaseOld.rename(oldBasePath + QLatin1String(".bak"))) {
std::cerr << qPrintable(QString::fromLatin1("Could not rename '%1' to '%2'. %3")
.arg(oldBasePath, oldBasePath + QLatin1String(".bak"),
installerBaseOld.errorString())) << std::endl;
}
if (!installerBaseNew.rename(oldBasePath)) {
std::cerr << qPrintable(QString::fromLatin1("Could not copy '%1' to '%2'. %3")
.arg(installerBaseNew.fileName(), oldBasePath, installerBaseNew.errorString()))
<< std::endl;
} else {
result = EXIT_SUCCESS;
}
} catch (const QInstaller::Error &error) {
std::cerr << qPrintable(error.message()) << std::endl;
}
} catch (const QInstaller::FileTaskException &e) {
std::cerr << qPrintable(e.message()) << std::endl;
} catch (const QUnhandledException &e) {
std::cerr << e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown exception caught."<< std::endl;
}
return result;
}

View File

@ -0,0 +1,59 @@
/**************************************************************************
**
** 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 BINARYREPLACE_H
#define BINARYREPLACE_H
#include <binaryformat.h>
class BinaryReplace
{
Q_DISABLE_COPY(BinaryReplace)
public:
BinaryReplace(const QInstaller::BinaryLayout &layout);
int replace(const QString &source, const QString &target);
private:
QInstaller::BinaryLayout m_binaryLayout;
};
#endif // BINARYREPLACE_H

21
tools/devtool/devtool.pro Normal file
View File

@ -0,0 +1,21 @@
TEMPLATE = app
TARGET = devtool
include(../../installerfw.pri)
QT -= gui
QT += network xml
CONFIG += console
DESTDIR = $$IFW_APP_PATH
HEADERS += operationrunner.h \
binaryreplace.h \
binarydump.h
SOURCES += main.cpp \
operationrunner.cpp \
binaryreplace.cpp \
binarydump.cpp
osx:include(../../no_app_bundle.pri)

212
tools/devtool/main.cpp Normal file
View File

@ -0,0 +1,212 @@
/**************************************************************************
**
** 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 "binarydump.h"
#include "binaryreplace.h"
#include "operationrunner.h"
#include <binaryformat.h>
#include <binaryformatenginehandler.h>
#include <errors.h>
#include <fileio.h>
#include <fileutils.h>
#include <init.h>
#include <kdupdaterupdateoperationfactory.h>
#include <utils.h>
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QFileInfo>
#include <QResource>
#include <iostream>
using namespace QInstallerCreator;
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
app.setApplicationVersion(QLatin1String("1.0.0"));
QCommandLineOption verbose(QLatin1String("verbose"),
QLatin1String("Verbose mode. Prints out more information."));
QCommandLineOption dump(QLatin1String("dump"),
QLatin1String("Dumps the binary content attached to an installer into target."),
QLatin1String("folder"));
QCommandLineOption run(QLatin1String("operation"),
QLatin1String("Executes an operation with a list of arguments. Mode can be DO or UNDO."),
QLatin1String("mode,name,args,..."));
QCommandLineOption update(QLatin1String("update"),
QLatin1String("Updates existing installer or maintenance tool with a new installer base."),
QLatin1String("file"));
QCommandLineParser parser;
parser.addVersionOption();
parser.addOption(verbose);
parser.addOption(update);
parser.addOption(dump);
parser.addOption(run);
parser.addPositionalArgument(QLatin1String("binary"), QLatin1String("Existing installer or "
"maintenance tool."));
parser.process(app.arguments());
const QStringList arguments = parser.positionalArguments();
if (arguments.isEmpty() || (arguments.count() > 1))
parser.showHelp(EXIT_FAILURE);
QInstaller::init();
QInstaller::setVerbose(parser.isSet(verbose));
QString bundlePath;
QString path = QFileInfo(arguments.first()).absoluteFilePath();
if (QInstaller::isInBundle(path, &bundlePath))
path = QDir(bundlePath).filePath(QLatin1String("Contents/Resources/installer.dat"));
int result = EXIT_FAILURE;
QVector<QByteArray> resourceMappings;
try {
QFile *file = new QFile(path);
QInstaller::openForRead(file);
qint64 pos = QInstaller::findMagicCookie(file, QInstaller::MagicCookie);
QInstaller::BinaryLayout layout = QInstaller::BinaryContent::readBinaryLayout(file, pos);
if (layout.magicMarker == QInstaller::MagicUninstallerMarker) {
QFileInfo fi(path);
if (QInstaller::isInBundle(fi.absoluteFilePath(), &bundlePath))
fi.setFile(bundlePath);
path = fi.absolutePath() + QLatin1Char('/') + fi.baseName() + QLatin1String(".dat");
file->setFileName(path);
pos = QInstaller::findMagicCookie(file, QInstaller::MagicCookie);
layout = QInstaller::BinaryContent::readBinaryLayout(file, pos);
}
if (parser.isSet(update)) {
// To update the binary we do not need any mapping.
BinaryReplace br(layout);
return br.replace(parser.value(update), path);
}
// map the inbuilt resources
foreach (const Range<qint64> &segment, layout.metadataResourceSegments) {
if (segment.length() <= 0)
continue;
if (!file->seek(segment.start()))
throw QInstaller::Error(QLatin1String("Could not seek to segment position."));
const QByteArray ba = QInstaller::retrieveData(file, segment.length());
if (!QResource::registerResource((const uchar*) ba.data(), QLatin1String(":/metadata")))
throw QInstaller::Error(QLatin1String("Could not register in-binary resource."));
resourceMappings.append(ba);
}
// instantiate the operations we support
const qint64 dataBlockStart = layout.endOfData - layout.dataBlockSize;
const qint64 operationsStart = layout.operationsStart + dataBlockStart;
if (!file->seek(operationsStart))
throw QInstaller::Error(QLatin1String("Could not seek to operation list."));
QList<QInstaller::Operation *> performedOperations;
const qint64 operationsCount = QInstaller::retrieveInt64(file);
for (int i = 0; i < operationsCount; ++i) {
const QString name = QInstaller::retrieveString(file);
const QString data = QInstaller::retrieveString(file);
QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance()
.create(name));
if (op.isNull()) {
throw QInstaller::Error(QString::fromLatin1("Could not load unknown operation %1")
.arg(name));
}
if (!op->fromXml(data)) {
throw QInstaller::Error(QString::fromLatin1("Could not load XML for operation: %1")
.arg(name));
}
performedOperations.append(op.take());
}
// seek to the position of the component index
const qint64 resourceOffsetAndLengtSize = 2 * sizeof(qint64);
const qint64 resourceSectionSize = resourceOffsetAndLengtSize * layout.resourceCount;
const qint64 offset = layout.endOfData - layout.indexSize - resourceSectionSize
- resourceOffsetAndLengtSize;
if (!file->seek(offset))
throw QInstaller::Error(QLatin1String("Could not seek to read component index info."));
const qint64 compIndexStart = QInstaller::retrieveInt64(file) + dataBlockStart;
if (!file->seek(compIndexStart))
throw QInstaller::Error(QLatin1String("Could not seek to start of component index."));
// setup the component index
QSharedPointer<QFile> data(file);
ComponentIndex index = ComponentIndex::read(data, dataBlockStart);
if (parser.isSet(dump)) {
// To dump the content we do not need the binary format engine.
if (layout.magicMarker != QInstaller::MagicInstallerMarker)
throw QInstaller::Error(QLatin1String("Source file is not an installer."));
BinaryDump bd;
return bd.dump(index, parser.value(dump));
}
// setup the binary format engine
QScopedPointer<BinaryFormatEngineHandler> binaryFormatEngineHandler;
binaryFormatEngineHandler.reset(new BinaryFormatEngineHandler(index));
if (parser.isSet(run)) {
OperationRunner runner(layout.magicMarker, performedOperations);
const QStringList arguments = parser.values(run);
if (arguments.first() == QLatin1String("DO"))
result = runner.runOperation(arguments.mid(1), OperationRunner::RunMode::Do);
else if (arguments.first() == QLatin1String("UNDO"))
result = runner.runOperation(arguments.mid(1), OperationRunner::RunMode::Undo);
}
} catch (const QInstaller::Error &error) {
std::cerr << qPrintable(error.message()) << std::endl;
} catch (...) {
std::cerr << "Unknown exception caught." << std::endl;
}
// unmap resources
foreach (const QByteArray &rccData, resourceMappings)
QResource::unregisterResource((const uchar*) rccData.data(), QLatin1String(":/metadata"));
return result;
}

View File

@ -0,0 +1,108 @@
/**************************************************************************
**
** Copyright (C) 2012-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 "operationrunner.h"
#include <errors.h>
#include <kdupdaterupdateoperationfactory.h>
#include <packagemanagercore.h>
#include <QMetaObject>
#include <iostream>
OperationRunner::OperationRunner(qint64 magicMarker, const QInstaller::OperationList &oldOperations)
: m_core(new QInstaller::PackageManagerCore(magicMarker, oldOperations))
{
// We need a package manager core as some operations expect them to be available.
}
OperationRunner::~OperationRunner()
{
delete m_core;
}
int OperationRunner::runOperation(QStringList arguments, RunMode mode)
{
int result = EXIT_FAILURE;
try {
const QString name = arguments.takeFirst();
QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance()
.create(name));
if (!op) {
std::cerr << "Cannot instantiate operation: " << qPrintable(name) << std::endl;
return EXIT_FAILURE;
}
if (QObject *const object = dynamic_cast<QObject*> (op.data())) {
const QMetaObject *const mo = object->metaObject();
if (mo->indexOfSignal(mo->normalizedSignature("outputTextChanged(QString)")) > -1)
connect(object, SIGNAL(outputTextChanged(QString)), this, SLOT(print(QString)));
}
op->setArguments(arguments);
op->setValue(QLatin1String("installer"), QVariant::fromValue(m_core));
bool readyPerformed = false;
if (mode == RunMode::Do)
readyPerformed = op->performOperation();
if (mode == RunMode::Undo)
readyPerformed = op->undoOperation();
if (readyPerformed) {
result = EXIT_SUCCESS;
std::cout << "Operation finished successfully." << std::endl;
} else {
std::cerr << "An error occurred while performing the operation: "
<< qPrintable(op->errorString()) << std::endl;
}
} catch (const QInstaller::Error &e) {
std::cerr << qPrintable(e.message()) << std::endl;
} catch (...) {
std::cerr << "Unknown exception caught." << std::endl;
}
return result;
}
void OperationRunner::print(const QString &value)
{
std::cout << qPrintable(value) << std::endl;
}

View File

@ -1,6 +1,6 @@
/**************************************************************************
**
** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2012-2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
@ -42,33 +42,34 @@
#ifndef OPERATIONRUNNER_H
#define OPERATIONRUNNER_H
#include "binaryformat.h"
#include "installer_global.h"
#include <qinstallerglobal.h>
QT_FORWARD_DECLARE_CLASS(QStringList)
#include <QObject>
namespace QInstaller {
class PackageManagerCore;
}
class PackageManagerCore;
class INSTALLER_EXPORT OperationRunner
class OperationRunner : public QObject
{
public:
OperationRunner();
explicit OperationRunner(const QString &path);
~OperationRunner();
Q_OBJECT
Q_DISABLE_COPY(OperationRunner)
bool init();
void setVerbose(bool verbose);
int runOperation(const QStringList &arguments);
public:
enum struct RunMode {
Do,
Undo
};
OperationRunner(qint64 magicMarker, const QInstaller::OperationList &oldOperations);
~OperationRunner();
int runOperation(QStringList arguments, RunMode mode);
private slots:
void print(const QString &value);
private:
PackageManagerCore *m_core;
QString m_path;
BinaryContent m_bc;
QInstaller::PackageManagerCore *m_core;
};
} // namespace QInstaller
#endif
#endif // OPERATIONRUNNER_H

View File

@ -4,7 +4,8 @@ TEMPLATE = subdirs
SUBDIRS += \
archivegen \
binarycreator \
repogen
repogen \
devtool
EXTRASUBDIRS = \
repocompare \