diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2012-06-13 12:35:38 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@nokia.com> | 2012-06-13 12:51:22 +0200 |
commit | 11024621308100ff59a6a29807d7fce8f64b8bc4 (patch) | |
tree | 0d84ce6380a8183d03425bf9f38d48c2bc664c1d | |
parent | e1c179e2e6baf9dd62f2c22c167b0bb391ef5c95 (diff) | |
parent | f924ee557ececb0a6fd5adc06dc9b4d552eaee12 (diff) |
Merge remote-tracking branch 'origin/master' into qt5
Change-Id: I5ee4f3e628f929642b71afaf4d70a00d057834a3
46 files changed, 951 insertions, 367 deletions
@@ -1,4 +1,4 @@ -These are instructions to create the installer framework +These are instructions to create the Installer Framework == Build == To build an installer, it is advised to use a statically linked Qt. @@ -33,7 +33,7 @@ Recommended configure options for windows: configure.exe -platform win32-msvc20XX -release -static -no-webkit -no-phonon -no-dbus -no-opengl -no-qt3support -no-xmlpatterns -no-svg -no-multimedia -no-declarative -no-declarative-debug -nomake examples -nomake demos -qt-sql-sqlite -plugin-sql-sqlite -opensource Recommended configure options for Linux: -configure -nomake examples -nomake demos -qt-zlib -qt-gif -qt-libtiff -qt-libpng -qt-libmng -qt-libjpeg -opensource -developer-build -static -no-webkit -no-phonon -no-dbus -no-opengl -no-qt3support -no-xmlpatterns -no-svg -release +configure -nomake examples -nomake demos -qt-zlib -qt-libtiff -qt-libpng -qt-libmng -qt-libjpeg -opensource -developer-build -static -no-webkit -no-phonon -no-dbus -no-opengl -no-qt3support -no-xmlpatterns -no-svg -release == Create an Installer == diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc index f55aa2de5..00fa04c37 100644 --- a/doc/installerfw.qdoc +++ b/doc/installerfw.qdoc @@ -207,10 +207,7 @@ \o RemoteRepositories \o List of remote repositories. You can add several \c Repository sections that each specify the \c Url to access the repository. - Optionally, you can add a \c Required section to specify whether - the installer should go ahead even if it cannot access the - server. Acceptable values are \c true and \c false. For more - information, see \l{Configuring Repositories}. + For more information, see \l{Configuring Repositories}. \row \o UninstallerName \o Filename of the generated uninstaller. Defaults to @@ -757,9 +754,6 @@ \o URL, which points to a list of available components. - \o Required, which determines whether the repository must be available - during the installation. - \endlist The URL needs to point to the Updates.xml file that lists the available @@ -769,17 +763,22 @@ <RemoteRepositories> <Repository> <Url>http://www.yourcompany.com/packages</Url> + <Enabled>1</Enabled> + <Username>user</Username> + <Password>password</Password> </Repository> </RemoteRepositories> \endcode - The \a Required setting specifies whether the installer should go ahead even - if it cannot access the server. If you set \c Required to \c true, the - installer works only if it can access the repository. If the repository is + The installer works only if it can access the repository. If the repository is accessed after the installation, the maintenance tool rejects installation. - However, uninstallation is still possible. If you set it to \c false, the - installer continues to work, but excludes any configuration that should - be on the server. + However, uninstallation is still possible. + A repository can be enabled or disabled by default. + For repositories requiring authentication, the details can also be set here, + although entering a password here is usually not advisable as it is saved in plain + text. Authentication details not set here will be gotten at runtime using a dialog. + The user can work around these settings at runtime. + \section1 Creating Installer Binaries diff --git a/installerfw.pri b/installerfw.pri index 2d1915ec6..86618d6d3 100644 --- a/installerfw.pri +++ b/installerfw.pri @@ -46,6 +46,8 @@ win32:INCLUDEPATH += $$IFW_SOURCE_TREE/src/libs/7zip/win/CPP unix:INCLUDEPATH += $$IFW_SOURCE_TREE/src/libs/7zip/unix/CPP LIBS += -L$$IFW_LIB_PATH +# The order is important. The linker needs to parse archives in reversed dependency order. +equals(TEMPLATE, app):LIBS += -linstaller unix:!macx:LIBS += -lutil macx:LIBS += -framework Carbon -framework Security diff --git a/src/libs/installer/addqtcreatorarrayvalueoperation.cpp b/src/libs/installer/addqtcreatorarrayvalueoperation.cpp index 23ca7a21a..43520b7b3 100644 --- a/src/libs/installer/addqtcreatorarrayvalueoperation.cpp +++ b/src/libs/installer/addqtcreatorarrayvalueoperation.cpp @@ -32,7 +32,6 @@ #include "addqtcreatorarrayvalueoperation.h" -#include "constants.h" #include "qtcreator_constants.h" #include "packagemanagercore.h" @@ -66,17 +65,22 @@ bool AddQtCreatorArrayValueOperation::performOperation() return false; } - PackageManagerCore *const core = qVariantValue<PackageManagerCore*>(value(QLatin1String("installer"))); if (!core) { setError(UserDefinedError); setErrorString(tr("Needed installer object in %1 operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), - QSettings::IniFormat); + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile); + if (qtCreatorInstallerSettingsFileName.isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerSettingsFile)); + return false; + } + + QSettings settings(qtCreatorInstallerSettingsFileName, QSettings::IniFormat); const QString &group = groupName(args.at(0)); const QString &arrayName = args.at(1); @@ -125,10 +129,19 @@ bool AddQtCreatorArrayValueOperation::undoOperation() setErrorString(tr("Needed installer object in %1 operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), - QSettings::IniFormat); + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/QtCreator.ini").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/QtCreator.ini").arg(core->value( + QLatin1String("TargetDir")))); +#endif + + QSettings settings(qtCreatorInstallerSettingsFileName, QSettings::IniFormat); const QString &group = groupName(args.at(0)); const QString &arrayName = args.at(1); diff --git a/src/libs/installer/adminauthorization_x11.cpp b/src/libs/installer/adminauthorization_x11.cpp index 592f56ef7..14467fecd 100644 --- a/src/libs/installer/adminauthorization_x11.cpp +++ b/src/libs/installer/adminauthorization_x11.cpp @@ -33,6 +33,7 @@ #include "adminauthorization.h" #include <QtCore/QFile> +#include <QDebug> #include <QtGui/QApplication> #include <QtGui/QInputDialog> @@ -71,7 +72,9 @@ static QString getPassword(QWidget *) { if (QApplication::type() == QApplication::GuiClient) { bool ok = false; - const QString result = QInputDialog::getText(0, QObject::tr( "Authorization required" ), QObject::tr( "Enter your password to authorize for sudo:" ), QLineEdit::Password, QString(), &ok); + const QString result = QInputDialog::getText(0, QObject::tr("Authorization required"), + QObject::tr("Enter your password to authorize for sudo:"), + QLineEdit::Password, QString(), &ok); return ok ? result : QString(); } else { std::cout << QObject::tr("Authorization required").toStdString() << std::endl; @@ -85,13 +88,17 @@ static QString getPassword(QWidget *) static void printError(QWidget *parent, const QString &value) { if (QApplication::type() == QApplication::GuiClient) - QMessageBox::critical(parent, QObject::tr( "Error acquiring admin rights" ), value, QMessageBox::Ok, QMessageBox::Ok); + QMessageBox::critical(parent, QObject::tr( "Error acquiring admin rights" ), value, + QMessageBox::Ok, QMessageBox::Ok); else std::cout << value.toStdString() << std::endl; } bool AdminAuthorization::execute(QWidget *parent, const QString &program, const QStringList &arguments) { + const QString fallback = program + QLatin1String(" ") + arguments.join(QLatin1String(" ")); + qDebug() << "Fallback:" << fallback; + // as we cannot pipe the password to su in QProcess, we need to setup a pseudo-terminal for it int masterFD = -1; int slaveFD = -1; diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp index 75a41ea31..963dd55c6 100644 --- a/src/libs/installer/component.cpp +++ b/src/libs/installer/component.cpp @@ -245,14 +245,16 @@ QString Component::value(const QString &key, const QString &defaultValue) const */ void Component::setValue(const QString &key, const QString &value) { - if (d->m_vars.value(key) == value) + QString normalizedValue = d->m_core->replaceVariables(value); + + if (d->m_vars.value(key) == normalizedValue) return; if (key == scName) - d->m_componentName = value; + d->m_componentName = normalizedValue; - d->m_vars[key] = value; - emit valueChanged(key, value); + d->m_vars[key] = normalizedValue; + emit valueChanged(key, normalizedValue); } /*! diff --git a/src/libs/installer/createlinkoperation.cpp b/src/libs/installer/createlinkoperation.cpp new file mode 100644 index 000000000..48c2774d1 --- /dev/null +++ b/src/libs/installer/createlinkoperation.cpp @@ -0,0 +1,105 @@ +/************************************************************************** +** +** This file is part of Installer Framework +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ +#include "createlinkoperation.h" + +#include "link.h" + +#include <QFileInfo> + +using namespace QInstaller; + +/* +TRANSLATOR QInstaller::CreateLinkOperation +*/ + +CreateLinkOperation::CreateLinkOperation() +{ + setName(QLatin1String("CreateLink")); +} + +void CreateLinkOperation::backup() +{ +} + +bool CreateLinkOperation::performOperation() +{ + QStringList args = arguments(); + + if (args.count() != 2) { + setError(InvalidArguments); + setErrorString(QObject::tr("Invalid arguments: %1 arguments given, 2 expected").arg( + args.count())); + return false; + } + + const QString& linkPath = args.at(0); + const QString& targetPath = args.at(1); + Link link = Link::create(linkPath, targetPath); + + if (!link.exists()) { + setError(UserDefinedError); + setErrorString(QObject::tr("Could not create link from %1 to %2.").arg(linkPath, targetPath)); + return false; + } + + return true; +} + +bool CreateLinkOperation::undoOperation() +{ + QStringList args = arguments(); + + const QString& linkPath = args.at(0); + const QString& targetPath = args.at(1); + + Link link = Link(linkPath); + if (!link.exists()) { + return true; + } + if (!link.remove()) { + setError(UserDefinedError); + setErrorString(QObject::tr("Could not remove link from %1 to %2.").arg(linkPath, targetPath)); + return false; + } + + return !QFileInfo(linkPath).exists(); +} + +bool CreateLinkOperation::testOperation() +{ + return true; +} + +Operation *CreateLinkOperation::clone() const +{ + return new CreateLinkOperation(); +} diff --git a/src/libs/installer/createlinkoperation.h b/src/libs/installer/createlinkoperation.h new file mode 100644 index 000000000..9e111926f --- /dev/null +++ b/src/libs/installer/createlinkoperation.h @@ -0,0 +1,54 @@ +/************************************************************************** +** +** This file is part of Installer Framework +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef CREATELINKOPERATION_H +#define CREATELINKOPERATION_H + +#include "qinstallerglobal.h" + +namespace QInstaller { + +class INSTALLER_EXPORT CreateLinkOperation : public Operation +{ +public: + CreateLinkOperation(); + + void backup(); + bool performOperation(); + bool undoOperation(); + bool testOperation(); + Operation *clone() const; +}; + +} + +#endif diff --git a/src/libs/installer/fsengineclient.cpp b/src/libs/installer/fsengineclient.cpp index beed6d32d..3221b9f29 100644 --- a/src/libs/installer/fsengineclient.cpp +++ b/src/libs/installer/fsengineclient.cpp @@ -33,6 +33,7 @@ #include "fsengineclient.h" #include "adminauthorization.h" +#include "messageboxhandler.h" #include <QtCore/QCoreApplication> #include <QtCore/QMutex> @@ -778,6 +779,23 @@ void FSEngineClientHandler::Private::maybeStartServer() if (startServerAsAdmin) { AdminAuthorization auth; serverStarted = auth.authorize() && auth.execute(0, serverCommand, serverArguments); + + if (!serverStarted) { + // something went wrong with authorizing, either user pressed cancel or entered + // wrong password + const QString fallback = serverCommand + QLatin1String(" ") + serverArguments.join(QLatin1String(" ")); + + const QMessageBox::Button res = + QInstaller::MessageBoxHandler::critical(QInstaller::MessageBoxHandler::currentBestSuitParent(), + QObject::tr("Authorization Error"), QObject::tr("Couldn't get authorization."), + QObject::tr("Couldn't get authorization that is needed for continuing the installation.\n" + "Either abort the installation or use the fallback solution by running\n" + "%1\nas root and then clicking ok.").arg(fallback), + QMessageBox::Abort | QMessageBox::Ok, QMessageBox::Ok); + + if (res == QMessageBox::Ok) + serverStarted = true; + } } else { serverStarted = QProcess::startDetached(serverCommand, serverArguments); } diff --git a/src/libs/installer/getrepositorymetainfojob.cpp b/src/libs/installer/getrepositorymetainfojob.cpp index c86ab9309..22fd3c0fd 100644 --- a/src/libs/installer/getrepositorymetainfojob.cpp +++ b/src/libs/installer/getrepositorymetainfojob.cpp @@ -31,7 +31,6 @@ **************************************************************************/ #include "getrepositorymetainfojob.h" -#include "constants.h" #include "errors.h" #include "lib7z_facade.h" #include "messageboxhandler.h" diff --git a/src/libs/installer/init.cpp b/src/libs/installer/init.cpp index 35aa15151..463628c03 100644 --- a/src/libs/installer/init.cpp +++ b/src/libs/installer/init.cpp @@ -65,6 +65,7 @@ #include "registertoolchainoperation.h" #include "registerdefaultdebuggeroperation.h" #include "updatecreatorsettingsfrom21to22operation.h" +#include "createlinkoperation.h" #include "minimumprogressoperation.h" @@ -228,6 +229,7 @@ void QInstaller::init() factory.registerUpdateOperation<ReplaceOperation>(QLatin1String("Replace")); factory.registerUpdateOperation<LineReplaceOperation>(QLatin1String( "LineReplace" ) ); factory.registerUpdateOperation<UpdateCreatorSettingsFrom21To22Operation>(QLatin1String("UpdateCreatorSettingsFrom21To22")); + factory.registerUpdateOperation<CreateLinkOperation>(QLatin1String("CreateLink")); factory.registerUpdateOperation<MinimumProgressOperation>(QLatin1String("MinimumProgress")); factory.registerUpdateOperation<LicenseOperation>(QLatin1String("License")); diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro index 31ebbaa84..f21394ae2 100644 --- a/src/libs/installer/installer.pro +++ b/src/libs/installer/installer.pro @@ -88,7 +88,9 @@ HEADERS += packagemanagercore.h \ constants.h \ packagemanagerproxyfactory.h \ createlocalrepositoryoperation.h \ - lib7z_facade.h + lib7z_facade.h \ + link.h \ + createlinkoperation.h SOURCES += packagemanagercore.cpp \ packagemanagercore_p.cpp \ @@ -158,7 +160,9 @@ SOURCES += packagemanagercore.cpp \ settings.cpp \ packagemanagerproxyfactory.cpp \ createlocalrepositoryoperation.cpp \ - lib7z_facade.cpp + lib7z_facade.cpp \ + link.cpp \ + createlinkoperation.cpp RESOURCES += resources/patch_file_lists.qrc diff --git a/src/libs/installer/lib7z_facade.cpp b/src/libs/installer/lib7z_facade.cpp index 14bfd25a0..7b995d0aa 100644 --- a/src/libs/installer/lib7z_facade.cpp +++ b/src/libs/installer/lib7z_facade.cpp @@ -1011,9 +1011,9 @@ public: // TODO! return S_OK; } - void setSource(const QStringList &dir) + void setSourcePaths(const QStringList &paths) { - sourceDir = dir; + sourcePaths = paths; } void setTarget(QIODevice* archive) { @@ -1024,7 +1024,7 @@ private: UpdateCallback* const q; QIODevice* target; - QStringList sourceDir; + QStringList sourcePaths; }; class Lib7z::UpdateCallbackPrivate @@ -1059,9 +1059,9 @@ UpdateCallbackImpl* UpdateCallback::impl() return d->impl(); } -void UpdateCallback::setSource(const QStringList &dir) +void UpdateCallback::setSourcePaths(const QStringList &paths) { - d->impl()->setSource(dir); + d->impl()->setSourcePaths(paths); } void UpdateCallback::setTarget(QIODevice* target) @@ -1134,7 +1134,7 @@ void ExtractItemJob::setTarget(QIODevice* dev) d->target = dev; } -void Lib7z::createArchive(QIODevice* archive, const QStringList &sourceDirectories, UpdateCallback* callback) +void Lib7z::createArchive(QIODevice* archive, const QStringList &sourcePaths, UpdateCallback* callback) { assert(archive); @@ -1142,8 +1142,7 @@ void Lib7z::createArchive(QIODevice* archive, const QStringList &sourceDirectori if (!callback) callback = dummyCallback.get(); - try - { + try { std::auto_ptr< CCodecs > codecs(new CCodecs); throwIfNotOK(codecs->Load(), QObject::tr("Could not load codecs")); @@ -1157,11 +1156,13 @@ void Lib7z::createArchive(QIODevice* archive, const QStringList &sourceDirectori const QString tempFile = generateTempFileName(); NWildcard::CCensor censor; - foreach(QString dir, sourceDirectories) { - const UString sourceDirectoryPath = QString2UString(QDir::toNativeSeparators(dir)); - if (UString2QString(sourceDirectoryPath) != QDir::toNativeSeparators(dir)) - throw UString2QString(sourceDirectoryPath).toLatin1().data(); - censor.AddItem(true, sourceDirectoryPath, true); + foreach (const QString &path, sourcePaths) { + const UString sourcePath = QString2UString(QDir::toNativeSeparators(path)); + if (UString2QString(sourcePath) != QDir::toNativeSeparators(path)) + throw UString2QString(sourcePath).toLatin1().data(); + // Only pass recursive with true if path is a directory, otherwise we include the file and + // possible folders located on the same directory level as the file into the created archive. + censor.AddItem(true, sourcePath, QFileInfo(path).isDir()); } CUpdateOptions options; @@ -1177,7 +1178,7 @@ void Lib7z::createArchive(QIODevice* archive, const QStringList &sourceDirectori CUpdateErrorInfo errorInfo; callback->setTarget(archive); - callback->setSource(sourceDirectories); + callback->setSourcePaths(sourcePaths); const HRESULT res = UpdateArchive(codecs.get(), censor, options, errorInfo, 0, callback->impl()); if (res != S_OK || !QFile::exists(tempFile)) throw SevenZipException(QObject::tr("Could not create archive %1").arg(tempFile)); diff --git a/src/libs/installer/lib7z_facade.h b/src/libs/installer/lib7z_facade.h index 58774df11..afdc85cfc 100644 --- a/src/libs/installer/lib7z_facade.h +++ b/src/libs/installer/lib7z_facade.h @@ -96,7 +96,7 @@ namespace Lib7z { virtual ~UpdateCallback(); void setTarget( QIODevice* archive ); - void setSource( const QStringList& dir ); + void setSourcePaths( const QStringList& paths ); virtual UpdateCallbackImpl* impl(); @@ -130,7 +130,7 @@ namespace Lib7z { /* * @thows Lib7z::SevenZipException */ - void INSTALLER_EXPORT createArchive( QIODevice* archive, const QStringList& sourceDirectory, UpdateCallback* callback = 0 ); + void INSTALLER_EXPORT createArchive( QIODevice* archive, const QStringList& sourcePaths, UpdateCallback* callback = 0 ); /* * @throws Lib7z::SevenZipException diff --git a/src/libs/installer/link.cpp b/src/libs/installer/link.cpp new file mode 100644 index 000000000..b31520e54 --- /dev/null +++ b/src/libs/installer/link.cpp @@ -0,0 +1,295 @@ +/************************************************************************** +** +** This file is part of Installer Framework +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "link.h" + +#include <QFileInfo> +#include <QDir> +#include <QDebug> + +#ifdef Q_OS_LINUX +#include <unistd.h> +#endif + +#ifdef Q_OS_WIN +#include <windows.h> +#include <Strsafe.h> + +// REPARSE_DATA_BUFFER structure from msdn help: http://msdn.microsoft.com/en-us/library/ff552012.aspx +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +#define _REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(_REPARSE_DATA_BUFFER, GenericReparseBuffer) + + +class FileHandleWrapper +{ +public: + FileHandleWrapper(const QString &path) + : m_dirHandle(INVALID_HANDLE_VALUE) + { + QString normalizedPath = QString(path).replace(QLatin1Char('/'), QLatin1Char('\\')); + m_dirHandle = CreateFile(normalizedPath.utf16(), GENERIC_READ | GENERIC_WRITE, 0, 0, + OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0); + + if (m_dirHandle == INVALID_HANDLE_VALUE) { + qWarning() << QString::fromLatin1("Could not open: '%1'; error: %2\n").arg(path).arg(GetLastError()); + } + } + + ~FileHandleWrapper() { + if (m_dirHandle != INVALID_HANDLE_VALUE) + CloseHandle(m_dirHandle); + } + + HANDLE handle() { + return m_dirHandle; + } + +private: + HANDLE m_dirHandle; +}; + +QString readWindowsSymLink(const QString &path) +{ + QString result; + FileHandleWrapper dirHandle(path); + if (dirHandle.handle() != INVALID_HANDLE_VALUE) { + REPARSE_DATA_BUFFER* reparseStructData = (REPARSE_DATA_BUFFER*)calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + DWORD bytesReturned = 0; + if (::DeviceIoControl(dirHandle.handle(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseStructData, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, 0)) { + if (reparseStructData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + int length = reparseStructData->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = reparseStructData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + const wchar_t* PathBuffer = &reparseStructData->MountPointReparseBuffer.PathBuffer[offset]; + result = QString::fromWCharArray(PathBuffer, length); + } else if (reparseStructData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + int length = reparseStructData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = reparseStructData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + const wchar_t* PathBuffer = &reparseStructData->SymbolicLinkReparseBuffer.PathBuffer[offset]; + result = QString::fromWCharArray(PathBuffer, length); + } + // cut-off "//?/" and "/??/" + if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) + result = result.mid(4); + } + free(reparseStructData); + } + return result; +} + +Link createJunction(const QString &linkPath, const QString &targetPath) +{ + if (!QDir().mkpath(linkPath)) { + qWarning() << QString::fromLatin1("Could not create the mount directory: %1").arg( + linkPath); + return Link(linkPath); + } + FileHandleWrapper dirHandle(linkPath); + if (dirHandle.handle() == INVALID_HANDLE_VALUE) { + qWarning() << QString::fromLatin1("Could not open: '%1'; error: %2\n").arg(linkPath).arg( + GetLastError()); + return Link(linkPath); + } + + TCHAR szDestDir[1024] = L"\\??\\"; //you need this to create valid unicode junctions + + QString normalizedTargetPath = QString(targetPath).replace(QLatin1Char('/'), QLatin1Char('\\')); + //now we add the real absolute path + StringCchCat(szDestDir, 1024, normalizedTargetPath.utf16()); + + // Allocates a block of memory for an array of num elements(1) and initializes all its bits to zero. + _REPARSE_DATA_BUFFER* reparseStructData = (_REPARSE_DATA_BUFFER*)calloc(1, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + const size_t destMountPointBytes = lstrlen(szDestDir) * sizeof(WCHAR); + + reparseStructData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + + // Reserved(USHORT) + SubstituteNameOffset(USHORT) + SubstituteNameLength(USHORT) + // + PrintNameOffset(USHORT) + PrintNameLength(USHORT) + PathBuffer[1](WCHAR) + uint spaceAfterGeneralData = sizeof(USHORT) * 5 + sizeof(WCHAR); //should be 12 + reparseStructData->ReparseDataLength = destMountPointBytes + spaceAfterGeneralData; + reparseStructData->Reserved = 0; + reparseStructData->MountPointReparseBuffer.SubstituteNameOffset = 0; + reparseStructData->MountPointReparseBuffer.SubstituteNameLength = destMountPointBytes; + // + sizeof(WCHAR) means \0 termination at the end of the string + reparseStructData->MountPointReparseBuffer.PrintNameOffset = destMountPointBytes + sizeof(WCHAR); + reparseStructData->MountPointReparseBuffer.PrintNameLength = 0; + StringCchCopy(reparseStructData->MountPointReparseBuffer.PathBuffer, 1024, szDestDir); + + + DWORD bytesReturned; + if (!::DeviceIoControl(dirHandle.handle(), FSCTL_SET_REPARSE_POINT, reparseStructData, + reparseStructData->ReparseDataLength + _REPARSE_DATA_BUFFER_HEADER_SIZE, 0, 0, + &bytesReturned, 0)) { + qWarning() << QString::fromLatin1("Could not set the reparse point: for '%1' to %2; error: %3" + ).arg(linkPath, targetPath).arg(GetLastError()); + } + return Link(linkPath); +} + +bool removeJunction(const QString &path) +{ + // Allocates a block of memory for an array of num elements(1) and initializes all its bits to zero. + _REPARSE_DATA_BUFFER* reparseStructData = (_REPARSE_DATA_BUFFER*)calloc(1, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + + reparseStructData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + + { // extra scope because we need to close the dirHandle before we can remove that directory + FileHandleWrapper dirHandle(path); + + DWORD bytesReturned; + if (!::DeviceIoControl(dirHandle.handle(), FSCTL_DELETE_REPARSE_POINT, reparseStructData, + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, 0, 0, + &bytesReturned, 0)) { + + qWarning() << QString::fromLatin1("Could not remove the reparse point: '%1'; error: %3" + ).arg(path).arg(GetLastError()); + return false; + } + } + + return QDir().rmdir(path); +} +#else +Link createLnSymlink(const QString &linkPath, const QString &targetPath) +{ + int linkedError = symlink(targetPath.toLocal8Bit(), linkPath.toLocal8Bit()); + if (linkedError != 0) { + qWarning() << QString::fromLatin1("Could not create a symlink: from '%1' to %2; error: %3" + ).arg(linkPath, targetPath).arg(linkedError); + } + + + return Link(linkPath); +} + +bool removeLnSymlink(const QString &path) +{ + return QFile::remove(path); +} + +#endif + +Link::Link(const QString &path) : m_path(path) +{ +} + +Link Link::create(const QString &link, const QString &targetPath) +{ + QStringList pathParts = QFileInfo(link).absoluteFilePath().split(QLatin1Char('/')); + pathParts.removeLast(); + QString linkPath = pathParts.join(QLatin1String("/")); + bool linkPathExists = QFileInfo(linkPath).exists(); + if (!linkPathExists) + linkPathExists = QDir().mkpath(linkPath); + if (!linkPathExists) { + qWarning() << QString::fromLatin1("Could not create the needed directories: %1").arg( + link); + return Link(link); + } + +#ifdef Q_OS_WIN + if (QFileInfo(targetPath).isDir()) + return createJunction(link, targetPath); + + qWarning() << QString::fromLatin1("At the moment the %1 can not create anything else as "\ + "junctions for directories under windows").arg(QLatin1String(Q_FUNC_INFO)); + return Link(link); +#else + return createLnSymlink(link, targetPath); +#endif +} + +QString Link::targetPath() const +{ +#ifdef Q_OS_WIN + return readWindowsSymLink(m_path); +#else + return QFileInfo(m_path).readLink(); +#endif +} + +bool Link::exists() +{ +#ifdef Q_OS_WIN + return QFileInfo(m_path).exists(); +#else + return QFileInfo(m_path).isSymLink(); +#endif +} + +bool Link::targetExists() +{ + return QFileInfo(targetPath()).exists(); +} + +bool Link::isValid() +{ + return targetExists() && QFileInfo(m_path).exists(); +} + +bool Link::remove() +{ + if (!exists()) + return false; +#ifdef Q_OS_WIN + return removeJunction(m_path); +#else + return removeLnSymlink(m_path); +#endif +} diff --git a/src/libs/installer/link.h b/src/libs/installer/link.h new file mode 100644 index 000000000..f54bfecae --- /dev/null +++ b/src/libs/installer/link.h @@ -0,0 +1,53 @@ +/************************************************************************** +** +** This file is part of Installer Framework +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef LINK_H +#define LINK_H + +#include <QString> + +class Link +{ +public: + Link(const QString &path); + static Link create(const QString &link, const QString &targetPath); + QString targetPath() const; + bool targetExists(); + bool exists(); + bool isValid(); + bool remove(); + +private: + QString m_path; +}; + +#endif // LINK_H diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 81537814c..de1e4122d 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -1201,17 +1201,23 @@ QList<QVariant> PackageManagerCore::execute(const QString &program, const QStrin \param program The program that should be executed. \param arguments Optional list of arguments. + \param workingDirectory Optional working directory of the forked process. \return If the command could not be executed, an false will be returned */ -bool PackageManagerCore::executeDetached(const QString &program, const QStringList &arguments) const +bool PackageManagerCore::executeDetached(const QString &program, const QStringList &arguments, + const QString &workingDirectory) const { QString adjustedProgram = replaceVariables(program); QStringList adjustedArguments; + QString adjustedWorkingDir = replaceVariables(workingDirectory); foreach (const QString &argument, arguments) adjustedArguments.append(replaceVariables(argument)); - qDebug() << "run application as detached process:" << adjustedProgram << adjustedArguments; - return QProcess::startDetached(adjustedProgram, adjustedArguments); + qDebug() << "run application as detached process:" << adjustedProgram << adjustedArguments << adjustedWorkingDir; + if (workingDirectory.isEmpty()) + return QProcess::startDetached(adjustedProgram, adjustedArguments); + else + return QProcess::startDetached(adjustedProgram, adjustedArguments, adjustedWorkingDir); } @@ -1369,7 +1375,10 @@ QString PackageManagerCore::value(const QString &key, const QString &defaultValu return dir; } #endif - return d->m_vars.value(key, defaultValue); + if (d->m_vars.contains(key)) + return d->m_vars.value(key); + + return d->m_settings.value(key, defaultValue).toString(); } /*! @@ -1377,11 +1386,12 @@ QString PackageManagerCore::value(const QString &key, const QString &defaultValu */ void PackageManagerCore::setValue(const QString &key, const QString &value) { - if (d->m_vars.value(key) == value) + QString normalizedValue = replaceVariables(value); + if (d->m_vars.value(key) == normalizedValue) return; - d->m_vars.insert(key, value); - emit valueChanged(key, value); + d->m_vars.insert(key, normalizedValue); + emit valueChanged(key, normalizedValue); } /*! @@ -1389,7 +1399,7 @@ void PackageManagerCore::setValue(const QString &key, const QString &value) */ bool PackageManagerCore::containsValue(const QString &key) const { - return d->m_vars.contains(key); + return d->m_vars.contains(key) || d->m_settings.containsValue(key); } void PackageManagerCore::setSharedFlag(const QString &key, bool value) @@ -1542,12 +1552,7 @@ bool PackageManagerCore::isPackageManager() const */ bool PackageManagerCore::runInstaller() { - try { - d->runInstaller(); - return true; - } catch (...) { - return false; - } + return d->runInstaller(); } /*! @@ -1555,12 +1560,7 @@ bool PackageManagerCore::runInstaller() */ bool PackageManagerCore::runUninstaller() { - try { - d->runUninstaller(); - return true; - } catch (...) { - return false; - } + return d->runUninstaller(); } /*! @@ -1568,12 +1568,7 @@ bool PackageManagerCore::runUninstaller() */ bool PackageManagerCore::runPackageUpdater() { - try { - d->runPackageUpdater(); - return true; - } catch (...) { - return false; - } + return d->runPackageUpdater(); } /*! @@ -1591,18 +1586,13 @@ void PackageManagerCore::languageChanged() */ bool PackageManagerCore::run() { - try { - if (isInstaller()) - d->runInstaller(); - else if (isUninstaller()) - d->runUninstaller(); - else if (isPackageManager() || isUpdater()) - d->runPackageUpdater(); - return true; - } catch (const Error &err) { - qDebug() << "Caught Installer Error:" << err.message(); - return false; - } + if (isInstaller()) + return d->runInstaller(); + else if (isUninstaller()) + return d->runUninstaller(); + else if (isPackageManager() || isUpdater()) + return d->runPackageUpdater(); + return false; } /*! diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index b7dd7585e..55d5760fd 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -118,7 +118,8 @@ public: Q_INVOKABLE QList<QVariant> execute(const QString &program, const QStringList &arguments = QStringList(), const QString &stdIn = QString()) const; Q_INVOKABLE bool executeDetached(const QString &program, - const QStringList &arguments = QStringList()) const; + const QStringList &arguments = QStringList(), + const QString &workingDirectory = QString()) const; Q_INVOKABLE QString environmentVariable(const QString &name) const; Q_INVOKABLE bool performOperation(const QString &name, const QStringList &arguments); diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 9bd8c64bb..ccb16d971 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -572,22 +572,6 @@ void PackageManagerCorePrivate::initialize() m_vars.insert(scTargetDir, replaceVariables(m_settings.targetDir())); m_vars.insert(scRemoveTargetDir, replaceVariables(m_settings.removeTargetDir())); - QSettingsWrapper creatorSettings(QSettingsWrapper::IniFormat, QSettingsWrapper::UserScope, - QLatin1String("Nokia"), QLatin1String("QtCreator")); - QFileInfo info(creatorSettings.fileName()); - if (info.exists()) { - m_vars.insert(QLatin1String("QtCreatorSettingsFile"), info.absoluteFilePath()); - QDir settingsDirectory = info.absoluteDir(); - if (settingsDirectory.exists(QLatin1String("qtversion.xml"))) { - m_vars.insert(QLatin1String("QtCreatorSettingsQtVersionFile"), - settingsDirectory.absoluteFilePath(QLatin1String("qtversion.xml"))); - } - if (settingsDirectory.exists(QLatin1String("toolChains.xml"))) { - m_vars.insert(QLatin1String("QtCreatorSettingsToolchainsFile"), - settingsDirectory.absoluteFilePath(QLatin1String("toolChains.xml"))); - } - } - if (!m_core->isInstaller()) { #ifdef Q_OS_MAC readMaintenanceConfigFiles(QCoreApplication::applicationDirPath() + QLatin1String("/../../..")); @@ -931,7 +915,6 @@ void PackageManagerCorePrivate::stopProcessesForUpdates(const QList<Component*> return; while (true) { - const QList<ProcessInfo> allProcesses = runningProcesses(); // FIXME: Unused? const QStringList processes = checkRunningProcessesFromList(processList); if (processes.isEmpty()) return; @@ -1357,17 +1340,8 @@ QString PackageManagerCorePrivate::registerPath() const return QString(); } -void PackageManagerCorePrivate::runInstaller() +bool PackageManagerCorePrivate::runInstaller() { - if (m_dependsOnLocalInstallerBinary && !KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath())) { - setStatus(PackageManagerCore::Failure); - ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation aborted!")); - MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), - QLatin1String("installationError"), tr("Error"), tr("It is not possible to install from network location")); - emit installationFinished(); - throw; - } - bool adminRightsGained = false; try { setStatus(PackageManagerCore::Running); @@ -1421,6 +1395,13 @@ void PackageManagerCorePrivate::runInstaller() const QList<Component*> componentsToInstall = m_core->orderedComponentsToInstall(); qDebug() << "Install size:" << componentsToInstall.size() << "components"; + callBeginInstallation(componentsToInstall); + stopProcessesForUpdates(componentsToInstall); + + if (m_dependsOnLocalInstallerBinary && !KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath())) { + throw Error(tr("It is not possible to install from network location")); + } + if (!adminRightsGained) { foreach (Component *component, m_core->orderedComponentsToInstall()) { if (component->value(scRequiresAdminRights, scFalse) == scFalse) @@ -1450,9 +1431,6 @@ void PackageManagerCorePrivate::runInstaller() info.setApplicationVersion(m_core->value(QLatin1String("ProductVersion"), m_settings.applicationVersion())); - callBeginInstallation(componentsToInstall); - stopProcessesForUpdates(componentsToInstall); - const int progressOperationCount = countProgressOperations(componentsToInstall) + (m_createLocalRepositoryFromBinary ? 1 : 0); // add one more operation as we support progress double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; @@ -1526,20 +1504,18 @@ void PackageManagerCorePrivate::runInstaller() if (adminRightsGained) m_core->dropAdminRights(); emit installationFinished(); - - throw; + return false; } + return true; } -void PackageManagerCorePrivate::runPackageUpdater() +bool PackageManagerCorePrivate::runPackageUpdater() { bool adminRightsGained = false; + if (m_completeUninstall) { + return runUninstaller(); + } try { - if (m_completeUninstall) { - runUninstaller(); - return; - } - setStatus(PackageManagerCore::Running); emit installationStarted(); //resets also the ProgressCoordninator @@ -1554,6 +1530,13 @@ void PackageManagerCorePrivate::runPackageUpdater() const QList<Component *> componentsToInstall = m_core->orderedComponentsToInstall(); qDebug() << "Install size:" << componentsToInstall.size() << "components"; + callBeginInstallation(componentsToInstall); + stopProcessesForUpdates(componentsToInstall); + + if (m_dependsOnLocalInstallerBinary && !KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath())) { + throw Error(tr("It is not possible to run that opertion from a network location")); + } + bool updateAdminRights = false; if (!adminRightsGained) { foreach (Component *component, componentsToInstall) { @@ -1651,9 +1634,6 @@ void PackageManagerCorePrivate::runPackageUpdater() } m_performedOperationsOld = nonRevertedOperations; // these are all operations left: those not reverted - callBeginInstallation(componentsToInstall); - stopProcessesForUpdates(componentsToInstall); - const double progressOperationCount = countProgressOperations(componentsToInstall); const double progressOperationSize = componentsInstallPartProgressSize / progressOperationCount; @@ -1689,12 +1669,12 @@ void PackageManagerCorePrivate::runPackageUpdater() if (adminRightsGained) m_core->dropAdminRights(); emit installationFinished(); - - throw; + return false; } + return true; } -void PackageManagerCorePrivate::runUninstaller() +bool PackageManagerCorePrivate::runUninstaller() { bool adminRightsGained = false; try { @@ -1763,9 +1743,9 @@ void PackageManagerCorePrivate::runUninstaller() if (adminRightsGained) m_core->dropAdminRights(); emit uninstallationFinished(); - - throw; + return false; } + return true; } void PackageManagerCorePrivate::installComponent(Component *component, double progressOperationSize, diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index ecf2f38d4..d2d97e115 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -115,16 +115,16 @@ public: bool appendComponentToInstall(Component *components); QString installReason(Component *component); - void runInstaller(); + bool runInstaller(); bool isInstaller() const; - void runUninstaller(); + bool runUninstaller(); bool isUninstaller() const; void runUpdater(); bool isUpdater() const; - void runPackageUpdater(); + bool runPackageUpdater(); bool isPackageManager() const; QString replaceVariables(const QString &str) const; diff --git a/src/libs/installer/qtcreator_constants.h b/src/libs/installer/qtcreator_constants.h index d8c29a302..546923c82 100644 --- a/src/libs/installer/qtcreator_constants.h +++ b/src/libs/installer/qtcreator_constants.h @@ -33,30 +33,6 @@ #ifndef QTCREATOR_CONSTANTS_H #define QTCREATOR_CONSTANTS_H -#if defined(Q_OS_MAC) - static const char QtCreatorSettingsSuffixPath[] = - "/Qt Creator.app/Contents/Resources/Nokia/QtCreator.ini"; -#else - static const char QtCreatorSettingsSuffixPath[] = - "/QtCreator/share/qtcreator/Nokia/QtCreator.ini"; -#endif - -#if defined(Q_OS_MAC) - static const char ToolChainSettingsSuffixPath[] = - "/Qt Creator.app/Contents/Resources/Nokia/toolChains.xml"; -#else - static const char ToolChainSettingsSuffixPath[] = - "/QtCreator/share/qtcreator/Nokia/toolChains.xml"; -#endif - -#if defined(Q_OS_MAC) - static const char QtVersionSettingsSuffixPath[] = - "/Qt Creator.app/Contents/Resources/Nokia/qtversion.xml"; -#else - static const char QtVersionSettingsSuffixPath[] = - "/QtCreator/share/qtcreator/Nokia/qtversion.xml"; -#endif - // Begin - copied from Creator src\plugins\projectexplorer\toolchainmanager.cpp static const char TOOLCHAIN_DATA_KEY[] = "ToolChain."; static const char TOOLCHAIN_COUNT_KEY[] = "ToolChain.Count"; @@ -74,4 +50,11 @@ static const char QtVersionsSectionName[] = "QtVersions"; static const char newQtVersionsKey[] = "NewQtVersions"; // End - copied from Creator +//the values for these keys are built in packagemanagercore->value() on the fly +//so it is possible that the installer creator can choose the location for these settings files +static const QLatin1String scQtCreatorInstallerSettingsFile("QtCreatorInstallerSettingsFile"); +static const QLatin1String scQtCreatorInstallerToolchainsFile("QtCreatorInstallerToolchainsFile"); +static const QLatin1String scQtCreatorInstallerQtVersionFile("QtCreatorInstallerQtVersionFile"); + + #endif // QTCREATOR_CONSTANTS_H diff --git a/src/libs/installer/qtpatchoperation.cpp b/src/libs/installer/qtpatchoperation.cpp index b8779150a..cf17fab99 100644 --- a/src/libs/installer/qtpatchoperation.cpp +++ b/src/libs/installer/qtpatchoperation.cpp @@ -36,7 +36,6 @@ #include "macrelocateqt.h" #endif -#include "constants.h" #include "packagemanagercore.h" #include <QSet> diff --git a/src/libs/installer/registerdefaultdebuggeroperation.cpp b/src/libs/installer/registerdefaultdebuggeroperation.cpp index 2cdb4e6bc..3b8c97250 100644 --- a/src/libs/installer/registerdefaultdebuggeroperation.cpp +++ b/src/libs/installer/registerdefaultdebuggeroperation.cpp @@ -32,7 +32,6 @@ #include "registerdefaultdebuggeroperation.h" -#include "constants.h" #include "persistentsettings.h" #include "packagemanagercore.h" #include "qtcreator_constants.h" @@ -95,8 +94,13 @@ bool RegisterDefaultDebuggerOperation::performOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - toolChainsXmlFilePath = rootInstallPath + QLatin1String(ToolChainSettingsSuffixPath); + if (core->value(scQtCreatorInstallerToolchainsFile).isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerToolchainsFile)); + return false; + } + toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile); int argCounter = 0; const QString &abiString = args.at(argCounter++); //for example x86-windows-msys-pe-32bit @@ -126,16 +130,23 @@ bool RegisterDefaultDebuggerOperation::undoOperation() return false; } - QString toolChainsXmlFilePath; - PackageManagerCore *const core = qVariantValue<PackageManagerCore *>(value(QLatin1String("installer"))); if (!core) { setError(UserDefinedError); setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - toolChainsXmlFilePath = rootInstallPath + QLatin1String(ToolChainSettingsSuffixPath); + + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/toolChains.xml").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/toolChains.xml").arg(core->value( + QLatin1String("TargetDir")))); +#endif int argCounter = 0; const QString &abiString = args.at(argCounter++); //for example x86-windows-msys-pe-32bit diff --git a/src/libs/installer/registerqtoperation.cpp b/src/libs/installer/registerqtoperation.cpp index 4f721ca4c..ba5083be6 100644 --- a/src/libs/installer/registerqtoperation.cpp +++ b/src/libs/installer/registerqtoperation.cpp @@ -43,6 +43,7 @@ #include <QtCore/QFileInfo> #include <QtCore/QSettings> #include <QtCore/QString> +#include <QDebug> using namespace QInstaller; @@ -68,6 +69,11 @@ bool RegisterQtInCreatorOperation::performOperation() } const QString &rootInstallPath = args.value(0); //for example "C:\\Nokia_SDK\\" + if (!rootInstallPath.isEmpty()) { + qWarning() << QString::fromLatin1("Because of internal changes the first argument(\"%1\") on %2 "\ + "operation is just ignored, please be aware of that").arg(rootInstallPath, name()); + } + const QString &versionName = args.value(1); const QString &path = args.value(2); QString mingwPath = args.value(3); @@ -84,7 +90,14 @@ bool RegisterQtInCreatorOperation::performOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - QString toolChainsXmlFilePath = rootInstallPath + QLatin1String(ToolChainSettingsSuffixPath); + + QString toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile); + if (toolChainsXmlFilePath.isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerToolchainsFile)); + return false; + } bool isCreator22 = false; //in case of the fake installer this component doesn't exist Component *creatorComponent = @@ -151,8 +164,13 @@ bool RegisterQtInCreatorOperation::performOperation() return true; } //END - this is for creator 2.2 - - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), QSettings::IniFormat); + if (core->value(scQtCreatorInstallerSettingsFile).isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerSettingsFile)); + return false; + } + QSettings settings(core->value(scQtCreatorInstallerSettingsFile), QSettings::IniFormat); const QStringList oldNewQtVersions = settings.value(QLatin1String("NewQtVersions")).toString() .split(QLatin1String(";")); @@ -191,8 +209,25 @@ bool RegisterQtInCreatorOperation::performOperation() //works with creator 2.1 and 2.2 bool RegisterQtInCreatorOperation::undoOperation() { - const QString &rootInstallPath = arguments().value(0); //for example "C:\\Nokia_SDK\\" - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), QSettings::IniFormat); + PackageManagerCore *const core = qVariantValue<PackageManagerCore *>(value(QLatin1String("installer"))); + if (!core) { + setError(UserDefinedError); + setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); + return false; + } + + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/QtCreator.ini").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/QtCreator.ini").arg(core->value( + QLatin1String("TargetDir")))); +#endif + + QSettings settings(qtCreatorInstallerSettingsFileName, QSettings::IniFormat); const QStringList oldNewQtVersions = settings.value(QLatin1String("NewQtVersions")).toString() .split(QLatin1String(";")); diff --git a/src/libs/installer/registerqtv23operation.cpp b/src/libs/installer/registerqtv23operation.cpp index 19b0342e7..fc3720c2c 100644 --- a/src/libs/installer/registerqtv23operation.cpp +++ b/src/libs/installer/registerqtv23operation.cpp @@ -32,7 +32,6 @@ #include "registerqtv23operation.h" -#include "constants.h" #include "packagemanagercore.h" #include "qtcreator_constants.h" #include "persistentsettings.h" @@ -104,15 +103,14 @@ bool RegisterQtInCreatorV23Operation::performOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - if (rootInstallPath.isEmpty() || !QDir(rootInstallPath).exists()) { + + if (core->value(scQtCreatorInstallerQtVersionFile).isEmpty()) { setError(UserDefinedError); - setErrorString(tr("The given TargetDir %1 is not a valid/existing dir.").arg(rootInstallPath)); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerQtVersionFile)); return false; } - - const QString qtVersionsFileName = rootInstallPath - + QLatin1String(QtVersionSettingsSuffixPath); + const QString qtVersionsFileName = core->value(scQtCreatorInstallerQtVersionFile); int argCounter = 0; const QString &versionName = args.at(argCounter++); const QString &path = QDir::toNativeSeparators(args.value(argCounter++)); @@ -183,10 +181,17 @@ bool RegisterQtInCreatorV23Operation::undoOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - const QString qtVersionsFileName = rootInstallPath - + QLatin1String(QtVersionSettingsSuffixPath); + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString qtVersionsFileName = core->value(scQtCreatorInstallerQtVersionFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/qtversion.xml").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString qtVersionsFileName = core->value(scQtCreatorInstallerQtVersionFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/qtversion.xml").arg(core->value( + QLatin1String("TargetDir")))); +#endif ProjectExplorer::PersistentSettingsReader reader; // If no file, then it has been removed already diff --git a/src/libs/installer/registerqtv2operation.cpp b/src/libs/installer/registerqtv2operation.cpp index 1209e52b9..63d484a9a 100644 --- a/src/libs/installer/registerqtv2operation.cpp +++ b/src/libs/installer/registerqtv2operation.cpp @@ -32,7 +32,6 @@ #include "registerqtv2operation.h" -#include "constants.h" #include "packagemanagercore.h" #include "qtcreator_constants.h" @@ -71,12 +70,6 @@ bool RegisterQtInCreatorV2Operation::performOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - if (rootInstallPath.isEmpty() || !QDir(rootInstallPath).exists()) { - setError(UserDefinedError); - setErrorString(tr("The given TargetDir %1 is not a valid/existing dir.").arg(rootInstallPath)); - return false; - } int argCounter = 0; const QString &versionName = args.value(argCounter++); @@ -96,8 +89,13 @@ bool RegisterQtInCreatorV2Operation::performOperation() const QString &systemRoot = QDir::toNativeSeparators(args.value(argCounter++)); //Symbian SDK root for example const QString &sbsPath = QDir::toNativeSeparators(args.value(argCounter++)); - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), - QSettings::IniFormat); + if (core->value(scQtCreatorInstallerSettingsFile).isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerSettingsFile)); + return false; + } + QSettings settings(core->value(scQtCreatorInstallerSettingsFile), QSettings::IniFormat); QString newVersions; QStringList oldNewQtVersions = settings.value(QLatin1String("NewQtVersions") @@ -147,7 +145,6 @@ bool RegisterQtInCreatorV2Operation::undoOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); int argCounter = 0; const QString &versionName = args.value(argCounter++); @@ -164,8 +161,18 @@ bool RegisterQtInCreatorV2Operation::undoOperation() } qmakePath = QDir::toNativeSeparators(qmakePath); - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), - QSettings::IniFormat); + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/QtCreator.ini").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/QtCreator.ini").arg(core->value( + QLatin1String("TargetDir")))); +#endif + + QSettings settings(qtCreatorInstallerSettingsFileName, QSettings::IniFormat); QString newVersions; QStringList oldNewQtVersions = settings.value(QLatin1String("NewQtVersions") diff --git a/src/libs/installer/registerqtvqnxoperation.cpp b/src/libs/installer/registerqtvqnxoperation.cpp index c7cdb8c4f..1cce3c7dc 100644 --- a/src/libs/installer/registerqtvqnxoperation.cpp +++ b/src/libs/installer/registerqtvqnxoperation.cpp @@ -32,7 +32,6 @@ #include "registerqtvqnxoperation.h" -#include "constants.h" #include "packagemanagercore.h" #include "qtcreator_constants.h" #include "persistentsettings.h" @@ -104,15 +103,14 @@ bool RegisterQtInCreatorQNXOperation::performOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - if (rootInstallPath.isEmpty() || !QDir(rootInstallPath).exists()) { + + if (core->value(scQtCreatorInstallerQtVersionFile).isEmpty()) { setError(UserDefinedError); - setErrorString(tr("The given TargetDir %1 is not a valid/existing dir.").arg(rootInstallPath)); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerQtVersionFile)); return false; } - - const QString qtVersionsFileName = rootInstallPath - + QLatin1String(QtVersionSettingsSuffixPath); + const QString qtVersionsFileName = core->value(scQtCreatorInstallerQtVersionFile); int argCounter = 0; const QString &versionName = args.at(argCounter++); const QString &path = QDir::toNativeSeparators(args.value(argCounter++)); @@ -185,10 +183,17 @@ bool RegisterQtInCreatorQNXOperation::undoOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - const QString qtVersionsFileName = rootInstallPath - + QLatin1String(QtVersionSettingsSuffixPath); + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString qtVersionsFileName = core->value(scQtCreatorInstallerQtVersionFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/qtversion.xml").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString qtVersionsFileName = core->value(scQtCreatorInstallerQtVersionFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/qtversion.xml").arg(core->value( + QLatin1String("TargetDir")))); +#endif ProjectExplorer::PersistentSettingsReader reader; // If no file, then it has been removed already diff --git a/src/libs/installer/registertoolchainoperation.cpp b/src/libs/installer/registertoolchainoperation.cpp index 66190e289..414f8ba14 100644 --- a/src/libs/installer/registertoolchainoperation.cpp +++ b/src/libs/installer/registertoolchainoperation.cpp @@ -32,7 +32,6 @@ #include "registertoolchainoperation.h" -#include "constants.h" #include "persistentsettings.h" #include "packagemanagercore.h" #include "qtcreator_constants.h" @@ -76,8 +75,13 @@ bool RegisterToolChainOperation::performOperation() setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - toolChainsXmlFilePath = rootInstallPath + QLatin1String(ToolChainSettingsSuffixPath); + if (core->value(scQtCreatorInstallerToolchainsFile).isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerToolchainsFile)); + return false; + } + toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile); QtCreatorToolChain toolChain; @@ -123,16 +127,23 @@ bool RegisterToolChainOperation::undoOperation() return false; } - QString toolChainsXmlFilePath; - PackageManagerCore *const core = qVariantValue<PackageManagerCore*>(value(QLatin1String("installer"))); if (!core) { setError(UserDefinedError); setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - toolChainsXmlFilePath = rootInstallPath + QLatin1String(ToolChainSettingsSuffixPath); + + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/toolChains.xml").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/toolChains.xml").arg(core->value( + QLatin1String("TargetDir")))); +#endif QtCreatorToolChain toolChain; diff --git a/src/libs/installer/setqtcreatorvalueoperation.cpp b/src/libs/installer/setqtcreatorvalueoperation.cpp index a63c46e58..d1fb074d1 100644 --- a/src/libs/installer/setqtcreatorvalueoperation.cpp +++ b/src/libs/installer/setqtcreatorvalueoperation.cpp @@ -37,6 +37,7 @@ #include "packagemanagercore.h" #include <QtCore/QSettings> +#include <QDebug> using namespace QInstaller; @@ -65,13 +66,31 @@ bool SetQtCreatorValueOperation::performOperation() return false; } + PackageManagerCore *const core = qVariantValue<PackageManagerCore *>(value(QLatin1String("installer"))); + if (!core) { + setError(UserDefinedError); + setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); + return false; + } + const QString &rootInstallPath = args.at(0); //for example "C:\\Nokia_SDK\\" + if (!rootInstallPath.isEmpty()) { + qWarning() << QString::fromLatin1("Because of internal changes the first argument(\"%1\") on %2 "\ + "operation is just ignored, please be aware of that").arg(rootInstallPath, name()); + } const QString &group = groupName(args.at(1)); const QString &key = args.at(2); const QString &settingsValue = args.at(3); { - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), QSettings::IniFormat); + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile); + if (qtCreatorInstallerSettingsFileName.isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerSettingsFile)); + return false; + } + QSettings settings(qtCreatorInstallerSettingsFileName, QSettings::IniFormat); if (!group.isEmpty()) settings.beginGroup(group); @@ -110,11 +129,33 @@ bool SetQtCreatorValueOperation::undoOperation() const QStringList args = arguments(); const QString &rootInstallPath = args.at(0); //for example "C:\\Nokia_SDK\\" + if (!rootInstallPath.isEmpty()) { + qWarning() << QString::fromLatin1("Because of internal changes the first argument(\"%1\") on %2 "\ + "operation is just ignored, please be aware of that").arg(rootInstallPath, name()); + } const QString &group = groupName(args.at(1)); const QString &key = args.at(2); - QSettings settings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), QSettings::IniFormat); + PackageManagerCore *const core = qVariantValue<PackageManagerCore *>(value(QLatin1String("installer"))); + if (!core) { + setError(UserDefinedError); + setErrorString(tr("Needed installer object in \"%1\" operation is empty.").arg(name())); + return false; + } + + // default value is the old value to keep the possibility that old saved operations can run undo +#ifdef Q_OS_MAC + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/Qt Creator.app/Contents/Resources/Nokia/QtCreator.ini").arg( + core->value(QLatin1String("TargetDir")))); +#else + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile, + QString::fromLatin1("%1/QtCreator/share/qtcreator/Nokia/QtCreator.ini").arg(core->value( + QLatin1String("TargetDir")))); +#endif + + QSettings settings(qtCreatorInstallerSettingsFileName, QSettings::IniFormat); if (!group.isEmpty()) settings.beginGroup(group); diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp index c7b1394cc..181152646 100644 --- a/src/libs/installer/settings.cpp +++ b/src/libs/installer/settings.cpp @@ -343,7 +343,7 @@ QStringList Settings::certificateFiles() const return d->m_data.value(scSigningCertificate).toStringList(); } -bool Settings::allowNoneAsciiCharacters() const +bool Settings::allowNonAsciiCharacters() const { return d->m_data.value(scAllowNonAsciiCharacters).toBool(); } @@ -465,6 +465,11 @@ void Settings::addUserRepositories(const QSet<Repository> &repositories) d->m_data.insertMulti(scUserRepositories, QVariant().fromValue(repository)); } +bool Settings::containsValue(const QString &key) const +{ + return d->m_data.contains(key); +} + QVariant Settings::value(const QString &key, const QVariant &defaultValue) const { return d->m_data.value(key, defaultValue); diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h index 12eba079b..ad7ad9e1f 100644 --- a/src/libs/installer/settings.h +++ b/src/libs/installer/settings.h @@ -113,8 +113,9 @@ public: void addUserRepositories(const QSet<Repository> &repositories); QStringList certificateFiles() const; - bool allowNoneAsciiCharacters() const; + bool allowNonAsciiCharacters() const; + bool containsValue(const QString &key) const; QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; QVariantList values(const QString &key, const QVariantList &defaultValue = QVariantList()) const; diff --git a/src/libs/installer/updatecreatorsettingsfrom21to22operation.cpp b/src/libs/installer/updatecreatorsettingsfrom21to22operation.cpp index edf4b2fab..289ef404e 100644 --- a/src/libs/installer/updatecreatorsettingsfrom21to22operation.cpp +++ b/src/libs/installer/updatecreatorsettingsfrom21to22operation.cpp @@ -32,7 +32,6 @@ #include "updatecreatorsettingsfrom21to22operation.h" -#include "constants.h" #include "registerdefaultdebuggeroperation.h" #include "registertoolchainoperation.h" #include "qtcreatorpersistentsettings.h" @@ -288,12 +287,23 @@ bool UpdateCreatorSettingsFrom21To22Operation::performOperation() setErrorString(tr("Needed installer object in %1 operation is empty.").arg(name())); return false; } - const QString &rootInstallPath = core->value(scTargetDir); - QString toolChainsXmlFilePath = rootInstallPath + QLatin1String(ToolChainSettingsSuffixPath); + QString toolChainsXmlFilePath = core->value(scQtCreatorInstallerToolchainsFile); + if (toolChainsXmlFilePath.isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerToolchainsFile)); + return false; + } - QSettings sdkSettings(rootInstallPath + QLatin1String(QtCreatorSettingsSuffixPath), - QSettings::IniFormat); + QString qtCreatorInstallerSettingsFileName = core->value(scQtCreatorInstallerSettingsFile); + if (qtCreatorInstallerSettingsFileName.isEmpty()) { + setError(UserDefinedError); + setErrorString(tr("There is no value set for %1 on the installer object.").arg( + scQtCreatorInstallerSettingsFile)); + return false; + } + QSettings sdkSettings(qtCreatorInstallerSettingsFileName, QSettings::IniFormat); convertDefaultGDBInstallerSettings(sdkSettings, core); diff --git a/src/libs/kdtools/kdlockfile_unix.cpp b/src/libs/kdtools/kdlockfile_unix.cpp index c40eb3b7d..6f362b974 100644 --- a/src/libs/kdtools/kdlockfile_unix.cpp +++ b/src/libs/kdtools/kdlockfile_unix.cpp @@ -28,6 +28,8 @@ #include <sys/file.h> +#include <unistd.h> + KDLockFile::Private::~Private() { unlock(); diff --git a/src/libs/kdtools/kdsavefile.cpp b/src/libs/kdtools/kdsavefile.cpp index d866968cf..94ed1aa36 100644 --- a/src/libs/kdtools/kdsavefile.cpp +++ b/src/libs/kdtools/kdsavefile.cpp @@ -34,6 +34,9 @@ #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> +#ifdef Q_OS_LINUX +#include <unistd.h> +#endif static int permissionsToMode(QFile::Permissions p, bool *ok) { diff --git a/src/libs/kdtools/kdsysinfo_win.cpp b/src/libs/kdtools/kdsysinfo_win.cpp index 3e99e3925..8681c6825 100644 --- a/src/libs/kdtools/kdsysinfo_win.cpp +++ b/src/libs/kdtools/kdsysinfo_win.cpp @@ -22,6 +22,8 @@ #include "kdsysinfo.h" +#include "link.h" + #include <windows.h> #include <Psapi.h> #include <Tlhelp32.h> @@ -249,93 +251,6 @@ bool killProcess(const ProcessInfo &process, int msecs) return returnValue; } -// REPARSE_DATA_BUFFER structure from msdn help: http://msdn.microsoft.com/en-us/library/ff552012.aspx -typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; - -QString junctionTargetPath(const QString &path) -{ - HANDLE fileHandle; - fileHandle = CreateFile(path.utf16(), FILE_READ_EA, FILE_SHARE_READ | FILE_SHARE_WRITE | - FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | - FILE_FLAG_OPEN_REPARSE_POINT, NULL); - if (fileHandle == INVALID_HANDLE_VALUE) { - qDebug() << QString::fromLatin1("Could not open: '%1'; error: %2\n").arg(path).arg(GetLastError()); - return path; - } - - REPARSE_DATA_BUFFER* reparseStructData = (REPARSE_DATA_BUFFER*)calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - - DWORD bytesReturned; - // fill the reparseStructData - BOOL isOk = DeviceIoControl(fileHandle, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseStructData, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, NULL); - if (isOk == FALSE) { - DWORD deviceIOControlError = GetLastError(); - if (deviceIOControlError == ERROR_NOT_A_REPARSE_POINT) - qDebug() << QString::fromLatin1("Could not reparse information (windows symlink) for %1").arg(path); - else { - qDebug() << QString::fromLatin1("Get DeviceIoControl for %1 failed with error: %2").arg( - path).arg(deviceIOControlError); - } - CloseHandle(fileHandle); - return path; - } - CloseHandle(fileHandle); - - QString realPath = path; - if (IsReparseTagMicrosoft(reparseStructData->ReparseTag)) { - size_t realPathLength = 0; - WCHAR *realPathWCHAR = 0; - if (reparseStructData->ReparseTag == IO_REPARSE_TAG_SYMLINK){ - realPathLength = reparseStructData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR); - realPathWCHAR = new WCHAR[realPathLength + 1]; - wcsncpy_s(realPathWCHAR, realPathLength + 1, &reparseStructData->SymbolicLinkReparseBuffer.PathBuffer[ - reparseStructData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], realPathLength); - } else if (reparseStructData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { - realPathLength = reparseStructData->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR); - realPathWCHAR = new WCHAR[realPathLength + 1]; - wcsncpy_s(realPathWCHAR, realPathLength + 1, &reparseStructData->MountPointReparseBuffer.PathBuffer[ - reparseStructData->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)], realPathLength); - } else { - qDebug() << QString::fromLatin1("Path %1 is not a symlink and not a mount point.").arg(path); - } - if (realPathLength != 0) { - realPathWCHAR[realPathLength] = 0; - realPath = QString::fromStdWString(realPathWCHAR); - delete [] realPathWCHAR; - } - - } else { - qDebug() << QString::fromLatin1("Path %1 is not reparse point.").arg(path); - } - free(reparseStructData); - return realPath; -} - bool pathIsOnLocalDevice(const QString &path) { if (!QFileInfo(path).exists()) @@ -348,7 +263,7 @@ bool pathIsOnLocalDevice(const QString &path) do { if (QFileInfo(dir, QString()).isSymLink()) { QString currentPath = QFileInfo(dir, QString()).absoluteFilePath(); - return pathIsOnLocalDevice(junctionTargetPath(currentPath)); + return pathIsOnLocalDevice(Link(currentPath).targetPath()); } } while (dir.cdUp()); diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp index 10932311a..d73040e77 100644 --- a/src/sdk/installerbase.cpp +++ b/src/sdk/installerbase.cpp @@ -70,6 +70,8 @@ using namespace QInstaller; using namespace QInstallerCreator; +static const char installer_create_datetime_placeholder [32] = "MY_InstallerCreateDateTime_MY"; + static QStringList repositories(const QStringList &arguments, const int index) { if (index < arguments.size()) { @@ -122,7 +124,16 @@ int main(int argc, char *argv[]) try { if (args.contains(QLatin1String("--version"))) { - InstallerBase::showVersion(QLatin1String(VERSION)); + QString versionOutPut; + QDateTime dateTimeCheck = QDateTime::fromString(QLatin1String( + installer_create_datetime_placeholder), QLatin1String("yyyy-MM-dd - HH:mm:ss")); + if (dateTimeCheck.isValid()) { + versionOutPut.append(QLatin1String("Installer creation time: ")); + versionOutPut.append(QLatin1String(installer_create_datetime_placeholder)); + versionOutPut.append(QLatin1String("\n")); + } + versionOutPut.append(QLatin1String(VERSION)); + InstallerBase::showVersion(versionOutPut); return 0; } diff --git a/src/sdk/installerbasecommons.cpp b/src/sdk/installerbasecommons.cpp index 0f6411f00..501a8a4a5 100644 --- a/src/sdk/installerbasecommons.cpp +++ b/src/sdk/installerbasecommons.cpp @@ -401,7 +401,7 @@ bool TargetDirectoryPageImpl::validatePage() return true; const QString targetDir = this->targetDir(); - if (!packageManagerCore()->settings().allowNoneAsciiCharacters()) { + if (!packageManagerCore()->settings().allowNonAsciiCharacters()) { for (int i = 0; i < targetDir.length(); ++i) { if (targetDir.at(i).unicode() & 0xff80) { return failWithError(QLatin1String("NonAsciiTarget"), tr("The path or installation directory " diff --git a/src/sdk/sdk.pro b/src/sdk/sdk.pro index 7ca88ef93..3cf5b6c64 100644 --- a/src/sdk/sdk.pro +++ b/src/sdk/sdk.pro @@ -5,7 +5,6 @@ TARGET = installerbase include(../../installerfw.pri) -LIBS += -linstaller QT += network script CONFIG -= app_bundle diff --git a/tests/test-installer/create-test-installer.bat b/tests/test-installer/create-test-installer.bat index 866e41f4c..9db034dad 100644 --- a/tests/test-installer/create-test-installer.bat +++ b/tests/test-installer/create-test-installer.bat @@ -1,76 +1,93 @@ -IF "%1" EQU "" ( - set OFFLINE_INSTALLER=true - set ONLINE_INSTALLER=true - set REPOGEN=true - set TEST_ONLINE_INSTALLER=false - set TEST_OFFLINE_INSTALLER=false +@IF "%1" EQU "" ( + @set OFFLINE_INSTALLER=true + @set ONLINE_INSTALLER=true + @set REPOGEN=true + @set TEST_ONLINE_INSTALLER=false + @set TEST_OFFLINE_INSTALLER=false ) else ( - set OFFLINE_INSTALLER=false - set ONLINE_INSTALLER=false - set REPOGEN=false - set TEST_ONLINE_INSTALLER=false - set TEST_OFFLINE_INSTALLER=false + @set OFFLINE_INSTALLER=false + @set ONLINE_INSTALLER=false + @set REPOGEN=false + @set TEST_ONLINE_INSTALLER=false + @set TEST_OFFLINE_INSTALLER=false ) -for %%i in (%1,%2,%3,%4,%5,%6,%7,%8,%9) DO ( - IF "%%i" EQU "offline" ( - set OFFLINE_INSTALLER=true +@for %%i in (%1,%2,%3,%4,%5,%6,%7,%8,%9) DO ( + @IF "%%i" EQU "offline" ( + @set OFFLINE_INSTALLER=true ) - IF "%%i" EQU "online" ( - set ONLINE_INSTALLER=true + @IF "%%i" EQU "online" ( + @set ONLINE_INSTALLER=true ) - IF "%%i" EQU "repogen" ( - set REPOGEN=true + @IF "%%i" EQU "repogen" ( + @set REPOGEN=true ) - IF "%%i" EQU "test_online" ( - set TEST_ONLINE_INSTALLER=true + @IF "%%i" EQU "test_online" ( + @set TEST_ONLINE_INSTALLER=true ) - IF "%%i" EQU "test_offline" ( - set TEST_OFFLINE_INSTALLER=true + @IF "%%i" EQU "test_offline" ( + @set TEST_OFFLINE_INSTALLER=true ) ) -set AUTO_INSTALLATION_SCRIPT=--script %CD%\auto_installations_script.qs +@set AUTO_INSTALLATION_SCRIPT=--script %CD%\auto_installations_script.qs -set BINARY_PATH_RELATIVE=%CD%\..\..\installerbuilder\bin -pushd . -cd %BINARY_PATH_RELATIVE% -set BINARY_PATH_ABSOLUTE=%CD% -popd +@set BINARY_PATH_RELATIVE=%CD%\..\..\bin +@pushd . +@cd %BINARY_PATH_RELATIVE% +@set BINARY_PATH_ABSOLUTE=%CD% +@popd -set LOCAL_REPOSITORY=file:///%BINARY_PATH_ABSOLUTE%/repository -set LOCAL_REPOSITORY_PATH=%LOCAL_REPOSITORY:\=/% +@set LOCAL_REPOSITORY=file:///%BINARY_PATH_ABSOLUTE%/repository +@set LOCAL_REPOSITORY_PATH=%LOCAL_REPOSITORY:\=/% call BatchSubstitute.bat http://www.xxxx.com/repository %LOCAL_REPOSITORY_PATH% ..\..\examples\testapp\config\config.xml > ..\..\examples\testapp\config\config.xml_new +@if %ERRORLEVEL% NEQ 0 goto error_marker copy /Y ..\..\examples\testapp\config\config.xml ..\..\examples\testapp\config\config.xml_old +@if %ERRORLEVEL% NEQ 0 goto error_marker + move /Y ..\..\examples\testapp\config\config.xml_new ..\..\examples\testapp\config\config.xml +@if %ERRORLEVEL% NEQ 0 goto error_marker IF "%OFFLINE_INSTALLER%" EQU "true" ( echo create offline installer - ..\..\installerbuilder\bin\binarycreator -t ..\..\installerbuilder\bin\installerbase.exe -v -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config --offline-only ..\..\installerbuilder\bin\test-installer-offline.exe com.nokia.testapp - IF errorlevel 1 pause ELSE echo ...done + ..\..\bin\binarycreator -t ..\..\bin\installerbase.exe -v -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config\config.xml --offline-only ..\..\bin\test-installer-offline.exe + @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) IF "%ONLINE_INSTALLER%" EQU "true" ( echo create online installer - ..\..\installerbuilder\bin\binarycreator -t ..\..\installerbuilder\bin\installerbase.exe -v -n -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config ..\..\installerbuilder\bin\test-installer-online.exe com.nokia.testapp - IF errorlevel 1 pause ELSE echo ...done + ..\..\bin\binarycreator -t ..\..\bin\installerbase.exe -v -n -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config\config.xml ..\..\bin\test-installer-online.exe + @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) IF "%REPOGEN%" EQU "true" ( echo create online repository - IF exist ..\..\installerbuilder\bin\repository rmdir /S /Q ..\..\installerbuilder\bin\repository - ..\..\installerbuilder\bin\repogen.exe -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config ..\..\installerbuilder\bin\repository com.nokia.testapp - IF errorlevel 1 pause ELSE echo ...done + @IF exist ..\..\bin\repository rmdir /S /Q ..\..\bin\repository + ..\..\bin\repogen.exe -p ..\..\examples\testapp\packages -c ..\..\examples\testapp\config\config.xml ..\..\bin\repository + @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) -IF "%TEST_OFFLINE_INSTALLER%" EQU "true" ( - ..\..\installerbuilder\bin\test-installer-offline.exe --verbose %AUTO_INSTALLATION_SCRIPT% +@IF "%TEST_OFFLINE_INSTALLER%" EQU "true" ( + ..\..\bin\test-installer-offline.exe --verbose %AUTO_INSTALLATION_SCRIPT% + @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) -IF "%TEST_ONLINE_INSTALLER%" EQU "true" ( - ..\..\installerbuilder\bin\test-installer-online.exe --verbose %AUTO_INSTALLATION_SCRIPT% +@IF "%TEST_ONLINE_INSTALLER%" EQU "true" ( + ..\..\bin\test-installer-online.exe --verbose %AUTO_INSTALLATION_SCRIPT% + @if %ERRORLEVEL% NEQ 0 goto error_marker ELSE goto done_marker ) copy /Y ..\..\examples\testapp\config\config.xml_old ..\..\examples\testapp\config\config.xml +@if %ERRORLEVEL% NEQ 0 goto error_marker + +goto done_marker + +:error_marker +echo *** Error compiling ifw *** +pause + +:done_marker +echo ...done + diff --git a/tools/archivegen/archive.cpp b/tools/archivegen/archive.cpp index 2d1257ae7..3b8db3e79 100644 --- a/tools/archivegen/archive.cpp +++ b/tools/archivegen/archive.cpp @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) QInstaller::init(); QInstaller::setVerbose(true); const QStringList sourceDirectories = app.arguments().mid(2); - QInstallerTools::compressDirectory(sourceDirectories, app.arguments().at(1)); + QInstallerTools::compressPaths(sourceDirectories, app.arguments().at(1)); return EXIT_SUCCESS; } catch (const Lib7z::SevenZipException &e) { std::cerr << e.message() << std::endl; diff --git a/tools/archivegen/archivegen.pro b/tools/archivegen/archivegen.pro index ff9fdbd59..886a9856e 100644 --- a/tools/archivegen/archivegen.pro +++ b/tools/archivegen/archivegen.pro @@ -7,7 +7,6 @@ include(../../installerfw.pri) QT -= gui QT += script -LIBS += -linstaller CONFIG += console CONFIG -= app_bundle diff --git a/tools/binarycreator/binarycreator.cpp b/tools/binarycreator/binarycreator.cpp index 9ec1d7106..ef3bd1fb0 100644 --- a/tools/binarycreator/binarycreator.cpp +++ b/tools/binarycreator/binarycreator.cpp @@ -31,6 +31,8 @@ **************************************************************************/ #include "common/repositorygen.h" +#include <qtpatch.h> + #include <binaryformat.h> #include <errors.h> #include <fileutils.h> @@ -194,6 +196,11 @@ Q_UNUSED(settings) throw Error(QObject::tr("Could not copy %1 to %2: %3").arg(instExe.fileName(), tempFile, instExe.errorString())); } + + QtPatch::patchBinaryFile(tempFile, QByteArray("MY_InstallerCreateDateTime_MY"), + QDateTime::currentDateTime().toString(QLatin1String("yyyy-MM-dd - HH:mm:ss")).toAscii()); + + input.installerExePath = tempFile; #if defined(Q_OS_WIN) diff --git a/tools/binarycreator/binarycreator.pro b/tools/binarycreator/binarycreator.pro index 706318ebc..2e36e1575 100644 --- a/tools/binarycreator/binarycreator.pro +++ b/tools/binarycreator/binarycreator.pro @@ -7,7 +7,6 @@ include(../../installerfw.pri) QT -= gui QT += script -LIBS += -linstaller CONFIG += console CONFIG -= app_bundle diff --git a/tools/common/repositorygen.cpp b/tools/common/repositorygen.cpp index 8534c1c20..d72ea2548 100644 --- a/tools/common/repositorygen.cpp +++ b/tools/common/repositorygen.cpp @@ -65,13 +65,8 @@ void QInstallerTools::printRepositoryGenOptions() std::cout << " --ignore-invalid-packages Ignore all invalid packages instead of aborting." << std::endl; } -void QInstallerTools::compressDirectory(const QStringList &paths, const QString &archivePath) +void QInstallerTools::compressPaths(const QStringList &paths, const QString &archivePath) { - foreach (const QString &path, paths) { - if (!QFileInfo(path).exists()) - throw QInstaller::Error(QObject::tr("Folder %1 does not exist.").arg(path)); - } - QFile archive(archivePath); QInstaller::openForWrite(&archive, archivePath); Lib7z::createArchive(&archive, paths); @@ -87,7 +82,7 @@ void QInstallerTools::compressMetaDirectories(const QString &repoDir) const QString absPath = sd.absolutePath(); const QString fn = QLatin1String("meta.7z"); const QString tmpTarget = repoDir + QLatin1String("/") +fn; - compressDirectory(QStringList() << absPath, tmpTarget); + compressPaths(QStringList() << absPath, tmpTarget); QFile tmp(tmpTarget); const QString finalTarget = absPath + QLatin1String("/") + fn; if (!tmp.rename(finalTarget)) { @@ -545,7 +540,7 @@ void QInstallerTools::compressMetaDirectories(const QString &repoDir, const QStr const QString absPath = sd.absolutePath(); const QString fn = QLatin1String(versionPrefix.toLatin1() + "meta.7z"); const QString tmpTarget = repoDir + QLatin1String("/") +fn; - compressDirectory(QStringList() << absPath, tmpTarget); + compressPaths(QStringList() << absPath, tmpTarget); // remove the files that got compressed QInstaller::removeFiles(absPath, true); @@ -595,7 +590,7 @@ void QInstallerTools::copyComponentData(const QString &packageDir, const QString } else if (fileInfo.isDir()) { qDebug() << "Compressing data directory" << entry; target = QString::fromLatin1("%1/%2/%4%3.7z").arg(repoDir, name, entry, info.version); - QInstallerTools::compressDirectory(QStringList() << dataDir.absoluteFilePath(entry), target); + QInstallerTools::compressPaths(QStringList() << dataDir.absoluteFilePath(entry), target); } else { continue; } diff --git a/tools/common/repositorygen.h b/tools/common/repositorygen.h index 7cb7a07a0..0e73d8a00 100644 --- a/tools/common/repositorygen.h +++ b/tools/common/repositorygen.h @@ -59,7 +59,7 @@ enum FilterType { QHash<QString, QString> buildPathToVersionMapping(const PackageInfoVector &info); void compressMetaDirectories(const QString &repoDir); -void compressDirectory(const QStringList &paths, const QString &archivePath); +void compressPaths(const QStringList &paths, const QString &archivePath); void compressMetaDirectories(const QString &repoDir, const QString &baseDir, const QHash<QString, QString> &versionMapping); diff --git a/tools/repogen/repogen.pro b/tools/repogen/repogen.pro index 5b6f0d03a..e4df1f56b 100644 --- a/tools/repogen/repogen.pro +++ b/tools/repogen/repogen.pro @@ -7,7 +7,6 @@ include(../../installerfw.pri) QT -= gui QT += script -LIBS += -linstaller CONFIG += console CONFIG -= app_bundle |