Merge remote-tracking branch 'origin/1.4' into 1.5

Change-Id: Ib2d382d1aa398b642dc15f4df7c03b19bf638546
This commit is contained in:
Tim Jenssen 2013-10-23 17:09:23 +02:00
commit 7778787b91
42 changed files with 547 additions and 245 deletions

View File

@ -1,3 +1,11 @@
1.4.1
- Added support to pass a query string when downloading archives. (QTIFW-329)
- Fixed progress display for redirected HTTP Downloads. (QTIFW-267)
- Add support to repogen to update only newer components. (QTIFW-234)
- Added more autotests.
- Improved documentation.
- Minor bugfixes.
1.4 1.4
- Force updating of Essential components. (QTIFW-38, QTIFW-155) - Force updating of Essential components. (QTIFW-38, QTIFW-155)
- Display release date in Updater and Packagemanager. (QTIFW-25) - Display release date in Updater and Packagemanager. (QTIFW-25)
@ -41,6 +49,7 @@
- Minor documentation fixes and additions. - Minor documentation fixes and additions.
- Added more autotests. - Added more autotests.
- Bugfixes - Bugfixes
- Added Japanese translation.
- Updated translations - Updated translations
- Cleaned up the Code. - Cleaned up the Code.

View File

@ -199,10 +199,10 @@
\o Filename for a watermark used as \a QWizard::WatermarkPixmap. \o Filename for a watermark used as \a QWizard::WatermarkPixmap.
\row \row
\o Banner \o Banner
\o Filename for a banner used as \a QWizard::BannerPixmap. \o Filename for a banner used as \a QWizard::BannerPixmap (only used by ModernStyle).
\row \row
\o Background \o Background
\o Filename for an image used as \a QWizard::BackgroundPixmap. \o Filename for an image used as \a QWizard::BackgroundPixmap (only used by MacStyle).
\row \row
\o RunProgram \o RunProgram
\o Command executed after the installer is done if the user accepts \o Command executed after the installer is done if the user accepts
@ -265,6 +265,10 @@
\o List of language codes to be used for translating the user interface. To add several language \o List of language codes to be used for translating the user interface. To add several language
variants, specify several Translation sections that each specify the name of a language variants, specify several Translation sections that each specify the name of a language
variant. Optional. For more information, see \l{Translating Pages}. variant. Optional. For more information, see \l{Translating Pages}.
\row
\o UrlQueryString
\o This string needs to be in the form "key=value" and will be appended to archive download
requests. This can be used to transmit information to the webserver hosting the repository.
\endtable \endtable
@ -445,6 +449,7 @@
\row \row
\o Virtual \o Virtual
\o Set to \c true to hide the component from the installer. \o Set to \c true to hide the component from the installer.
Note that setting this on a root component does not work.
\row \row
\o SortingPriority \o SortingPriority
\o Priority of the component in the tree. The tree is sorted from \o Priority of the component in the tree. The tree is sorted from
@ -1007,34 +1012,35 @@
Updates.xml file in the current repository. You can add, replace, or remove Updates.xml file in the current repository. You can add, replace, or remove
repositories. repositories.
\section2 Adding Repositories
To update a repository, add the following code to Updates.xml:
\code \code
<RepositoryUpdate> <RepositoryUpdate>
<Repository action="add" url="http://www.example.com/repository" name="user" password="password" <Repository action="..." OPTIONS />
displayname="Example Repository" /> <Repository action="..." OPTIONS />
</RepositoryUpdate> </RepositoryUpdate>
\endcode \endcode
\section2 Adding Repositories
To update a repository, add the following code to the RepositoryUpdate section:
\code
<Repository action="add" url="http://www.example.com/repository" name="user" password="password"
displayname="Example Repository" />
\endcode
\section2 Removing Repositories \section2 Removing Repositories
To remove a repository, add the following code to Updates.xml: To remove a repository, add the following code to the RepositoryUpdate section:
\code \code
<RepositoryUpdate> <Repository action="remove" url="http://www.example.com/repository" />
<Repository action="remove" url="http://www.example.com/repository" />
</RepositoryUpdate>
\endcode \endcode
\section2 Replacing repositories \section2 Replacing repositories
To replace one repository with another, add the following code to Updates.xml: To replace one repository with another, add the following code to the RepositoryUpdate section:
\code \code
<RepositoryUpdate> <Repository action="replace" oldurl="http://www.example.com/repository"
<Repository action="replace" oldurl="http://www.example.com/repository" newurl="http://www.example.com/newrepository" name="user" password="password"
newurl="http://www.example.com/newrepository" name="user" password="password" displayname="New Example Repository" />
displayname="New Example Repository" />
</RepositoryUpdate>
\endcode \endcode
*/ */

View File

@ -56,6 +56,9 @@ unix:INCLUDEPATH += $$IFW_SOURCE_TREE/src/libs/7zip/unix/CPP
LIBS += -L$$IFW_LIB_PATH LIBS += -L$$IFW_LIB_PATH
# The order is important. The linker needs to parse archives in reversed dependency order. # The order is important. The linker needs to parse archives in reversed dependency order.
equals(TEMPLATE, app):LIBS += -linstaller equals(TEMPLATE, app):LIBS += -linstaller
win32:equals(TEMPLATE, app) {
LIBS += -luser32
}
unix:!macx:LIBS += -lutil unix:!macx:LIBS += -lutil
macx:LIBS += -framework Carbon -framework Security macx:LIBS += -framework Carbon -framework Security
@ -106,6 +109,9 @@ static {
LIBS += -l7z LIBS += -l7z
win32-g++*: LIBS += -lmpr -luuid win32-g++*: LIBS += -lmpr -luuid
win32:exists($$IFW_LIB_PATH/installer.lib):POST_TARGETDEPS += $$IFW_LIB_PATH/installer.lib equals(TEMPLATE, app) {
unix:exists($$IFW_LIB_PATH/libinstaller.a):POST_TARGETDEPS += $$IFW_LIB_PATH/libinstaller.a win32-msvc*:POST_TARGETDEPS += $$IFW_LIB_PATH/installer.lib $$IFW_LIB_PATH/7z.lib
win32-g++*:POST_TARGETDEPS += $$IFW_LIB_PATH/libinstaller.a $$IFW_LIB_PATH/lib7z.a
unix:POST_TARGETDEPS += $$IFW_LIB_PATH/libinstaller.a $$IFW_LIB_PATH/lib7z.a
}
} }

View File

@ -1,8 +1,7 @@
include(../../../installerfw.pri)
QT = core QT = core
TARGET = 7z TARGET = 7z
TEMPLATE = lib TEMPLATE = lib
include(../../../installerfw.pri)
INCLUDEPATH += . .. INCLUDEPATH += . ..
CONFIG += staticlib CONFIG += staticlib
DESTDIR = $$IFW_LIB_PATH DESTDIR = $$IFW_LIB_PATH

View File

@ -55,6 +55,7 @@
#include <QTemporaryFile> #include <QTemporaryFile>
#include <errno.h> #include <errno.h>
#include <string.h>
using namespace QInstaller; using namespace QInstaller;
using namespace QInstallerCreator; using namespace QInstallerCreator;
@ -220,33 +221,26 @@ qint64 QInstaller::findMagicCookie(QFile *in, quint64 magicCookie)
Q_ASSERT(in); Q_ASSERT(in);
Q_ASSERT(in->isOpen()); Q_ASSERT(in->isOpen());
Q_ASSERT(in->isReadable()); Q_ASSERT(in->isReadable());
const qint64 oldPos = in->pos();
const qint64 MAX_SEARCH = 1024 * 1024; // stop searching after one MB const qint64 fileSize = in->size();
qint64 searched = 0; const size_t markerSize = sizeof(qint64);
try {
while (searched < MAX_SEARCH) { // Search through 1MB, if smaller through the whole file. Note: QFile::map() does not change QFile::pos().
const qint64 pos = in->size() - searched - sizeof(qint64); const qint64 maxSearch = qMin((1024LL * 1024LL), fileSize);
if (pos < 0) const uchar *const mapped = in->map(fileSize - maxSearch, maxSearch);
throw Error(QObject::tr("Searched whole file, no marker found")); if (!mapped) {
if (!in->seek(pos)) { throw Error(QObject::tr("Could not map %1 from file %2: %3").arg(QString::number(maxSearch),
throw Error(QObject::tr("Could not seek to %1 in file %2: %3").arg(QString::number(pos), in->fileName(), in->errorString()));
in->fileName(), in->errorString()));
}
const quint64 num = static_cast<quint64>(retrieveInt64(in));
if (num == magicCookie) {
in->seek(oldPos);
return pos;
}
searched += 1;
}
throw Error(QObject::tr("No marker found, stopped after %1.").arg(humanReadableSize(MAX_SEARCH)));
} catch (const Error& err) {
in->seek(oldPos);
throw err;
} catch (...) {
in->seek(oldPos);
throw Error(QObject::tr("No marker found, unknown exception caught."));
} }
qint64 searched = maxSearch - markerSize;
while (searched >= 0) {
if (memcmp(&magicCookie, (mapped + searched), markerSize) == 0)
return (fileSize - maxSearch) + searched;
--searched;
}
throw Error(QObject::tr("No marker found, stopped after %1.").arg(humanReadableSize(maxSearch)));
return -1; // never reached return -1; // never reached
} }
@ -802,7 +796,7 @@ BinaryContentPrivate::BinaryContentPrivate(const BinaryContentPrivate &other)
BinaryContentPrivate::~BinaryContentPrivate() BinaryContentPrivate::~BinaryContentPrivate()
{ {
foreach (const QByteArray &rccData, m_resourceMappings) foreach (const QByteArray &rccData, m_resourceMappings)
QResource::unregisterResource((const uchar*)rccData.constData()); QResource::unregisterResource((const uchar*)rccData.constData(), QLatin1String(":/metadata"));
m_resourceMappings.clear(); m_resourceMappings.clear();
} }
@ -1143,6 +1137,29 @@ int BinaryContent::registerEmbeddedQResources()
return d->m_resourceMappings.count(); 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);
}
}
/*! /*!
Returns the binary component index as read from the file. Returns the binary component index as read from the file.
*/ */

