diff options
Diffstat (limited to 'src/libs/installer')
-rw-r--r-- | src/libs/installer/consumeoutputoperation.cpp | 158 | ||||
-rw-r--r-- | src/libs/installer/consumeoutputoperation.h | 65 | ||||
-rw-r--r-- | src/libs/installer/init.cpp | 2 | ||||
-rw-r--r-- | src/libs/installer/installer.pro | 2 | ||||
-rw-r--r-- | src/libs/installer/qtpatch.cpp | 57 | ||||
-rw-r--r-- | src/libs/installer/qtpatch.h | 1 | ||||
-rw-r--r-- | src/libs/installer/qtpatchoperation.cpp | 68 | ||||
-rw-r--r-- | src/libs/installer/qtpatchoperation.h | 2 | ||||
-rw-r--r-- | src/libs/installer/utils.cpp | 34 | ||||
-rw-r--r-- | src/libs/installer/utils.h | 1 |
10 files changed, 328 insertions, 62 deletions
diff --git a/src/libs/installer/consumeoutputoperation.cpp b/src/libs/installer/consumeoutputoperation.cpp new file mode 100644 index 000000000..2d3bc1ec0 --- /dev/null +++ b/src/libs/installer/consumeoutputoperation.cpp @@ -0,0 +1,158 @@ +/************************************************************************** +** +** 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 "consumeoutputoperation.h" +#include "packagemanagercore.h" +#include "utils.h" + +#include <QFile> +#include <QDir> +#include <QProcess> +#include <QDebug> + +using namespace QInstaller; + +ConsumeOutputOperation::ConsumeOutputOperation() +{ + setName(QLatin1String("ConsumeOutput")); +} + +void ConsumeOutputOperation::backup() +{ +} + +bool ConsumeOutputOperation::performOperation() +{ + // Arguments: + // 1. key where the output will be saved + // 2. executable path + // 3. argument for the executable + // 4. more arguments possible ... + if (arguments().count() < 3) { + setError(InvalidArguments); + setErrorString(tr("Invalid arguments in %0: %1 arguments given, %2 expected%3.").arg(name()).arg( + arguments().count()).arg(tr("at least 2"), QLatin1String("(<to be saved installer key name>, " + "<executable>, [argument1], [argument2], ...)"))); + return false; + } + + PackageManagerCore *const core = value(QLatin1String("installer")).value<PackageManagerCore*>(); + if (!core) { + setError(UserDefinedError); + setErrorString(tr("Needed installer object in %1 operation is empty.").arg(name())); + return false; + } + + const QString installerKeyName = arguments().at(0); + if (installerKeyName.isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("Can not save the output of %1 to an empty installer key value.").arg( + arguments().at(1))); + return false; + } + + QString executablePath = arguments().at(1); +#ifdef Q_OS_WIN + if (!QFile::exists(executablePath)) + executablePath = executablePath + QLatin1String(".exe"); +#endif + + const QFileInfo executable(executablePath); + if (!executable.exists() || !executable.isExecutable()) { + setError(UserDefinedError); + setErrorString(tr("File '%1' does not exist or is not an executable binary.").arg( + QDir::toNativeSeparators(executable.absoluteFilePath()))); + return false; + } + + QByteArray executableOutput; + QProcess process; + + + const QStringList processArguments = arguments().mid(2); + // in some cases it is not runable, because another process is blocking it(filewatcher ...) + int waitCount = 0; + while (executableOutput.isEmpty() && waitCount < 60) { + + process.start(executable.absoluteFilePath(), processArguments, QIODevice::ReadOnly); + if (process.waitForFinished(2000)) { + if (process.exitStatus() == QProcess::CrashExit) { + setError(UserDefinedError); + setErrorString(tr("Running '%1' resulted in a crash.").arg( + QDir::toNativeSeparators(executable.absoluteFilePath()))); + return false; + } + executableOutput.append(process.readAllStandardOutput()); + } + if (executableOutput.isEmpty()) { + ++waitCount; + static const int waitTimeInMilliSeconds = 500; + uiDetachedWait(waitTimeInMilliSeconds); + } + if (process.state() > QProcess::NotRunning ) { + qWarning() << executable.absoluteFilePath() << "process is still running, need to kill it."; + process.kill(); + } + + } + if (executableOutput.isEmpty()) { + qWarning() << QString::fromLatin1("Can't get any query output from executable: '%1'").arg( + executable.absoluteFilePath()); + } + core->setValue(installerKeyName, QString::fromLatin1(executableOutput)); + return true; +} + +bool ConsumeOutputOperation::undoOperation() +{ + return true; +} + +bool ConsumeOutputOperation::testOperation() +{ + return true; +} + +Operation *ConsumeOutputOperation::clone() const +{ + return new ConsumeOutputOperation(); +} + diff --git a/src/libs/installer/consumeoutputoperation.h b/src/libs/installer/consumeoutputoperation.h new file mode 100644 index 000000000..f776cf35a --- /dev/null +++ b/src/libs/installer/consumeoutputoperation.h @@ -0,0 +1,65 @@ +/************************************************************************** +** +** 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$ +** +**************************************************************************/ + +#ifndef CONSUMEOUTPUTOPERATION_H +#define CONSUMEOUTPUTOPERATION_H + +#include "qinstallerglobal.h" + +namespace QInstaller { + +class INSTALLER_EXPORT ConsumeOutputOperation : public Operation +{ +public: + ConsumeOutputOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + Operation *clone() const; + +private: +}; + +} // namespace QInstaller + +#endif // CONSUMEOUTPUTOPERATION_H diff --git a/src/libs/installer/init.cpp b/src/libs/installer/init.cpp index 0fcc3c6a7..a8a7f54d8 100644 --- a/src/libs/installer/init.cpp +++ b/src/libs/installer/init.cpp @@ -62,6 +62,7 @@ // QtSDK specific #include "qtpatchoperation.h" +#include "consumeoutputoperation.h" #include "setdemospathonqtoperation.h" #include "setexamplespathonqtoperation.h" #include "setpluginpathonqtcoreoperation.h" @@ -243,6 +244,7 @@ void QInstaller::init() factory.registerUpdateOperation<MinimumProgressOperation>(QLatin1String("MinimumProgress")); factory.registerUpdateOperation<LicenseOperation>(QLatin1String("License")); factory.registerUpdateOperation<ApplyProductKeyOperation>(QLatin1String("ApplyProductKey")); + factory.registerUpdateOperation<ConsumeOutputOperation>(QLatin1String("ConsumeOutput")); // QtSDK specific factory.registerUpdateOperation<RegisterQtInCreatorQNXOperation>(QLatin1String("RegisterQtInCreatorQNX")); diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro index ec884e5a3..ab28aa72b 100644 --- a/src/libs/installer/installer.pro +++ b/src/libs/installer/installer.pro @@ -55,6 +55,7 @@ HEADERS += packagemanagercore.h \ persistentsettings.h \ projectexplorer_export.h \ qtpatchoperation.h \ + consumeoutputoperation.h \ setpathonqtcoreoperation.h \ setdemospathonqtoperation.h \ setexamplespathonqtoperation.h \ @@ -128,6 +129,7 @@ HEADERS += packagemanagercore.h \ qtpatch.cpp \ persistentsettings.cpp \ qtpatchoperation.cpp \ + consumeoutputoperation.cpp \ setpathonqtcoreoperation.cpp \ setdemospathonqtoperation.cpp \ setexamplespathonqtoperation.cpp \ diff --git a/src/libs/installer/qtpatch.cpp b/src/libs/installer/qtpatch.cpp index 02795b34b..6581815c2 100644 --- a/src/libs/installer/qtpatch.cpp +++ b/src/libs/installer/qtpatch.cpp @@ -40,6 +40,7 @@ **************************************************************************/ #include "qtpatch.h" +#include "utils.h" #include <QString> #include <QStringList> @@ -52,35 +53,20 @@ #include <QCoreApplication> #include <QByteArrayMatcher> -#ifdef Q_OS_WIN -#include <windows.h> // for Sleep -#endif -#ifdef Q_OS_UNIX -#include <errno.h> -#include <signal.h> -#include <time.h> -#endif - -static void sleepCopiedFromQTest(int ms) +QHash<QString, QByteArray> QtPatch::readQmakeOutput(const QByteArray &data) { - if (ms < 0) - return; -#ifdef Q_OS_WIN - Sleep(uint(ms)); -#else - struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; - nanosleep(&ts, NULL); -#endif -} - -static void uiDetachedWait(int ms) -{ - QTime timer; - timer.start(); - do { - QCoreApplication::processEvents(QEventLoop::AllEvents, ms); - sleepCopiedFromQTest(10); - } while (timer.elapsed() < ms); + QHash<QString, QByteArray> qmakeValueHash; + QTextStream stream(data, QIODevice::ReadOnly); + while (!stream.atEnd()) { + const QString line = stream.readLine(); + const int index = line.indexOf(QLatin1Char(':')); + if (index != -1) { + QString value = line.mid(index+1); + if (value != QLatin1String("**Unknown**") ) + qmakeValueHash.insert(line.left(index), value.toUtf8()); + } + } + return qmakeValueHash; } QHash<QString, QByteArray> QtPatch::qmakeValues(const QString &qmakePath, QByteArray *qmakeOutput) @@ -113,21 +99,12 @@ QHash<QString, QByteArray> QtPatch::qmakeValues(const QString &qmakePath, QByteA } QByteArray output = process.readAllStandardOutput(); qmakeOutput->append(output); - QTextStream stream(&output); - while (!stream.atEnd()) { - const QString line = stream.readLine(); - const int index = line.indexOf(QLatin1Char(':')); - if (index != -1) { - QString value = line.mid(index+1); - if (value != QLatin1String("**Unknown**") ) - qmakeValueHash.insert(line.left(index), value.toUtf8()); - } - } + qmakeValueHash = readQmakeOutput(output); } if (qmakeValueHash.isEmpty()) { ++waitCount; static const int waitTimeInMilliSeconds = 500; - uiDetachedWait(waitTimeInMilliSeconds); + QInstaller::uiDetachedWait(waitTimeInMilliSeconds); } if (process.state() > QProcess::NotRunning ) { qDebug() << "qmake process is still running, need to kill it."; @@ -232,7 +209,7 @@ bool QtPatch::openFileForPatching(QFile *file) while (!file->open(QFile::ReadWrite) && waitCount < 60) { ++waitCount; static const int waitTimeInMilliSeconds = 500; - uiDetachedWait(waitTimeInMilliSeconds); + QInstaller::uiDetachedWait(waitTimeInMilliSeconds); } return file->openMode() == QFile::ReadWrite; } diff --git a/src/libs/installer/qtpatch.h b/src/libs/installer/qtpatch.h index 5868e6ce2..13c7df84a 100644 --- a/src/libs/installer/qtpatch.h +++ b/src/libs/installer/qtpatch.h @@ -50,6 +50,7 @@ namespace QtPatch { +QHash<QString, QByteArray> INSTALLER_EXPORT readQmakeOutput(const QByteArray &data); QHash<QString, QByteArray> INSTALLER_EXPORT qmakeValues(const QString &qmakePath, QByteArray *qmakeOutput); bool INSTALLER_EXPORT patchBinaryFile(const QString &fileName, diff --git a/src/libs/installer/qtpatchoperation.cpp b/src/libs/installer/qtpatchoperation.cpp index 018d4e24a..997b92b77 100644 --- a/src/libs/installer/qtpatchoperation.cpp +++ b/src/libs/installer/qtpatchoperation.cpp @@ -176,7 +176,24 @@ bool QtPatchOperation::performOperation() return false; } - QString type = arguments().at(0); + QStringList args = arguments(); + QString qmakeOutputInstallerKey; + QStringList filteredQmakeOutputInstallerKey = args.filter(QLatin1String("QmakeOutputInstallerKey="), + Qt::CaseInsensitive); + PackageManagerCore *const core = value(QLatin1String("installer")).value<PackageManagerCore*>(); + if (!filteredQmakeOutputInstallerKey.isEmpty()) { + if (!core) { + setError(UserDefinedError); + setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); + return false; + } + QString qmakeOutputInstallerKeyArgument = filteredQmakeOutputInstallerKey.at(0); + qmakeOutputInstallerKey = qmakeOutputInstallerKeyArgument; + qmakeOutputInstallerKey.replace(QLatin1String("QmakeOutputInstallerKey="), QString(), Qt::CaseInsensitive); + args.removeAll(qmakeOutputInstallerKeyArgument); + } + + QString type = args.at(0); bool isPlatformSupported = type.contains(QLatin1String("linux"), Qt::CaseInsensitive) || type.contains(QLatin1String("windows"), Qt::CaseInsensitive) || type.contains(QLatin1String("mac"), Qt::CaseInsensitive); @@ -187,31 +204,42 @@ bool QtPatchOperation::performOperation() return false; } - const QString newQtPathStr = QDir::toNativeSeparators(arguments().at(1)); - const QByteArray newQtPath = newQtPathStr.toUtf8(); + if (!filteredQmakeOutputInstallerKey.isEmpty() && core->value(qmakeOutputInstallerKey).isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("Could not find the needed QmakeOutputInstallerKey(%1) value on the installer " + "object. The ConsumeOutput operation on the valid qmake needs to be called first.").arg( + qmakeOutputInstallerKey)); + return false; + } + const QString newQtPathStr = QDir::toNativeSeparators(args.at(1)); + const QByteArray newQtPath = newQtPathStr.toUtf8(); QString qmakePath = QString::fromUtf8(newQtPath) + QLatin1String("/bin/qmake"); #ifdef Q_OS_WIN qmakePath = qmakePath + QLatin1String(".exe"); #endif - if (!QFile::exists(qmakePath)) { - setError(UserDefinedError); - setErrorString(tr("QMake from the current Qt version \n(%1)is not existing. Please file a bugreport " - "with this dialog at https://bugreports.qt-project.org.").arg(QDir::toNativeSeparators(qmakePath))); - return false; + QHash<QString, QByteArray> qmakeValueHash; + if (!core->value(qmakeOutputInstallerKey).isEmpty()) { + qmakeValueHash = QtPatch::readQmakeOutput(core->value(qmakeOutputInstallerKey).toLatin1()); + } else { + if (!QFile::exists(qmakePath)) { + setError(UserDefinedError); + setErrorString(tr("QMake from the current Qt version \n(%1)is not existing. Please file a bugreport " + "with this dialog at https://bugreports.qt-project.org.").arg(QDir::toNativeSeparators(qmakePath))); + return false; + } + QByteArray qmakeOutput; + qmakeValueHash = QtPatch::qmakeValues(qmakePath, &qmakeOutput); + if (qmakeValueHash.isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("The output of \n%1 -query\nis not parseable. Please file a bugreport with this " + "dialog https://bugreports.qt-project.org.\noutput: \"%2\"").arg(QDir::toNativeSeparators(qmakePath), + QString::fromUtf8(qmakeOutput))); + return false; + } } - QByteArray qmakeOutput; - QHash<QString, QByteArray> qmakeValueHash = QtPatch::qmakeValues(qmakePath, &qmakeOutput); - - if (qmakeValueHash.isEmpty()) { - setError(UserDefinedError); - setErrorString(tr("The output of \n%1 -query\nis not parseable. Please file a bugreport with this " - "dialog https://bugreports.qt-project.org.\noutput: \"%2\"").arg(QDir::toNativeSeparators(qmakePath), - QString::fromUtf8(qmakeOutput))); - return false; - } const QByteArray oldQtPath = qmakeValueHash.value(QLatin1String("QT_INSTALL_PREFIX")); bool oldQtPathFromQMakeIsEmpty = oldQtPath.isEmpty(); @@ -246,13 +274,11 @@ bool QtPatchOperation::performOperation() fileName = QString::fromLatin1(":/files-to-patch-windows"); else if (type == QLatin1String("linux")) fileName = QString::fromLatin1(":/files-to-patch-linux"); - else if (type == QLatin1String("linux-emb-arm")) - fileName = QString::fromLatin1(":/files-to-patch-linux-emb-arm"); else if (type == QLatin1String("mac")) fileName = QString::fromLatin1(":/files-to-patch-macx"); QFile patchFileListFile(fileName); - QString version = arguments().value(2).toLower(); + QString version = args.value(2).toLower(); if (!version.isEmpty()) patchFileListFile.setFileName(fileName + QLatin1Char('-') + version); diff --git a/src/libs/installer/qtpatchoperation.h b/src/libs/installer/qtpatchoperation.h index f1919f4c6..346466c43 100644 --- a/src/libs/installer/qtpatchoperation.h +++ b/src/libs/installer/qtpatchoperation.h @@ -46,7 +46,7 @@ namespace QInstaller { -class QtPatchOperation : public Operation +class INSTALLER_EXPORT QtPatchOperation : public Operation { public: QtPatchOperation(); diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp index 1112bcebb..2b5491f62 100644 --- a/src/libs/installer/utils.cpp +++ b/src/libs/installer/utils.cpp @@ -45,6 +45,7 @@ #include <QtCore/QDir> #include <QtCore/QProcessEnvironment> #include <QtCore/QVector> +#include <QCoreApplication> #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) # include "qt_windows.h" @@ -54,6 +55,39 @@ #include <iostream> #include <sstream> + +#ifdef Q_OS_WIN +#include <windows.h> // for Sleep +#endif +#ifdef Q_OS_UNIX +#include <errno.h> +#include <signal.h> +#include <time.h> +#endif + +namespace { +void sleepCopiedFromQTest(int ms) +{ + if (ms < 0) + return; +#ifdef Q_OS_WIN + Sleep(uint(ms)); +#else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, NULL); +#endif +} +} +void QInstaller::uiDetachedWait(int ms) +{ + QTime timer; + timer.start(); + do { + QCoreApplication::processEvents(QEventLoop::AllEvents, ms); + sleepCopiedFromQTest(10); + } while (timer.elapsed() < ms); +} + static bool verb = false; void QInstaller::setVerbose(bool v) diff --git a/src/libs/installer/utils.h b/src/libs/installer/utils.h index e6aca456d..229dfe95a 100644 --- a/src/libs/installer/utils.h +++ b/src/libs/installer/utils.h @@ -57,6 +57,7 @@ class QIODevice; QT_END_NAMESPACE namespace QInstaller { + void INSTALLER_EXPORT uiDetachedWait(int ms); QByteArray INSTALLER_EXPORT calculateHash(QIODevice *device, QCryptographicHash::Algorithm algo); QByteArray INSTALLER_EXPORT calculateHash(const QString &path, QCryptographicHash::Algorithm algo); |