View File

@ -242,6 +242,7 @@ public:
qint64 magicMarker() const; qint64 magicMarker() const;
int registerEmbeddedQResources(); int registerEmbeddedQResources();
void registerAsDefaultQResource(const QString &path);
QInstallerCreator::ComponentIndex componentIndex() const; QInstallerCreator::ComponentIndex componentIndex() const;
private: private:

View File

@ -211,6 +211,7 @@ Component::Component(PackageManagerCore *core)
setPrivate(d); setPrivate(d);
connect(this, SIGNAL(valueChanged(QString, QString)), this, SLOT(updateModelData(QString, QString))); connect(this, SIGNAL(valueChanged(QString, QString)), this, SLOT(updateModelData(QString, QString)));
qRegisterMetaType<QList<QInstaller::Component*> >("QList<QInstaller::Component*>");
} }
/*! /*!
@ -899,6 +900,7 @@ OperationList Component::operations() const
if (!d->m_minimumProgressOperation) { if (!d->m_minimumProgressOperation) {
d->m_minimumProgressOperation = KDUpdater::UpdateOperationFactory::instance() d->m_minimumProgressOperation = KDUpdater::UpdateOperationFactory::instance()
.create(QLatin1String("MinimumProgress")); .create(QLatin1String("MinimumProgress"));
d->m_minimumProgressOperation->setValue(QLatin1String("component"), name());
d->m_operations.append(d->m_minimumProgressOperation); d->m_operations.append(d->m_minimumProgressOperation);
} }
@ -906,6 +908,7 @@ OperationList Component::operations() const
d->m_licenseOperation = KDUpdater::UpdateOperationFactory::instance() d->m_licenseOperation = KDUpdater::UpdateOperationFactory::instance()
.create(QLatin1String("License")); .create(QLatin1String("License"));
d->m_licenseOperation->setValue(QLatin1String("installer"), QVariant::fromValue(d->m_core)); d->m_licenseOperation->setValue(QLatin1String("installer"), QVariant::fromValue(d->m_core));
d->m_licenseOperation->setValue(QLatin1String("component"), name());
QVariantMap licenses; QVariantMap licenses;
const QList<QPair<QString, QString> > values = d->m_licenses.values(); const QList<QPair<QString, QString> > values = d->m_licenses.values();

View File

@ -182,7 +182,7 @@ void DownloadArchivesJob::fetchNextArchive()
if (m_downloader != 0) if (m_downloader != 0)
m_downloader->deleteLater(); m_downloader->deleteLater();
m_downloader = setupDownloader(); m_downloader = setupDownloader(QString(), m_core->value(QLatin1String("UrlQueryString")));
if (!m_downloader) { if (!m_downloader) {
m_archivesToDownload.removeFirst(); m_archivesToDownload.removeFirst();
QMetaObject::invokeMethod(this, "fetchNextArchive", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "fetchNextArchive", Qt::QueuedConnection);
@ -292,13 +292,16 @@ void DownloadArchivesJob::finishWithError(const QString &error)
emitFinishedWithError(QInstaller::DownloadError, msg.arg(error, m_downloader->url().toString())); emitFinishedWithError(QInstaller::DownloadError, msg.arg(error, m_downloader->url().toString()));
} }
KDUpdater::FileDownloader *DownloadArchivesJob::setupDownloader(const QString &suffix) KDUpdater::FileDownloader *DownloadArchivesJob::setupDownloader(const QString &suffix, const QString &queryString)
{ {
KDUpdater::FileDownloader *downloader = 0; KDUpdater::FileDownloader *downloader = 0;
const QFileInfo fi = QFileInfo(m_archivesToDownload.first().first); const QFileInfo fi = QFileInfo(m_archivesToDownload.first().first);
const Component *const component = m_core->componentByName(QFileInfo(fi.path()).fileName()); const Component *const component = m_core->componentByName(QFileInfo(fi.path()).fileName());
if (component) { if (component) {
const QUrl url(m_archivesToDownload.first().second + suffix); QString fullQueryString;
if (!queryString.isEmpty())
fullQueryString = QLatin1String("?") + queryString;
const QUrl url(m_archivesToDownload.first().second + suffix + fullQueryString);
const QString &scheme = url.scheme(); const QString &scheme = url.scheme();
downloader = FileDownloaderFactory::instance().create(scheme, this); downloader = FileDownloaderFactory::instance().create(scheme, this);

View File

@ -91,7 +91,7 @@ protected Q_SLOTS:
void emitDownloadProgress(double progress); void emitDownloadProgress(double progress);
private: private:
KDUpdater::FileDownloader *setupDownloader(const QString &suffix = QString()); KDUpdater::FileDownloader *setupDownloader(const QString &suffix = QString(), const QString &queryString = QString());
private: private:
PackageManagerCore *m_core; PackageManagerCore *m_core;

View File

@ -75,13 +75,12 @@ bool ExtractArchiveOperation::performOperation()
Receiver receiver; Receiver receiver;
Callback callback; Callback callback;
// usually we have to connect it as queued connection but then some blocking work is in the main thread connect(&callback, SIGNAL(currentFileChanged(QString)), this, SLOT(fileFinished(QString)));
connect(&callback, SIGNAL(progressChanged(QString)), this, SLOT(slotProgressChanged(QString)), connect(&callback, SIGNAL(progressChanged(double)), this, SIGNAL(progressChanged(double)));
Qt::DirectConnection);
if (PackageManagerCore *core = this->value(QLatin1String("installer")).value<PackageManagerCore*>()) { if (PackageManagerCore *core = this->value(QLatin1String("installer")).value<PackageManagerCore*>()) {
connect(core, SIGNAL(statusChanged(QInstaller::PackageManagerCore::Status)), &callback, connect(core, SIGNAL(statusChanged(QInstaller::PackageManagerCore::Status)), &callback,
SLOT(statusChanged(QInstaller::PackageManagerCore::Status)), Qt::QueuedConnection); SLOT(statusChanged(QInstaller::PackageManagerCore::Status)));
} }
//Runnable is derived from QRunable which will be deleted by the ThreadPool -> no parent is needed //Runnable is derived from QRunable which will be deleted by the ThreadPool -> no parent is needed
@ -125,8 +124,8 @@ bool ExtractArchiveOperation::undoOperation()
const QStringList files = value(QLatin1String("files")).toStringList(); const QStringList files = value(QLatin1String("files")).toStringList();
WorkerThread *const thread = new WorkerThread(this, files); WorkerThread *const thread = new WorkerThread(this, files);
connect(thread, SIGNAL(outputTextChanged(QString)), this, SIGNAL(outputTextChanged(QString)), connect(thread, SIGNAL(currentFileChanged(QString)), this, SIGNAL(outputTextChanged(QString)));
Qt::QueuedConnection); connect(thread, SIGNAL(progressChanged(double)), this, SIGNAL(progressChanged(double)));
QEventLoop loop; QEventLoop loop;
connect(thread, SIGNAL(finished()), &loop, SLOT(quit()), Qt::QueuedConnection); connect(thread, SIGNAL(finished()), &loop, SLOT(quit()), Qt::QueuedConnection);
@ -149,7 +148,7 @@ Operation *ExtractArchiveOperation::clone() const
/*! /*!
This slot is direct connected to the caller so please don't call it from another thread in the same time. This slot is direct connected to the caller so please don't call it from another thread in the same time.
*/ */
void ExtractArchiveOperation::slotProgressChanged(const QString &filename) void ExtractArchiveOperation::fileFinished(const QString &filename)
{ {
QStringList files = value(QLatin1String("files")).toStringList(); QStringList files = value(QLatin1String("files")).toStringList();
files.prepend(filename); files.prepend(filename);

View File

@ -64,9 +64,10 @@ public:
Q_SIGNALS: Q_SIGNALS:
void outputTextChanged(const QString &progress); void outputTextChanged(const QString &progress);
void progressChanged(double);
private Q_SLOTS: private Q_SLOTS:
void slotProgressChanged(const QString &progress); void fileFinished(const QString &progress);
private: private:
class Callback; class Callback;

View File

@ -71,9 +71,12 @@ public:
ExtractArchiveOperation *const op = m_op;//dynamic_cast< ExtractArchiveOperation* >(parent()); ExtractArchiveOperation *const op = m_op;//dynamic_cast< ExtractArchiveOperation* >(parent());
Q_ASSERT(op != 0); Q_ASSERT(op != 0);
int removedCounter = 0;
foreach (const QString &file, m_files) { foreach (const QString &file, m_files) {
removedCounter++;
const QFileInfo fi(file); const QFileInfo fi(file);
emit outputTextChanged(file); emit currentFileChanged(file);
emit progressChanged(double(removedCounter) / m_files.count());
if (fi.isFile() || fi.isSymLink()) { if (fi.isFile() || fi.isSymLink()) {
op->deleteFileNowOrLater(fi.absoluteFilePath()); op->deleteFileNowOrLater(fi.absoluteFilePath());
} else if (fi.isDir()) { } else if (fi.isDir()) {
@ -85,7 +88,8 @@ public:
} }
Q_SIGNALS: Q_SIGNALS:
void outputTextChanged(const QString &filename); void currentFileChanged(const QString &filename);
void progressChanged(double);
private: private:
QStringList m_files; QStringList m_files;
@ -105,7 +109,8 @@ public:
Callback() : state(S_OK), createBackups(true) {} Callback() : state(S_OK), createBackups(true) {}
Q_SIGNALS: Q_SIGNALS:
void progressChanged(const QString &filename); void currentFileChanged(const QString &filename);
void progressChanged(double progress);
public Q_SLOTS: public Q_SLOTS:
void statusChanged(QInstaller::PackageManagerCore::Status status) void statusChanged(QInstaller::PackageManagerCore::Status status)
@ -130,7 +135,7 @@ public Q_SLOTS:
protected: protected:
void setCurrentFile(const QString &filename) void setCurrentFile(const QString &filename)
{ {
emit progressChanged(QDir::toNativeSeparators(filename)); emit currentFileChanged(QDir::toNativeSeparators(filename));
} }
static QString generateBackupName(const QString &fn) static QString generateBackupName(const QString &fn)
@ -161,8 +166,9 @@ protected:
return true; return true;
} }
HRESULT setCompleted(quint64 /*completed*/, quint64 /*total*/) HRESULT setCompleted(quint64 completed, quint64 total)
{ {
emit progressChanged(double(completed) / total);
return state; return state;
} }
}; };

View File

@ -289,8 +289,7 @@ void QInstaller::removeDirectory(const QString &path, bool ignoreErrors)
QDirIterator it(path, QDir::NoDotAndDotDot | QDir::Dirs | QDir::NoSymLinks | QDir::Hidden, QDirIterator it(path, QDir::NoDotAndDotDot | QDir::Dirs | QDir::NoSymLinks | QDir::Hidden,
QDirIterator::Subdirectories); QDirIterator::Subdirectories);
while (it.hasNext()) { while (it.hasNext()) {
it.next(); dirs.prepend(it.next());
dirs.prepend(it.filePath());
removeFiles(dirs.at(0), ignoreErrors); removeFiles(dirs.at(0), ignoreErrors);
} }
@ -461,14 +460,18 @@ QString QInstaller::generateTemporaryFileName(const QString &templ)
return f.fileName(); return f.fileName();
} }
QString QInstaller::createTemporaryDirectory(const QString &templ) QString QInstaller::createTemporaryDirectory(const QString &templateName)
{ {
const QString t = QDir::tempPath() + QLatin1String("/") + templ + QLatin1String("XXXXXX"); QString path = QDir::tempPath() + QLatin1String("/") + templateName + QLatin1String("XXXXXX");
QTemporaryFile f(t); {
if (!f.open()) QTemporaryFile f(path);
throw Error(QObject::tr("Could not create temporary folder for template %1: %2").arg(t, f.errorString())); if (!f.open()) {
const QString path = f.fileName() + QLatin1String("meta"); throw Error(QObject::tr("Could not create temporary directory %1: %2").arg(f.fileName(),
qDebug() << "\nCreating meta data directory at" << path; f.errorString()));
}
path = f.fileName();
}
qDebug() << "\nCreating temporary directory at:" << path;
QInstaller::mkpath(path); QInstaller::mkpath(path);
return path; return path;

View File

@ -108,7 +108,7 @@ private:
Creates a temporary directory Creates a temporary directory
@throws QInstaller::Error if creating the temporary directory fails @throws QInstaller::Error if creating the temporary directory fails
*/ */
QString INSTALLER_EXPORT createTemporaryDirectory(const QString &templ=QString()); QString INSTALLER_EXPORT createTemporaryDirectory(const QString &templateName = QString());
QString INSTALLER_EXPORT generateTemporaryFileName(const QString &templ=QString()); QString INSTALLER_EXPORT generateTemporaryFileName(const QString &templ=QString());

View File

@ -49,6 +49,8 @@
#include "kdupdaterfiledownloader.h" #include "kdupdaterfiledownloader.h"
#include "kdupdaterfiledownloaderfactory.h" #include "kdupdaterfiledownloaderfactory.h"
#include "productkeycheck.h"
#include <QTimer> #include <QTimer>
@ -197,14 +199,14 @@ void GetRepositoryMetaInfoJob::startUpdatesXmlDownload()
} }
if (!url.isValid()) { if (!url.isValid()) {
finished(QInstaller::InvalidUrl, tr("Invalid repository URL: %1").arg(url.toString())); finished(QInstaller::InvalidUrl, tr("Invalid repository URL: %1").arg(m_repository.displayname()));
return; return;
} }
m_downloader = FileDownloaderFactory::instance().create(url.scheme(), this); m_downloader = FileDownloaderFactory::instance().create(url.scheme(), this);
if (!m_downloader) { if (!m_downloader) {
finished(QInstaller::InvalidUrl, tr("URL scheme not supported: %1 (%2)").arg(url.scheme(), finished(QInstaller::InvalidUrl, tr("URL scheme not supported: %1 (%2)").arg(url.scheme(),
url.toString())); m_repository.displayname()));
return; return;
} }
@ -244,20 +246,7 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadFinished()
Q_ASSERT(!fn.isEmpty()); Q_ASSERT(!fn.isEmpty());
Q_ASSERT(QFile::exists(fn)); Q_ASSERT(QFile::exists(fn));
try {
m_temporaryDirectory = createTemporaryDirectory(QLatin1String("remoterepo"));
m_tempDirDeleter.add(m_temporaryDirectory);
} catch (const QInstaller::Error& e) {
finished(QInstaller::ExtractionError, e.message());
return;
}
QFile updatesFile(fn); QFile updatesFile(fn);
if (!updatesFile.rename(m_temporaryDirectory + QLatin1String("/Updates.xml"))) {
finished(QInstaller::DownloadError, tr("Could not move Updates.xml to target location. Error: %1")
.arg(updatesFile.errorString()));
return;
}
if (!updatesFile.open(QIODevice::ReadOnly)) { if (!updatesFile.open(QIODevice::ReadOnly)) {
finished(QInstaller::DownloadError, tr("Could not open Updates.xml for reading. Error: %1") finished(QInstaller::DownloadError, tr("Could not open Updates.xml for reading. Error: %1")
@ -272,7 +261,7 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadFinished()
if (!success) { if (!success) {
const QString msg = tr("Could not fetch a valid version of Updates.xml from repository: %1. " const QString msg = tr("Could not fetch a valid version of Updates.xml from repository: %1. "
"Error: %2").arg(m_repository.url().toString(), err); "Error: %2").arg(m_repository.displayname(), err);
const QMessageBox::StandardButton b = const QMessageBox::StandardButton b =
MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
@ -302,15 +291,16 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadFinished()
repository.setUsername(el.attribute(QLatin1String("username"))); repository.setUsername(el.attribute(QLatin1String("username")));
repository.setPassword(el.attribute(QLatin1String("password"))); repository.setPassword(el.attribute(QLatin1String("password")));
repository.setDisplayName(el.attribute(QLatin1String("displayname"))); repository.setDisplayName(el.attribute(QLatin1String("displayname")));
repositoryUpdates.insertMulti(action, qMakePair(repository, Repository())); if (ProductKeyCheck::instance()->isValidRepository(repository)) {
repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
qDebug() << "Repository to add:" << repository.url().toString(); qDebug() << "Repository to add:" << repository.displayname();
}
} else if (action == QLatin1String("remove")) { } else if (action == QLatin1String("remove")) {
// remove possible default repositories using the given server url // remove possible default repositories using the given server url
Repository repository(el.attribute(QLatin1String("url")), true); Repository repository(el.attribute(QLatin1String("url")), true);
repositoryUpdates.insertMulti(action, qMakePair(repository, Repository())); repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
qDebug() << "Repository to remove:" << repository.url().toString(); qDebug() << "Repository to remove:" << repository.displayname();
} else if (action == QLatin1String("replace")) { } else if (action == QLatin1String("replace")) {
// replace possible default repositories using the given server url // replace possible default repositories using the given server url
Repository oldRepository(el.attribute(QLatin1String("oldUrl")), true); Repository oldRepository(el.attribute(QLatin1String("oldUrl")), true);
@ -319,19 +309,42 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadFinished()
newRepository.setPassword(el.attribute(QLatin1String("password"))); newRepository.setPassword(el.attribute(QLatin1String("password")));
newRepository.setDisplayName(el.attribute(QLatin1String("displayname"))); newRepository.setDisplayName(el.attribute(QLatin1String("displayname")));
// store the new repository and the one old it replaces if (ProductKeyCheck::instance()->isValidRepository(newRepository)) {
repositoryUpdates.insertMulti(action, qMakePair(newRepository, oldRepository)); // store the new repository and the one old it replaces
qDebug() << "Replace repository:" << oldRepository.url().toString() << "with:" repositoryUpdates.insertMulti(action, qMakePair(newRepository, oldRepository));
<< newRepository.url().toString(); qDebug() << "Replace repository:" << oldRepository.displayname() << "with:"
<< newRepository.displayname();
}
} else { } else {
qDebug() << "Invalid additional repositories action set in Updates.xml fetched from:" qDebug() << "Invalid additional repositories action set in Updates.xml fetched from:"
<< m_repository.url().toString() << "Line:" << el.lineNumber(); << m_repository.displayname() << "Line:" << el.lineNumber();
} }
} }
} }
if (!repositoryUpdates.isEmpty()) { if (!repositoryUpdates.isEmpty()) {
if (m_core->settings().updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) { const QSet<Repository> temporaries = m_core->settings().temporaryRepositories();
// in case the temp repository introduced something new, we only want that temporary
if (temporaries.contains(m_repository)) {
QSet<Repository> childTempRepositories;
typedef QPair<Repository, Repository> RepositoryPair;
QList<RepositoryPair> values = repositoryUpdates.values(QLatin1String("add"));
foreach (const RepositoryPair &value, values)
childTempRepositories.insert(value.first);
values = repositoryUpdates.values(QLatin1String("replace"));
foreach (const RepositoryPair &value, values)
childTempRepositories.insert(value.first);
QSet<Repository> newChildTempRepositories = childTempRepositories.subtract(temporaries);
if (newChildTempRepositories.count() > 0) {
m_core->settings().addTemporaryRepositories(newChildTempRepositories, true);
finished(QInstaller::RepositoryUpdatesReceived, tr("Repository updates received."));
return;
}
} else if (m_core->settings().updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) {
if (m_core->isUpdater() || m_core->isPackageManager()) if (m_core->isUpdater() || m_core->isPackageManager())
m_core->writeMaintenanceConfigFiles(); m_core->writeMaintenanceConfigFiles();
finished(QInstaller::RepositoryUpdatesReceived, tr("Repository updates received.")); finished(QInstaller::RepositoryUpdatesReceived, tr("Repository updates received."));
@ -358,6 +371,19 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadFinished()
} }
} }
try {
m_temporaryDirectory = createTemporaryDirectory(QLatin1String("remoterepo-"));
m_tempDirDeleter.add(m_temporaryDirectory);
} catch (const QInstaller::Error& e) {
finished(QInstaller::ExtractionError, e.message());
return;
}
if (!updatesFile.rename(m_temporaryDirectory + QLatin1String("/Updates.xml"))) {
finished(QInstaller::DownloadError, tr("Could not move Updates.xml to target location. Error: %1")
.arg(updatesFile.errorString()));
return;
}
setTotalAmount(m_packageNames.count() + 1); setTotalAmount(m_packageNames.count() + 1);
setProcessedAmount(1); setProcessedAmount(1);
emit infoMessage(this, tr("Finished updating component meta information.")); emit infoMessage(this, tr("Finished updating component meta information."));
@ -427,7 +453,7 @@ void GetRepositoryMetaInfoJob::fetchNextMetaInfo()
if (!m_downloader) { if (!m_downloader) {
m_currentPackageName.clear(); m_currentPackageName.clear();
m_currentPackageVersion.clear(); m_currentPackageVersion.clear();
qWarning() << "Scheme not supported:" << url.toString(); qWarning() << "Scheme not supported:" << m_repository.displayname();
QMetaObject::invokeMethod(this, "fetchNextMetaInfo", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "fetchNextMetaInfo", Qt::QueuedConnection);
return; return;
} }

View File

@ -421,7 +421,7 @@ void PackageManagerCore::writeMaintenanceConfigFiles()
void PackageManagerCore::reset(const QHash<QString, QString> &params) void PackageManagerCore::reset(const QHash<QString, QString> &params)
{ {
d->m_completeUninstall = false; d->m_completeUninstall = false;
d->m_forceRestart = false; d->m_needsHardRestart = false;
d->m_status = PackageManagerCore::Unfinished; d->m_status = PackageManagerCore::Unfinished;
d->m_installerBaseBinaryUnreplaced.clear(); d->m_installerBaseBinaryUnreplaced.clear();
@ -596,11 +596,17 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize)
If a component marked as important was installed during update If a component marked as important was installed during update
process true is returned. process true is returned.
*/ */
bool PackageManagerCore::needsRestart() const bool PackageManagerCore::needsHardRestart() const
{ {
return d->m_forceRestart; return d->m_needsHardRestart;
} }
void PackageManagerCore::setNeedsHardRestart(bool needsHardRestart)
{
d->m_needsHardRestart = needsHardRestart;
}
void PackageManagerCore::rollBackInstallation() void PackageManagerCore::rollBackInstallation()
{ {
emit titleMessageChanged(tr("Cancelling the Installer")); emit titleMessageChanged(tr("Cancelling the Installer"));

View File

@ -248,7 +248,8 @@ public:
int downloadNeededArchives(double partProgressSize); int downloadNeededArchives(double partProgressSize);
bool needsRestart() const; bool needsHardRestart() const;
void setNeedsHardRestart(bool needsHardRestart = true);
bool finishedWithSuccess() const; bool finishedWithSuccess() const;
public Q_SLOTS: public Q_SLOTS:

View File

@ -225,7 +225,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_updaterApplication(new DummyConfigurationInterface) , m_updaterApplication(new DummyConfigurationInterface)
, m_FSEngineClientHandler(initFSEngineClientHandler()) , m_FSEngineClientHandler(initFSEngineClientHandler())
, m_status(PackageManagerCore::Unfinished) , m_status(PackageManagerCore::Unfinished)
, m_forceRestart(false) , m_needsHardRestart(false)
, m_testChecksum(false) , m_testChecksum(false)
, m_launchedAsRoot(AdminAuthorization::hasAdminRights()) , m_launchedAsRoot(AdminAuthorization::hasAdminRights())
, m_completeUninstall(false) , m_completeUninstall(false)
@ -1094,7 +1094,25 @@ void PackageManagerCorePrivate::writeUninstallerBinaryData(QIODevice *output, QF
const qint64 dataBlockStart = output->pos(); const qint64 dataBlockStart = output->pos();
QVector<Range<qint64> >resourceSegments; QVector<Range<qint64> >resourceSegments;
foreach (const Range<qint64> &segment, layout.metadataResourceSegments) { QVector<Range<qint64> >existingResourceSegments = layout.metadataResourceSegments;
const QString newDefaultResource = m_core->value(QString::fromLatin1("DefaultResourceReplacement"));
if (!newDefaultResource.isEmpty()) {
QFile file(newDefaultResource);
if (file.open(QIODevice::ReadOnly)) {
resourceSegments.append(Range<qint64>::fromStartAndLength(output->pos(), file.size()));
appendData(output, &file, file.size());
existingResourceSegments.remove(0);
file.remove(); // clear all possible leftovers
m_core->setValue(QString::fromLatin1("DefaultResourceReplacement"), QString());
} else {
qWarning() << QString::fromLatin1("Could not replace default resource with '%1'.")
.arg(newDefaultResource);
}
}
foreach (const Range<qint64> &segment, existingResourceSegments) {
input->seek(segment.start()); input->seek(segment.start());
resourceSegments.append(Range<qint64>::fromStartAndLength(output->pos(), segment.length())); resourceSegments.append(Range<qint64>::fromStartAndLength(output->pos(), segment.length()));
appendData(output, input, segment.length()); appendData(output, input, segment.length());
@ -1156,8 +1174,6 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio
performedOperations.append(takeOwnedOperation(op)); performedOperations.append(takeOwnedOperation(op));
} }
writeMaintenanceConfigFiles();
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
// if it is a bundle, we need some stuff in it... // if it is a bundle, we need some stuff in it...
const QString sourceAppDirPath = QCoreApplication::applicationDirPath(); const QString sourceAppDirPath = QCoreApplication::applicationDirPath();
@ -1264,7 +1280,7 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio
bool newBinaryWritten = false; bool newBinaryWritten = false;
bool replacementExists = false; bool replacementExists = false;
const QString installerBaseBinary = m_core->replaceVariables(m_installerBaseBinaryUnreplaced); const QString installerBaseBinary = replaceVariables(m_installerBaseBinaryUnreplaced);
if (!installerBaseBinary.isEmpty() && QFileInfo(installerBaseBinary).exists()) { if (!installerBaseBinary.isEmpty() && QFileInfo(installerBaseBinary).exists()) {
qDebug() << "Got a replacement installer base binary:" << installerBaseBinary; qDebug() << "Got a replacement installer base binary:" << installerBaseBinary;
@ -1272,8 +1288,8 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio
try { try {
openForRead(&replacementBinary, replacementBinary.fileName()); openForRead(&replacementBinary, replacementBinary.fileName());
writeUninstallerBinary(&replacementBinary, replacementBinary.size(), true); writeUninstallerBinary(&replacementBinary, replacementBinary.size(), true);
qDebug() << "Wrote the binary with the new replacement.";
m_forceRestart = true;
newBinaryWritten = true; newBinaryWritten = true;
replacementExists = true; replacementExists = true;
} catch (const Error &error) { } catch (const Error &error) {
@ -1283,10 +1299,17 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio
if (!replacementBinary.remove()) { if (!replacementBinary.remove()) {
// Is there anything more sensible we can do with this error? I think not. It's not serious // Is there anything more sensible we can do with this error? I think not. It's not serious
// enough for throwing / aborting the process. // enough for throwing / aborting the process.
qDebug() << QString::fromLatin1("Could not remove installer base binary (%1) after updating " qDebug() << QString::fromLatin1("Could not remove installer base binary '%1' after updating "
"the uninstaller: %2").arg(installerBaseBinary, replacementBinary.errorString()); "the uninstaller: %2").arg(installerBaseBinary, replacementBinary.errorString());
} else {
qDebug() << QString::fromLatin1("Removed installer base binary '%1' after updating the "
"uninstaller/ maintenance tool.").arg(installerBaseBinary);
} }
m_installerBaseBinaryUnreplaced.clear(); m_installerBaseBinaryUnreplaced.clear();
} else if (!installerBaseBinary.isEmpty() && !QFileInfo(installerBaseBinary).exists()) {
qWarning() << QString::fromLatin1("The current uninstaller/ maintenance tool could not be "
"updated. '%1' does not exist. Please fix the 'setInstallerBaseBinary(<temp_installer_base_"
"binary_path>)' call in your script.").arg(installerBaseBinary);
} }
QFile input; QFile input;
@ -1330,9 +1353,7 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio
#endif #endif
} }
performedOperations = sortOperationsBasedOnComponentDependencies( performedOperations = sortOperationsBasedOnComponentDependencies(performedOperations);
performedOperations);
m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true")); m_core->setValue(QLatin1String("installedOperationAreSorted"), QLatin1String("true"));
try { try {
@ -1363,10 +1384,11 @@ void PackageManagerCorePrivate::writeUninstaller(OperationList performedOperatio
appendInt64(&file, MagicCookie); appendInt64(&file, MagicCookie);
} }
input.close(); input.close();
writeMaintenanceConfigFiles();
deferredRename(dataFile + QLatin1String(".new"), dataFile, false); deferredRename(dataFile + QLatin1String(".new"), dataFile, false);
if (newBinaryWritten) { if (newBinaryWritten) {
const bool restart = replacementExists && isUpdater() && (!statusCanceledOrFailed()); const bool restart = replacementExists && isUpdater() && (!statusCanceledOrFailed()) && m_needsHardRestart;
deferredRename(uninstallerName() + QLatin1String(".new"), uninstallerName(), restart); deferredRename(uninstallerName() + QLatin1String(".new"), uninstallerName(), restart);
qDebug() << "Maintenance tool restart:" << (restart ? "true." : "false."); qDebug() << "Maintenance tool restart:" << (restart ? "true." : "false.");
} }
@ -1888,7 +1910,7 @@ void PackageManagerCorePrivate::installComponent(Component *component, double pr
throw Error(operation->errorString()); throw Error(operation->errorString());
if (component->value(scEssential, scFalse) == scTrue) if (component->value(scEssential, scFalse) == scTrue)
m_forceRestart = true; m_needsHardRestart = true;
} }
registerPathesForUninstallation(component->pathesForUninstallation(), component->name()); registerPathesForUninstallation(component->pathesForUninstallation(), component->name());
@ -2389,9 +2411,11 @@ OperationList PackageManagerCorePrivate::sortOperationsBasedOnComponentDependenc
// create the complete component graph // create the complete component graph
Graph<QString> componentGraph; Graph<QString> componentGraph;
const QRegExp dash(QLatin1String("-.*"));
foreach (const Component* componentNode, m_core->availableComponents()) { foreach (const Component* componentNode, m_core->availableComponents()) {
componentGraph.addNode(componentNode->name()); componentGraph.addNode(componentNode->name());
componentGraph.addEdges(componentNode->name(), componentNode->dependencies()); const QStringList dependencies = componentNode->dependencies().replaceInStrings(dash,QString());
componentGraph.addEdges(componentNode->name(), dependencies);
} }
foreach (const QString &componentName, componentGraph.sort()) foreach (const QString &componentName, componentGraph.sort())

View File

@ -205,7 +205,7 @@ public:
int m_status; int m_status;
QString m_error; QString m_error;
bool m_forceRestart; bool m_needsHardRestart;
bool m_testChecksum; bool m_testChecksum;
bool m_launchedAsRoot; bool m_launchedAsRoot;
bool m_completeUninstall; bool m_completeUninstall;

View File

@ -138,7 +138,7 @@ QVariant PackageManagerCoreData::value(const QString &key, const QVariant &_defa
if (key == scTargetDir) { if (key == scTargetDir) {
QString dir = m_variables.value(key); QString dir = m_variables.value(key);
if (dir.isEmpty()) if (dir.isEmpty())
dir = m_settings.value(key, _default).toString(); dir = replaceVariables(m_settings.value(key, _default).toString());
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
return QInstaller::normalizePathName(dir); return QInstaller::normalizePathName(dir);
#else #else

View File

@ -128,7 +128,7 @@ public:
setPixmap(QWizard::BannerPixmap, QPixmap()); setPixmap(QWizard::BannerPixmap, QPixmap());
setLayout(new QVBoxLayout); setLayout(new QVBoxLayout);
setSubTitle(QString()); setSubTitle(QLatin1String(" "));
setTitle(widget->windowTitle()); setTitle(widget->windowTitle());
m_widget->setProperty("complete", true); m_widget->setProperty("complete", true);
m_widget->setProperty("final", false); m_widget->setProperty("final", false);
@ -248,7 +248,7 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent)
connect(m_core, SIGNAL(installationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection); connect(m_core, SIGNAL(installationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection);
connect(m_core, SIGNAL(uninstallationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection); connect(m_core, SIGNAL(uninstallationFinished()), this, SLOT(showFinishedPage()), Qt::QueuedConnection);
connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentPageChanged(int))); connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(executeControlScript(int)));
connect(this, SIGNAL(currentIdChanged(int)), m_core, SIGNAL(currentPageChanged(int))); connect(this, SIGNAL(currentIdChanged(int)), m_core, SIGNAL(currentPageChanged(int)));
connect(button(QWizard::FinishButton), SIGNAL(clicked()), this, SIGNAL(finishButtonClicked())); connect(button(QWizard::FinishButton), SIGNAL(clicked()), this, SIGNAL(finishButtonClicked()));
connect(button(QWizard::FinishButton), SIGNAL(clicked()), m_core, SIGNAL(finishButtonClicked())); connect(button(QWizard::FinishButton), SIGNAL(clicked()), m_core, SIGNAL(finishButtonClicked()));
@ -301,8 +301,8 @@ void PackageManagerGui::clickButton(int wb, int delay)
{ {
// transform the FinishButton to CancelButton, because of the needed misuse of the // transform the FinishButton to CancelButton, because of the needed misuse of the
// CancelButton as a FinishButton to have some more control of closing the wizard // CancelButton as a FinishButton to have some more control of closing the wizard
if (!m_core->isInstaller() && currentId() == PackageManagerCore::InstallationFinished && if ((m_core->isUpdater() || m_core->isPackageManager()) && currentId() ==
wb == QWizard::FinishButton) { PackageManagerCore::InstallationFinished && wb == QWizard::FinishButton) {
wb = QWizard::CancelButton; wb = QWizard::CancelButton;
} }
if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) )) if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) ))
@ -315,8 +315,8 @@ bool PackageManagerGui::isButtonEnabled(int wb)
{ {
// transform the FinishButton to CancelButton, because of the needed misuse of the // transform the FinishButton to CancelButton, because of the needed misuse of the
// CancelButton as a FinishButton to have some more control of closing the wizard // CancelButton as a FinishButton to have some more control of closing the wizard
if (!m_core->isInstaller() && currentId() == PackageManagerCore::InstallationFinished && if ((m_core->isUpdater() || m_core->isPackageManager()) && currentId() ==
wb == QWizard::FinishButton) { PackageManagerCore::InstallationFinished && wb == QWizard::FinishButton) {
wb = QWizard::CancelButton; wb = QWizard::CancelButton;
} }
if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) )) if (QAbstractButton *b = button(static_cast<QWizard::WizardButton>(wb) ))
@ -353,12 +353,6 @@ void PackageManagerGui::loadControlScript(const QString &scriptPath)
qDebug() << "Loaded control script" << scriptPath; qDebug() << "Loaded control script" << scriptPath;
} }
void PackageManagerGui::slotCurrentPageChanged(int id)
{
QMetaObject::invokeMethod(this, "delayedControlScriptExecution", Qt::QueuedConnection,
Q_ARG(int, id));
}
void PackageManagerGui::callControlScriptMethod(const QString &methodName) void PackageManagerGui::callControlScriptMethod(const QString &methodName)
{ {
if (!d->m_controlScriptContext.isValid()) if (!d->m_controlScriptContext.isValid())
@ -376,9 +370,9 @@ void PackageManagerGui::callControlScriptMethod(const QString &methodName)
} }
} }
void PackageManagerGui::delayedControlScriptExecution(int id) void PackageManagerGui::executeControlScript(int pageId)
{ {
if (PackageManagerPage *const p = qobject_cast<PackageManagerPage*> (page(id))) if (PackageManagerPage *const p = qobject_cast<PackageManagerPage*> (page(pageId)))
callControlScriptMethod(p->objectName() + QLatin1String("Callback")); callControlScriptMethod(p->objectName() + QLatin1String("Callback"));
} }
@ -524,6 +518,7 @@ void PackageManagerGui::cancelButtonClicked()
QDialog::reject(); QDialog::reject();
} }
} else { } else {
m_core->setNeedsHardRestart(false);
QDialog::reject(); QDialog::reject();
} }
} }
@ -1870,7 +1865,7 @@ void FinishedPage::entering()
if (!finishedText.isEmpty()) if (!finishedText.isEmpty())
m_msgLabel->setText(finishedText); m_msgLabel->setText(finishedText);
if (!packageManagerCore()->value(scRunProgram).isEmpty()) { if (!packageManagerCore()->isUninstaller() && !packageManagerCore()->value(scRunProgram).isEmpty()) {
m_runItCheckBox->show(); m_runItCheckBox->show();
m_runItCheckBox->setText(packageManagerCore()->value(scRunProgramDescription, tr("Run %1 now.")) m_runItCheckBox->setText(packageManagerCore()->value(scRunProgramDescription, tr("Run %1 now."))
.arg(productName())); .arg(productName()));
@ -1903,7 +1898,7 @@ void FinishedPage::handleFinishClicked()
{ {
const QString program = packageManagerCore()->replaceVariables(packageManagerCore()->value(scRunProgram)); const QString program = packageManagerCore()->replaceVariables(packageManagerCore()->value(scRunProgram));
const QStringList args = packageManagerCore()->replaceVariables( const QStringList args = packageManagerCore()->replaceVariables(
packageManagerCore()->value(scRunProgramArguments)).split(QLatin1Char(' ')); packageManagerCore()->value(scRunProgramArguments)).split(QLatin1Char(' '), QString::SkipEmptyParts);
if (!m_runItCheckBox->isChecked() || program.isEmpty()) if (!m_runItCheckBox->isChecked() || program.isEmpty())
return; return;
@ -1942,7 +1937,7 @@ int RestartPage::nextId() const
void RestartPage::entering() void RestartPage::entering()
{ {
if (!packageManagerCore()->needsRestart()) { if (!packageManagerCore()->needsHardRestart()) {
if (QAbstractButton *finish = wizard()->button(QWizard::FinishButton)) if (QAbstractButton *finish = wizard()->button(QWizard::FinishButton))
finish->setVisible(false); finish->setVisible(false);
QMetaObject::invokeMethod(this, "restart", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "restart", Qt::QueuedConnection);

View File

@ -116,8 +116,7 @@ protected Q_SLOTS:
void wizardWidgetInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page); void wizardWidgetInsertionRequested(QWidget *widget, QInstaller::PackageManagerCore::WizardPage page);
void wizardWidgetRemovalRequested(QWidget *widget); void wizardWidgetRemovalRequested(QWidget *widget);
void wizardPageVisibilityChangeRequested(bool visible, int page); void wizardPageVisibilityChangeRequested(bool visible, int page);
void slotCurrentPageChanged(int id); void executeControlScript(int pageId);
void delayedControlScriptExecution(int id);
void setValidatorForCustomPageRequested(QInstaller::Component *component, const QString &name, void setValidatorForCustomPageRequested(QInstaller::Component *component, const QString &name,
const QString &callbackName); const QString &callbackName);

View File

@ -103,6 +103,14 @@ void ProgressCoordinator::registerPartProgress(QObject *sender, const char *sign
Q_ASSERT(isConnected); Q_ASSERT(isConnected);
} }
/*!
This slot gets the progress changed signals from different tasks. The values 0 and 1 are handled as
special values.
0 - is just ignored, so you can use a timer which gives the progress, e.g. like a downloader does.
1 - means the task is finished, even if there comes another 1 from that task, so it will be ignored.
*/
void ProgressCoordinator::partProgressChanged(double fraction) void ProgressCoordinator::partProgressChanged(double fraction)
{ {
if (fraction < 0 || fraction > 1) { if (fraction < 0 || fraction > 1) {
@ -110,6 +118,16 @@ void ProgressCoordinator::partProgressChanged(double fraction)
return; return;
} }
// no fraction no change
if (fraction == 0)
return;
// ignore senders sending 100% multiple times
if (fraction == 1 && m_senderPendingCalculatedPercentageHash.contains(sender())
&& m_senderPendingCalculatedPercentageHash.value(sender()) == 0) {
return;
}
double partProgressSize = m_senderPartProgressSizeHash.value(sender(), 0); double partProgressSize = m_senderPartProgressSizeHash.value(sender(), 0);
if (partProgressSize == 0) { if (partProgressSize == 0) {
qWarning() << "It seems that this sender was not registered in the right way:" << sender(); qWarning() << "It seems that this sender was not registered in the right way:" << sender();
@ -137,9 +155,9 @@ void ProgressCoordinator::partProgressChanged(double fraction)
newCurrentCompletePercentage = 100; newCurrentCompletePercentage = 100;
} }
if (qRound(m_currentCompletePercentage) < qRound(newCurrentCompletePercentage)) { // In undo mode, the progress has to go backward, new has to be smaller than current
qWarning("This should not happen!"); if (qRound(m_currentCompletePercentage) < qRound(newCurrentCompletePercentage))
} qDebug("Something is wrong with the calculation of the progress.");
m_currentCompletePercentage = newCurrentCompletePercentage; m_currentCompletePercentage = newCurrentCompletePercentage;
if (fraction == 1) { if (fraction == 1) {
@ -170,12 +188,13 @@ void ProgressCoordinator::partProgressChanged(double fraction)
newCurrentCompletePercentage = 100; newCurrentCompletePercentage = 100;
} }
if (qRound(m_currentCompletePercentage) > qRound(newCurrentCompletePercentage)) { // In normal mode, the progress has to go forward, new has to be larger than current
qWarning("This should not happen!"); if (qRound(m_currentCompletePercentage) > qRound(newCurrentCompletePercentage))
} qDebug("Something is wrong with the calculation of the progress.");
m_currentCompletePercentage = newCurrentCompletePercentage; m_currentCompletePercentage = newCurrentCompletePercentage;
if (fraction == 1 || fraction == 0) { if (fraction == 1) {
m_currentBasePercentage = m_currentBasePercentage + pendingCalculatedPartPercentage; m_currentBasePercentage = m_currentBasePercentage + pendingCalculatedPartPercentage;
m_senderPendingCalculatedPercentageHash.insert(sender(), 0); m_senderPendingCalculatedPercentageHash.insert(sender(), 0);
} else { } else {

View File

@ -8,5 +8,5 @@ host-bin/qdoc
*.la *.la
*.prl *.prl
*.pc *.pc
*.pri
*.cmake

View File

@ -0,0 +1,12 @@
bin/qmake
bin/lrelease
bin/qdoc
host-bin/qmake
host-bin/lrelease
host-bin/qdoc
%%
*.la
*.prl
*.pc

View File

@ -0,0 +1,12 @@
bin/qmake
bin/lrelease
bin/qdoc
host-bin/qmake
host-bin/lrelease
host-bin/qdoc
%%
*.la
*.prl
*.pc
*.pri
*.cmake

View File

@ -8,4 +8,6 @@ host-bin/qdoc.exe
*.la *.la
*.prl *.prl
*.pc *.pc
*.pri
*.cmake

View File

@ -0,0 +1,13 @@
bin/qmake.exe
bin/lrelease.exe
bin/qdoc.exe
host-bin/qmake.exe
host-bin/lrelease.exe
host-bin/qdoc.exe
%%
*.la
*.prl
*.pc
*.pri
*.cmake

View File

@ -8,6 +8,8 @@
<file>files-to-patch-macx-qt5</file> <file>files-to-patch-macx-qt5</file>
<file>files-to-patch-linux-emb-arm</file> <file>files-to-patch-linux-emb-arm</file>
<file>files-to-patch-windows-emb-arm</file> <file>files-to-patch-windows-emb-arm</file>
<file>files-to-patch-macx-emb-arm</file> <file>files-to-patch-windows-emb-arm-qt5</file>
<file>files-to-patch-macx-emb-arm-qt5</file>
<file>files-to-patch-linux-emb-arm-qt5</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -65,29 +65,24 @@ static QString errnoToQString(int error)
#endif #endif
} }
static bool removeDirectory(const QString &path, QString *errorString, bool force = true) static bool removeDirectory(const QString &path, QString *errorString, bool force)
{ {
Q_ASSERT(errorString); Q_ASSERT(errorString);
const QFileInfoList entries = QDir(path).entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden);
for (QFileInfoList::const_iterator it = entries.constBegin(); it != entries.constEnd(); ++it) { QDir dir = path;
if (it->isDir() && !it->isSymLink()) { const QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden);
removeDirectory(it->filePath(), errorString, force); foreach (const QFileInfo &entry, entries) {
} else if (force) { if (entry.isDir() && (!entry.isSymLink()))
QFile f(it->filePath()); removeDirectory(entry.filePath(), errorString, force);
if (!f.remove()) else if (force && (!QFile(entry.filePath()).remove()))
return false; return false;
}
} }
// even remove some hidden, OS-created files in there // even remove some hidden, OS-created files in there
#if defined Q_OS_MAC QInstaller::removeSystemGeneratedFiles(path);
QFile::remove(path + QLatin1String("/.DS_Store"));
#elif defined Q_OS_WIN
QFile::remove(path + QLatin1String("/Thumbs.db"));
#endif
errno = 0; errno = 0;
const bool success = QDir().rmdir(path); const bool success = dir.rmdir(path);
if (errno) if (errno)
*errorString = errnoToQString(errno); *errorString = errnoToQString(errno);
return success; return success;
@ -170,7 +165,7 @@ bool CopyOperation::performOperation()
QFile sourceFile(source); QFile sourceFile(source);
if (!sourceFile.exists()) { if (!sourceFile.exists()) {
setError(UserDefinedError); setError(UserDefinedError);
setErrorString(tr("Could not copy a none existing file: %1").arg(source)); setErrorString(tr("Could not copy a non-existent file: %1").arg(source));
return false; return false;
} }
// If destination file exists, we cannot use QFile::copy() because it does not overwrite an existing // If destination file exists, we cannot use QFile::copy() because it does not overwrite an existing

View File

@ -61,6 +61,7 @@
#include <kdrunoncechecker.h> #include <kdrunoncechecker.h>
#include <kdupdaterfiledownloaderfactory.h> #include <kdupdaterfiledownloaderfactory.h>
#include <QDirIterator>
#include <QtCore/QTranslator> #include <QtCore/QTranslator>
#include <QMessageBox> #include <QMessageBox>
@ -254,11 +255,10 @@ int main(int argc, char *argv[])
qDebug() << "Resource tree before loading the in-binary resource:"; qDebug() << "Resource tree before loading the in-binary resource:";
qDebug() << "Language: " << QLocale().uiLanguages().value(0, QLatin1String("No UI language set")); qDebug() << "Language: " << QLocale().uiLanguages().value(0, QLatin1String("No UI language set"));
QDir dir(QLatin1String(":/")); QDirIterator it(QLatin1String(":/"), QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden,
foreach (const QString &i, dir.entryList()) { QDirIterator::Subdirectories);
const QByteArray ba = i.toUtf8(); while (it.hasNext())
qDebug().nospace() << " :/" << ba.constData(); qDebug() << QString::fromLatin1(" %1").arg(it.next());
}
} }
// register custom operations before reading the binary content cause they may used in // register custom operations before reading the binary content cause they may used in
@ -296,59 +296,6 @@ int main(int argc, char *argv[])
// instantiate the installer we are actually going to use // instantiate the installer we are actually going to use
QInstaller::PackageManagerCore core(content.magicMarker(), content.performedOperations()); QInstaller::PackageManagerCore core(content.magicMarker(), content.performedOperations());
if (QInstaller::isVerbose()) {
qDebug() << "Resource tree after loading the in-binary resource:";
QDir dir = QDir(QLatin1String(":/"));
foreach (const QString &i, dir.entryList())
qDebug() << QString::fromLatin1(" :/%1").arg(i);
dir = QDir(QLatin1String(":/metadata/"));
foreach (const QString &i, dir.entryList())
qDebug() << QString::fromLatin1(" :/metadata/%1").arg(i);
dir = QDir(QLatin1String(":/translations/"));
foreach (const QString &i, dir.entryList())
qDebug() << QString::fromLatin1(" :/translations/%1").arg(i);
}
const QString directory = QLatin1String(":/translations");
const QStringList translations = core.settings().translations();
// 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;
}
}
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());
}
}
QString controlScript; QString controlScript;
QHash<QString, QString> params; QHash<QString, QString> params;
for (int i = 1; i < args.size(); ++i) { for (int i = 1; i < args.size(); ++i) {
@ -413,6 +360,56 @@ int main(int argc, char *argv[])
} }
} }
// 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 after loading the in-binary resource:";
QDirIterator it(QLatin1String(":/"), QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden,
QDirIterator::Subdirectories);
while (it.hasNext())
qDebug() << QString::fromLatin1(" %1").arg(it.next());
}
const QString directory = QLatin1String(":/translations");
const QStringList translations = core.settings().translations();
// 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;
}
}
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());
}
}
// Create the wizard gui // Create the wizard gui
TabController controller(0); TabController controller(0);
controller.setManager(&core); controller.setManager(&core);

View File

@ -63,6 +63,7 @@
#include <iostream> #include <iostream>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
# include <windows.h>
# include <wincon.h> # include <wincon.h>
# ifndef ENABLE_INSERT_MODE # ifndef ENABLE_INSERT_MODE
@ -135,6 +136,12 @@ public:
m_oldCerr = std::cerr.rdbuf(); m_oldCerr = std::cerr.rdbuf();
m_newCerr.open("CONOUT$"); m_newCerr.open("CONOUT$");
std::cerr.rdbuf(m_newCerr.rdbuf()); std::cerr.rdbuf(m_newCerr.rdbuf());
# ifndef Q_CC_MINGW
HMENU systemMenu = GetSystemMenu(GetConsoleWindow(), FALSE);
if (systemMenu != NULL)
RemoveMenu(systemMenu, SC_CLOSE, MF_BYCOMMAND);
DrawMenuBar(GetConsoleWindow());
# endif
#endif #endif
} }
~MyApplicationConsole() ~MyApplicationConsole()

View File

@ -75,16 +75,19 @@ IntroductionPageImpl::IntroductionPageImpl(QInstaller::PackageManagerCore *core)
QVBoxLayout *layout = new QVBoxLayout(widget); QVBoxLayout *layout = new QVBoxLayout(widget);
m_packageManager = new QRadioButton(tr("Package manager"), this); m_packageManager = new QRadioButton(tr("Package manager"), this);
m_packageManager->setObjectName(QLatin1String("PackageManagerRadioButton"));
layout->addWidget(m_packageManager); layout->addWidget(m_packageManager);
m_packageManager->setChecked(core->isPackageManager()); m_packageManager->setChecked(core->isPackageManager());
connect(m_packageManager, SIGNAL(toggled(bool)), this, SLOT(setPackageManager(bool))); connect(m_packageManager, SIGNAL(toggled(bool)), this, SLOT(setPackageManager(bool)));
m_updateComponents = new QRadioButton(tr("Update components"), this); m_updateComponents = new QRadioButton(tr("Update components"), this);
m_updateComponents->setObjectName(QLatin1String("UpdaterRadioButton"));
layout->addWidget(m_updateComponents); layout->addWidget(m_updateComponents);
m_updateComponents->setChecked(core->isUpdater()); m_updateComponents->setChecked(core->isUpdater());
connect(m_updateComponents, SIGNAL(toggled(bool)), this, SLOT(setUpdater(bool))); connect(m_updateComponents, SIGNAL(toggled(bool)), this, SLOT(setUpdater(bool)));
m_removeAllComponents = new QRadioButton(tr("Remove all components"), this); m_removeAllComponents = new QRadioButton(tr("Remove all components"), this);
m_removeAllComponents->setObjectName(QLatin1String("UninstallerRadioButton"));
layout->addWidget(m_removeAllComponents); layout->addWidget(m_removeAllComponents);
m_removeAllComponents->setChecked(core->isUninstaller()); m_removeAllComponents->setChecked(core->isUninstaller());
connect(m_removeAllComponents, SIGNAL(toggled(bool)), this, SLOT(setUninstaller(bool))); connect(m_removeAllComponents, SIGNAL(toggled(bool)), this, SLOT(setUninstaller(bool)));

View File

@ -150,7 +150,6 @@ int TabController::init()
} }
d->m_gui->restart(); d->m_gui->restart();
d->m_gui->setWindowModality(Qt::WindowModal);
d->m_gui->show(); d->m_gui->show();
onCurrentIdChanged(d->m_gui->currentId()); onCurrentIdChanged(d->m_gui->currentId());

View File

@ -99,7 +99,7 @@
<translation>: %12</translation> <translation>: %12</translation>
</message> </message>
<message> <message>
<source>Could not copy a none existing file: %1</source> <source>Could not copy a non-existent file: %1</source>
<translation>: %1</translation> <translation>: %1</translation>
</message> </message>
<message> <message>

View File

@ -0,0 +1,5 @@
include(../../qttest.pri)
QT -= gui
SOURCES += tst_binaryformat.cpp

View File

@ -0,0 +1,115 @@
/**************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
**************************************************************************/
#include <binaryformat.h>
#include <errors.h>
#include <fileutils.h>
#include <QTest>
#include <QTemporaryFile>
static const qint64 scTinySize = 72704LL;
static const qint64 scSmallSize = 524288LL;
static const qint64 scLargeSize = 2097152LL;
class tst_BinaryFormat : public QObject
{
Q_OBJECT
private slots:
void findMagicCookieSmallFile()
{
QTemporaryFile file;
file.open();
try {
QInstaller::blockingWrite(&file, QByteArray(scSmallSize, '1'));
QInstaller::appendInt64(&file, QInstaller::MagicCookie);
QCOMPARE(QInstaller::findMagicCookie(&file, QInstaller::MagicCookie), scSmallSize);
} catch (const QInstaller::Error &error) {
QFAIL(qPrintable(error.message()));
} catch (...) {
QFAIL("Unexpected error.");
}
}
void findMagicCookieLargeFile()
{
QTemporaryFile file;
file.open();
try {
QInstaller::blockingWrite(&file, QByteArray(scLargeSize, '1'));
QInstaller::appendInt64(&file, QInstaller::MagicCookie);
QInstaller::blockingWrite(&file, QByteArray(scTinySize, '2'));
QCOMPARE(QInstaller::findMagicCookie(&file, QInstaller::MagicCookie), scLargeSize);
} catch (const QInstaller::Error &error) {
QFAIL(qPrintable(error.message()));
} catch (...) {
QFAIL("Unexpected error.");
}
}
void testFindMagicCookieWithError()
{
QTest::ignoreMessage(QtDebugMsg, "create Error-Exception: \"No marker found, stopped after 71.00 KiB.\" ");
QTemporaryFile file;
file.open();
try {
QInstaller::blockingWrite(&file, QByteArray(scTinySize, '1'));
// throws
QInstaller::findMagicCookie(&file, QInstaller::MagicCookie);
} catch (const QInstaller::Error &error) {
QCOMPARE(qPrintable(error.message()), "No marker found, stopped after 71.00 KiB.");
} catch (...) {
QFAIL("Unexpected error.");
}
}
};
QTEST_MAIN(tst_BinaryFormat)
#include "tst_binaryformat.moc"

View File

@ -12,5 +12,6 @@ SUBDIRS += \
consumeoutputoperationtest \ consumeoutputoperationtest \
mkdiroperationtest \ mkdiroperationtest \
copyoperationtest \ copyoperationtest \
solver solver \
binaryformat

View File

@ -26,9 +26,9 @@ public:
virtual void init() {} virtual void init() {}
void callProtectedDelayedControlScriptExecution(int id) void callProtectedDelayedExecuteControlScript(int id)
{ {
delayedControlScriptExecution(id); executeControlScript(id);
} }
}; };
@ -218,18 +218,16 @@ private slots:
testGui.loadControlScript(":///data/auto-install.qs"); testGui.loadControlScript(":///data/auto-install.qs");
QCOMPARE(m_core.value("GuiTestValue"), QString("hello")); QCOMPARE(m_core.value("GuiTestValue"), QString("hello"));
testGui.show();
// show event calls automatically the first callback which does not exist // show event calls automatically the first callback which does not exist
setExpectedScriptOutput("Control script callback \"IntroductionPageCallback\" does not exist. "); setExpectedScriptOutput("Control script callback \"IntroductionPageCallback\" does not exist. ");
// give some time to the event triggering mechanism testGui.show();
qApp->processEvents();
// inside the auto-install script we are clicking the next button, with a not existing button // inside the auto-install script we are clicking the next button, with a not existing button
QTest::ignoreMessage(QtWarningMsg, "Button with type: \"unknown button\" not found! "); QTest::ignoreMessage(QtWarningMsg, "Button with type: \"unknown button\" not found! ");
testGui.callProtectedDelayedControlScriptExecution(PackageManagerCore::ComponentSelection); testGui.callProtectedDelayedExecuteControlScript(PackageManagerCore::ComponentSelection);
setExpectedScriptOutput("FinishedPageCallback - OK"); setExpectedScriptOutput("FinishedPageCallback - OK");
testGui.callProtectedDelayedControlScriptExecution(PackageManagerCore::InstallationFinished); testGui.callProtectedDelayedExecuteControlScript(PackageManagerCore::InstallationFinished);
} catch (const Error &error) { } catch (const Error &error) {
QFAIL(qPrintable(error.message())); QFAIL(qPrintable(error.message()));
} }

View File

@ -164,6 +164,7 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
const QUrl url(a.arguments().value(1)); const QUrl url(a.arguments().value(1));
KDUpdater::FileDownloaderFactory::setFollowRedirects(true);
qDebug() << url.toString(); qDebug() << url.toString();
KDUpdater::FileDownloader *loader = KDUpdater::FileDownloaderFactory::instance().create(url.scheme(), 0); KDUpdater::FileDownloader *loader = KDUpdater::FileDownloaderFactory::instance().create(url.scheme(), 0);
if (loader) { if (loader) {

View File

@ -400,7 +400,7 @@ private:
const QString oldPath; const QString oldPath;
}; };
static QString createBinaryResourceFile(const QString &directory) static QString createBinaryResourceFile(const QString &directory, const QString &binaryName)
{ {
QTemporaryFile projectFile(directory + QLatin1String("/rccprojectXXXXXX.qrc")); QTemporaryFile projectFile(directory + QLatin1String("/rccprojectXXXXXX.qrc"));
if (!projectFile.open()) if (!projectFile.open())
@ -408,16 +408,19 @@ static QString createBinaryResourceFile(const QString &directory)
projectFile.close(); projectFile.close();
const WorkingDirectoryChange wd(directory); const WorkingDirectoryChange wd(directory);
const QString binaryName = generateTemporaryFileName();
const QString projectFileName = QFileInfo(projectFile.fileName()).absoluteFilePath(); const QString projectFileName = QFileInfo(projectFile.fileName()).absoluteFilePath();
// 1. create the .qrc file // 1. create the .qrc file
runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-project") if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-project") << QLatin1String("-o")
<< QLatin1String("-o") << projectFileName); << projectFileName) != EXIT_SUCCESS) {
throw Error(QString::fromLatin1("Could not create rcc project file."));
}
// 2. create the binary resource file from the .qrc file // 2. create the binary resource file from the .qrc file
runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-binary") if (runRcc(QStringList() << QLatin1String("rcc") << QLatin1String("-binary") << QLatin1String("-o")
<< QLatin1String("-o") << binaryName << projectFileName); << binaryName << projectFileName) != EXIT_SUCCESS) {
throw Error(QString::fromLatin1("Could not compile rcc project file."));
}
return binaryName; return binaryName;
} }
@ -467,7 +470,12 @@ static void printUsage()
std::cout << " -r|--resources r1,.,rn include the given resource files into the binary" << std::endl; std::cout << " -r|--resources r1,.,rn include the given resource files into the binary" << std::endl;
std::cout << " -v|--verbose Verbose output" << std::endl; std::cout << " -v|--verbose Verbose output" << std::endl;
std::cout << std::endl << std::endl; std::cout << " -rcc|--compile-resource Compiles the default resource and outputs the result into"
<< std::endl;
std::cout << " 'update.rcc' in the current path." << std::endl;
std::cout << std::endl;
std::cout << "Packages are to be found in the current working directory and get listed as "
"their names" << std::endl << std::endl;
std::cout << "Example (offline installer):" << std::endl; std::cout << "Example (offline installer):" << std::endl;
char sep = QDir::separator().toLatin1(); char sep = QDir::separator().toLatin1();
std::cout << " " << appName << " --offline-only -c installer-config" << sep << "config.xml -p " std::cout << " " << appName << " --offline-only -c installer-config" << sep << "config.xml -p "
@ -481,6 +489,9 @@ static void printUsage()
std::cout << std::endl; std::cout << std::endl;
std::cout << "Creates an installer for the SDK without qt and qt creator." << std::endl; std::cout << "Creates an installer for the SDK without qt and qt creator." << std::endl;
std::cout << std::endl; std::cout << std::endl;
std::cout << "Example update.rcc:" << std::endl;
std::cout << " " << appName << " -c installer-config" << sep << "config.xml -p packages-directory "
"-rcc" << std::endl;
} }
void copyConfigData(const QString &configFile, const QString &targetDir) void copyConfigData(const QString &configFile, const QString &targetDir)
@ -576,6 +587,7 @@ int main(int argc, char **argv)
QStringList resources; QStringList resources;
QStringList filteredPackages; QStringList filteredPackages;
QInstallerTools::FilterType ftype = QInstallerTools::Exclude; QInstallerTools::FilterType ftype = QInstallerTools::Exclude;
bool compileResource = false;
const QStringList args = app.arguments().mid(1); const QStringList args = app.arguments().mid(1);
for (QStringList::const_iterator it = args.begin(); it != args.end(); ++it) { for (QStringList::const_iterator it = args.begin(); it != args.end(); ++it) {
@ -661,6 +673,8 @@ int main(int argc, char **argv)
} else if (*it == QLatin1String("--ignore-translations") } else if (*it == QLatin1String("--ignore-translations")
|| *it == QLatin1String("--ignore-invalid-packages")) { || *it == QLatin1String("--ignore-invalid-packages")) {
continue; continue;
} else if (*it == QLatin1String("-rcc") || *it == QLatin1String("--compile-resource")) {
compileResource = true;
} else { } else {
if (it->startsWith(QLatin1String("-"))) { if (it->startsWith(QLatin1String("-"))) {
return printErrorAndUsageAndExit(QString::fromLatin1("Error: Unknown option \"%1\" used. Maybe you " return printErrorAndUsageAndExit(QString::fromLatin1("Error: Unknown option \"%1\" used. Maybe you "
@ -689,7 +703,7 @@ int main(int argc, char **argv)
ftype = QInstallerTools::Include; ftype = QInstallerTools::Include;
} }
if (target.isEmpty()) if (target.isEmpty() && !compileResource)
return printErrorAndUsageAndExit(QString::fromLatin1("Error: Target parameter missing.")); return printErrorAndUsageAndExit(QString::fromLatin1("Error: Target parameter missing."));
if (configFile.isEmpty()) if (configFile.isEmpty())
@ -723,11 +737,11 @@ int main(int argc, char **argv)
if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg"))) if (!target.endsWith(QLatin1String(".app")) && !target.endsWith(QLatin1String(".dmg")))
target += QLatin1String(".app"); target += QLatin1String(".app");
#endif #endif
{ if (!compileResource) {
Input input; Input input;
input.outputPath = target; input.outputPath = target;
input.installerExePath = templateBinary; input.installerExePath = templateBinary;
input.binaryResourcePath = createBinaryResourceFile(tmpMetaDir); input.binaryResourcePath = createBinaryResourceFile(tmpMetaDir, generateTemporaryFileName());
input.binaryResources = createBinaryResourceFiles(resources); input.binaryResources = createBinaryResourceFiles(resources);
QInstallerTools::copyComponentData(packagesDirectories, tmpMetaDir, &packages); QInstallerTools::copyComponentData(packagesDirectories, tmpMetaDir, &packages);
@ -755,6 +769,9 @@ int main(int argc, char **argv)
QFile::remove(input.binaryResourcePath); QFile::remove(input.binaryResourcePath);
foreach (const QString &resource, input.binaryResources) foreach (const QString &resource, input.binaryResources)
QFile::remove(resource); QFile::remove(resource);
} else {
createBinaryResourceFile(tmpMetaDir, QDir::currentPath() + QLatin1String("/update.rcc"));
exitCode = EXIT_SUCCESS;
} }
} catch (const Error &e) { } catch (const Error &e) {
std::cerr << "Caught exception: " << e.message() << std::endl; std::cerr << "Caught exception: " << e.message() << std::endl;