diff options
author | Christian Kandeler <christian.kandeler@digia.com> | 2014-01-09 17:50:40 +0100 |
---|---|---|
committer | Joerg Bornemann <joerg.bornemann@digia.com> | 2014-01-10 18:11:22 +0100 |
commit | 81af9acaa295a574c1cb5e6714725197dac7f530 (patch) | |
tree | cc8c94467f49a7d267e5249f624874feecc7eed4 /src/lib/corelib/tools | |
parent | 2fe25eb3f20ffb4e58cb559f2bcb9950c963290a (diff) |
Move Qt profile setup into a dedicated library.
Otherwise all changes to the implementation will have to be duplicated
in IDEs.
Change-Id: I61e6d4fa1ee9b724eb5d9de9f233dc915a6c8bc3
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Diffstat (limited to 'src/lib/corelib/tools')
49 files changed, 6143 insertions, 0 deletions
diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp new file mode 100644 index 000000000..2261124d8 --- /dev/null +++ b/src/lib/corelib/tools/buildoptions.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "buildoptions.h" + +#include <QSharedData> +#include <QThread> + +namespace qbs { +namespace Internal { + +class BuildOptionsPrivate : public QSharedData +{ +public: + BuildOptionsPrivate() : maxJobCount(0), dryRun(false), keepGoing(false), logElapsedTime(false) + { + } + + QStringList changedFiles; + QStringList activeFileTags; + int maxJobCount; + bool dryRun; + bool keepGoing; + bool forceTimestampCheck; + bool logElapsedTime; +}; + +} // namespace Internal + +/*! + * \class BuildOptions + * \brief The \c BuildOptions class comprises parameters that influence the behavior of + * build and clean operations. + */ + +/*! + * \brief Creates a \c BuildOptions object and initializes its members to sensible default values. + */ +BuildOptions::BuildOptions() : d(new Internal::BuildOptionsPrivate) +{ +} + +BuildOptions::BuildOptions(const BuildOptions &other) : d(other.d) +{ +} + +BuildOptions &BuildOptions::operator=(const BuildOptions &other) +{ + d = other.d; + return *this; +} + +BuildOptions::~BuildOptions() +{ +} + +/*! + * \brief If non-empty, qbs pretends that only these files have changed. + * By default, this list is empty. + */ +QStringList BuildOptions::changedFiles() const +{ + return d->changedFiles; +} + +/*! + * \brief If the given list is empty, qbs will pretend only the listed files are changed. + * \note The list elements must be absolute file paths. + */ +void BuildOptions::setChangedFiles(const QStringList &changedFiles) +{ + d->changedFiles = changedFiles; +} + +/*! + * \brief The list of active file tags. + * \sa setActiveFileTags + */ +QStringList BuildOptions::activeFileTags() const +{ + return d->activeFileTags; +} + +/*! + * \brief Set the list of active file tags. + * If this list is non-empty, then every transformer with non-matching output file tags is skipped. + * E.g. set changed files to "foo.cpp" and activeFileTags to ["obj"] to run the compiler + * on foo.cpp without further processing like linking. + * \sa activeFileTags + */ +void BuildOptions::setActiveFileTags(const QStringList &fileTags) +{ + d->activeFileTags = fileTags; +} + +/*! + * \brief Returns the default value for \c maxJobCount. + * This value will be used when \c maxJobCount has not been set explicitly. + */ +int BuildOptions::defaultMaxJobCount() +{ + return QThread::idealThreadCount(); +} + +/*! + * \brief Returns the maximum number of build commands to run concurrently. + * If the value is not valid (i.e. <= 0), a sensible one will be derived at build time + * from the number of available processor cores at build time. + * The default is 0. + * \sa BuildOptions::defaultMaxJobCount + */ +int BuildOptions::maxJobCount() const +{ + return d->maxJobCount; +} + +/*! + * \brief Controls how many build commands can be run in parallel. + * A value <= 0 leaves the decision to qbs. + */ +void BuildOptions::setMaxJobCount(int jobCount) +{ + d->maxJobCount = jobCount; +} + +/*! + * \brief Returns true iff qbs will not actually execute any commands, but just show what + * would happen. + * The default is false. + */ +bool BuildOptions::dryRun() const +{ + return d->dryRun; +} + +/*! + * \brief Controls whether qbs will actually build something. + * If the argument is true, qbs will just emit information about what it would do. Otherwise, + * the build is actually done. + * \note After you build with this setting enabled, the next call to \c build() on the same + * \c Project object will do nothing, since the internal state needs to be updated the same way + * as if an actual build had happened. You'll need to create a new \c Project object to do + * a real build afterwards. + */ +void BuildOptions::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} + +/*! + * \brief Returns true iff a build will continue after an error. + * E.g. a failed compile command will result in a warning message being printed, instead of + * stopping the build process right away. However, there might still be fatal errors after which the + * build process cannot continue. + * The default is \c false. + */ +bool BuildOptions::keepGoing() const +{ + return d->keepGoing; +} + +/*! + * \brief Controls whether a qbs will try to continue building after an error has occurred. + */ +void BuildOptions::setKeepGoing(bool keepGoing) +{ + d->keepGoing = keepGoing; +} + +/*! + * \brief Returns true if qbs is to use physical timestamps instead of the timestamps stored in the + * build graph. + * The default is \c false. + */ +bool BuildOptions::forceTimestampCheck() const +{ + return d->forceTimestampCheck; +} + +/*! + * \brief Controls whether qbs should use physical timestamps for up-to-date checks. + */ +void BuildOptions::setForceTimestampCheck(bool enabled) +{ + d->forceTimestampCheck = enabled; +} + +/*! + * \brief Returns true iff the time the operation takes will be logged. + * The default is \c false. + */ +bool BuildOptions::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * \brief Controls whether the build time will be measured and logged. + */ +void BuildOptions::setLogElapsedTime(bool log) +{ + d->logElapsedTime = log; +} + + +bool operator==(const BuildOptions &bo1, const BuildOptions &bo2) +{ + return bo1.changedFiles() == bo2.changedFiles() + && bo1.dryRun() == bo2.dryRun() + && bo1.keepGoing() == bo2.keepGoing() + && bo1.logElapsedTime() == bo2.logElapsedTime() + && bo1.maxJobCount() == bo2.maxJobCount(); +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/buildoptions.h b/src/lib/corelib/tools/buildoptions.h new file mode 100644 index 000000000..2c277fc3b --- /dev/null +++ b/src/lib/corelib/tools/buildoptions.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_BUILDOPTIONS_H +#define QBS_BUILDOPTIONS_H + +#include "qbs_export.h" + +#include <QSharedDataPointer> +#include <QStringList> + +namespace qbs { +namespace Internal { class BuildOptionsPrivate; } + +class QBS_EXPORT BuildOptions +{ +public: + BuildOptions(); + BuildOptions(const BuildOptions &other); + BuildOptions &operator=(const BuildOptions &other); + ~BuildOptions(); + + QStringList changedFiles() const; + void setChangedFiles(const QStringList &changedFiles); + + QStringList activeFileTags() const; + void setActiveFileTags(const QStringList &fileTags); + + static int defaultMaxJobCount(); + int maxJobCount() const; + void setMaxJobCount(int jobCount); + + bool dryRun() const; + void setDryRun(bool dryRun); + + bool keepGoing() const; + void setKeepGoing(bool keepGoing); + + bool forceTimestampCheck() const; + void setForceTimestampCheck(bool enabled); + + bool logElapsedTime() const; + void setLogElapsedTime(bool log); + +private: + QSharedDataPointer<Internal::BuildOptionsPrivate> d; +}; + +bool operator==(const BuildOptions &bo1, const BuildOptions &bo2); +inline bool operator!=(const BuildOptions &bo1, const BuildOptions &bo2) { return !(bo1 == bo2); } + +} // namespace qbs + +#endif // QBS_BUILDOPTIONS_H diff --git a/src/lib/corelib/tools/cleanoptions.cpp b/src/lib/corelib/tools/cleanoptions.cpp new file mode 100644 index 000000000..359fd47dc --- /dev/null +++ b/src/lib/corelib/tools/cleanoptions.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "cleanoptions.h" + +#include <QSharedData> + +namespace qbs { +namespace Internal { + +class CleanOptionsPrivate : public QSharedData +{ +public: + CleanOptionsPrivate() + : cleanType(CleanOptions::CleanupAll), dryRun(false), + keepGoing(false), logElapsedTime(false) + { } + + CleanOptions::CleanType cleanType; + bool dryRun; + bool keepGoing; + bool logElapsedTime; +}; + +} + +/*! + * \class CleanOptions + * \brief The \c CleanOptions class comprises parameters that influence the behavior of + * cleaning operations. + */ + +/*! + * \enum CleanOptions::CleanType + * This enum type specifies which kind of build artifacts to remove. + * \value CleanupAll Indicates that all files created by the build process should be removed. + * \value CleanupTemporaries Indicates that only intermediate build artifacts should be removed. + * If, for example, the product to clean up for is a Linux shared library, the .so file + * would be left on the disk, but the .o files would be removed. + */ + +CleanOptions::CleanOptions() : d(new Internal::CleanOptionsPrivate) +{ +} + +CleanOptions::CleanOptions(const CleanOptions &other) : d(other.d) +{ +} + +CleanOptions &CleanOptions::operator=(const CleanOptions &other) +{ + d = other.d; + return *this; +} + +CleanOptions::~CleanOptions() +{ +} + +/*! + * \brief Returns information about which type of artifacts will be removed. + */ +CleanOptions::CleanType CleanOptions::cleanType() const +{ + return d->cleanType; +} + +/*! + * \brief Controls which kind of artifacts to remove. + * \sa CleanOptions::CleanType + */ +void CleanOptions::setCleanType(CleanOptions::CleanType cleanType) +{ + d->cleanType = cleanType; +} + +/*! + * \brief Returns true iff qbs will not actually remove any files, but just show what would happen. + * The default is false. + */ +bool CleanOptions::dryRun() const +{ + return d->dryRun; +} + +/*! + * \brief Controls whether clean-up will actually take place. + * If the argument is true, then qbs will emit information about which files would be removed + * instead of actually doing it. + */ +void CleanOptions::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} + +/*! + * Returns true iff clean-up will continue if an error occurs. + * The default is false. + */ +bool CleanOptions::keepGoing() const +{ + return d->keepGoing; +} + +/*! + * \brief Controls whether to abort on errors. + * If the argument is true, then if a file cannot be removed e.g. due to a permission problem, + * a warning will be printed and the clean-up will continue. If the argument is false, + * then the clean-up will abort immediately in case of an error. + */ +void CleanOptions::setKeepGoing(bool keepGoing) +{ + d->keepGoing = keepGoing; +} + +/*! + * \brief Returns true iff the time the operation takes will be logged. + * The default is false. + */ +bool CleanOptions::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * \brief Controls whether the clean-up time will be measured and logged. + */ +void CleanOptions::setLogElapsedTime(bool log) +{ + d->logElapsedTime = log; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/cleanoptions.h b/src/lib/corelib/tools/cleanoptions.h new file mode 100644 index 000000000..0e3a0a564 --- /dev/null +++ b/src/lib/corelib/tools/cleanoptions.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_CLEANOPTIONS_H +#define QBS_CLEANOPTIONS_H + +#include "qbs_export.h" + +#include <QSharedDataPointer> +#include <QString> + +namespace qbs { +namespace Internal { class CleanOptionsPrivate; } + +class QBS_EXPORT CleanOptions +{ +public: + CleanOptions(); + CleanOptions(const CleanOptions &other); + CleanOptions &operator=(const CleanOptions &other); + ~CleanOptions(); + + enum CleanType { CleanupAll, CleanupTemporaries }; + CleanType cleanType() const; + void setCleanType(CleanType cleanType); + + bool dryRun() const; + void setDryRun(bool dryRun); + + bool keepGoing() const; + void setKeepGoing(bool keepGoing); + + bool logElapsedTime() const; + void setLogElapsedTime(bool log); + +private: + QSharedDataPointer<Internal::CleanOptionsPrivate> d; +}; + +} // namespace qbs + +#endif // Include guard diff --git a/src/lib/corelib/tools/codelocation.cpp b/src/lib/corelib/tools/codelocation.cpp new file mode 100644 index 000000000..70a1814cd --- /dev/null +++ b/src/lib/corelib/tools/codelocation.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "codelocation.h" + +#include <QDataStream> +#include <QDir> +#include <QRegExp> +#include <QSharedData> +#include <QString> + +namespace qbs { + +class CodeLocation::CodeLocationPrivate : public QSharedData +{ +public: + QString fileName; + int line; + int column; +}; + +CodeLocation::CodeLocation() : d(new CodeLocationPrivate) +{ + d->line = d->column = -1; +} + +CodeLocation::CodeLocation(const QString &aFileName, int aLine, int aColumn) + : d(new CodeLocationPrivate) +{ + d->fileName = aFileName; + d->line = aLine; + d->column = aColumn; +} + +CodeLocation::CodeLocation(const CodeLocation &other) : d(other.d) +{ +} + +CodeLocation &CodeLocation::operator=(const CodeLocation &other) +{ + d = other.d; + return *this; +} + +CodeLocation::~CodeLocation() +{ +} + +QString CodeLocation::fileName() const +{ + return d->fileName; +} + +int CodeLocation::line() const +{ + return d->line; +} + +int CodeLocation::column() const +{ + return d->column; +} + +bool CodeLocation::isValid() const +{ + return !fileName().isEmpty(); +} + +QString CodeLocation::toString() const +{ + QString str; + if (isValid()) { + str = QDir::toNativeSeparators(fileName()); + QString lineAndColumn; + if (line() > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+$")))) + lineAndColumn += QLatin1Char(':') + QString::number(line()); + if (column() > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+:[0-9]+$")))) + lineAndColumn += QLatin1Char(':') + QString::number(column()); + str += lineAndColumn; + } + return str; +} + +bool operator==(const CodeLocation &cl1, const CodeLocation &cl2) +{ + return cl1.fileName() == cl2.fileName() && cl1.line() == cl2.line() + && cl1.column() == cl2.column(); +} + +bool operator!=(const CodeLocation &cl1, const CodeLocation &cl2) +{ + return !(cl1 == cl2); +} + +QDataStream &operator<<(QDataStream &s, const CodeLocation &o) +{ + s << o.fileName(); + s << o.line(); + s << o.column(); + return s; +} + +QDataStream &operator>>(QDataStream &s, CodeLocation &o) +{ + QString fileName; + int line; + int column; + s >> fileName; + s >> line; + s >> column; + o = CodeLocation(fileName, line, column); + return s; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/codelocation.h b/src/lib/corelib/tools/codelocation.h new file mode 100644 index 000000000..204192b5a --- /dev/null +++ b/src/lib/corelib/tools/codelocation.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_SOURCELOCATION_H +#define QBS_SOURCELOCATION_H + +#include "qbs_export.h" + +#include <QExplicitlySharedDataPointer> + +QT_BEGIN_NAMESPACE +class QDataStream; +class QString; +QT_END_NAMESPACE + +namespace qbs { + +class QBS_EXPORT CodeLocation +{ +public: + CodeLocation(); + CodeLocation(const QString &aFileName, int aLine = -1, int aColumn = -1); + CodeLocation(const CodeLocation &other); + CodeLocation &operator=(const CodeLocation &other); + ~CodeLocation(); + + QString fileName() const; + int line() const; + int column() const; + + bool isValid() const; + QString toString() const; +private: + class CodeLocationPrivate; + QExplicitlySharedDataPointer<CodeLocationPrivate> d; +}; + +QBS_EXPORT bool operator==(const CodeLocation &cl1, const CodeLocation &cl2); +QBS_EXPORT bool operator!=(const CodeLocation &cl1, const CodeLocation &cl2); + +QDataStream &operator<<(QDataStream &s, const CodeLocation &o); +QDataStream &operator>>(QDataStream &s, CodeLocation &o); + +} // namespace qbs + +#endif // QBS_SOURCELOCATION_H diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp new file mode 100644 index 000000000..4bcdc620c --- /dev/null +++ b/src/lib/corelib/tools/error.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "error.h" + +#include <QSharedData> +#include <QStringList> + +namespace qbs { + +class ErrorItem::ErrorItemPrivate : public QSharedData +{ +public: + QString description; + CodeLocation codeLocation; +}; + +/*! + * \class ErrorData + * \brief The \c ErrorData class describes (part of) an error resulting from a qbs operation. + * It is always delivered as part of an \c Error. + * \sa Error + */ + +ErrorItem::ErrorItem() : d(new ErrorItemPrivate) +{ +} + +ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocation) + : d(new ErrorItemPrivate) +{ + d->description = description; + d->codeLocation = codeLocation; +} + +ErrorItem::ErrorItem(const ErrorItem &rhs) : d(rhs.d) +{ +} + +ErrorItem &ErrorItem::operator=(const ErrorItem &other) +{ + d = other.d; + return *this; +} + +ErrorItem::~ErrorItem() +{ +} + +QString ErrorItem::description() const +{ + return d->description; +} + +CodeLocation ErrorItem::codeLocation() const +{ + return d->codeLocation; +} + +/*! + * \fn const QString &ErrorData::description() const + * \brief A general description of the error. + */ + + /*! + * \fn const QString &ErrorData::codeLocation() const + * \brief The location at which file in which the error occurred. + * \note This information might not be applicable, in which case location().isValid() returns false + */ + +/*! + * \brief A full textual description of the error using all available information. + */ +QString ErrorItem::toString() const +{ + QString str = codeLocation().toString(); + if (!str.isEmpty()) + str += QLatin1Char(' '); + return str += description(); +} + + +class ErrorInfo::ErrorInfoPrivate : public QSharedData +{ +public: + ErrorInfoPrivate() : internalError(false) { } + + QList<ErrorItem> items; + bool internalError; +}; + +/*! + * \class Error + * \brief Represents an error resulting from a qbs operation. + * It is made up of one or more \c ErrorData objects. + * \sa ErrorData + */ + +ErrorInfo::ErrorInfo() : d(new ErrorInfoPrivate) +{ +} + +ErrorInfo::ErrorInfo(const ErrorInfo &rhs) : d(rhs.d) +{ +} + +ErrorInfo::ErrorInfo(const QString &description, const CodeLocation &location, bool internalError) + : d(new ErrorInfoPrivate) +{ + append(description, location); + d->internalError = internalError; +} + +ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) +{ + d = other.d; + return *this; +} + +ErrorInfo::~ErrorInfo() +{ +} + +void ErrorInfo::append(const QString &description, const CodeLocation &location) +{ + d->items.append(ErrorItem(description, location)); +} + +void ErrorInfo::prepend(const QString &description, const CodeLocation &location) +{ + d->items.prepend(ErrorItem(description, location)); +} + +/*! + * \brief A list of concrete error description. + * Most often, there will be one element in this list, but there can be more e.g. to illustrate + * how an error condition propagates through several source files. + */ +QList<ErrorItem> ErrorInfo::items() const +{ + return d->items; +} + +void ErrorInfo::clear() +{ + d->items.clear(); +} + +/*! + * \brief A complete textual description of the error. + * All "sub-errors" will be represented. + * \sa Error::entries() + */ +QString ErrorInfo::toString() const +{ + QStringList lines; + foreach (const ErrorItem &e, d->items) + lines.append(e.toString()); + return lines.join(QLatin1String("\n")); +} + +/*! + * \brief Returns true if this error represents a bug in qbs, false otherwise. + */ +bool ErrorInfo::isInternalError() const +{ + return d->internalError; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h new file mode 100644 index 000000000..3aae9e239 --- /dev/null +++ b/src/lib/corelib/tools/error.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_ERROR +#define QBS_ERROR + +#include "codelocation.h" + +#include <QExplicitlySharedDataPointer> +#include <QList> +#include <QMetaType> +#include <QSharedDataPointer> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +namespace qbs { +class CodeLocation; + +class QBS_EXPORT ErrorItem +{ + friend class ErrorInfo; +public: + ErrorItem(); + ErrorItem(const ErrorItem &rhs); + ErrorItem &operator=(const ErrorItem &other); + ~ErrorItem(); + + QString description() const; + CodeLocation codeLocation() const; + QString toString() const; + +private: + ErrorItem(const QString &description, const CodeLocation &codeLocation); + + class ErrorItemPrivate; + QExplicitlySharedDataPointer<ErrorItemPrivate> d; +}; + +class QBS_EXPORT ErrorInfo +{ +public: + ErrorInfo(); + ErrorInfo(const ErrorInfo &rhs); + ErrorInfo(const QString &description, const CodeLocation &location = CodeLocation(), + bool internalError = false); + ErrorInfo &operator=(const ErrorInfo &other); + ~ErrorInfo(); + + void append(const QString &description, const CodeLocation &location = CodeLocation()); + void prepend(const QString &description, const CodeLocation &location = CodeLocation()); + QList<ErrorItem> items() const; + bool hasError() const { return !items().isEmpty(); } + void clear(); + QString toString() const; + bool isInternalError() const; + +private: + class ErrorInfoPrivate; + QSharedDataPointer<ErrorInfoPrivate> d; +}; + +} // namespace qbs + +Q_DECLARE_METATYPE(qbs::ErrorInfo) + +#endif // QBS_ERROR diff --git a/src/lib/corelib/tools/fileinfo.cpp b/src/lib/corelib/tools/fileinfo.cpp new file mode 100644 index 000000000..9eca8c2ca --- /dev/null +++ b/src/lib/corelib/tools/fileinfo.cpp @@ -0,0 +1,477 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "fileinfo.h" + +#include <logging/translator.h> +#include <tools/hostosinfo.h> +#include <tools/qbsassert.h> + +#include <QCoreApplication> +#include <QDateTime> +#include <QDir> +#include <QFileInfo> + +#if defined(Q_OS_UNIX) +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> +#elif defined(Q_OS_WIN) +#include <qt_windows.h> +#endif + +namespace qbs { +namespace Internal { + +QString FileInfo::fileName(const QString &fp) +{ + int last = fp.lastIndexOf(QLatin1Char('/')); + if (last < 0) + return fp; + return fp.mid(last + 1); +} + +QString FileInfo::baseName(const QString &fp) +{ + QString fn = fileName(fp); + int dot = fn.indexOf(QLatin1Char('.')); + if (dot < 0) + return fp; + return fn.mid(0, dot); +} + +QString FileInfo::completeBaseName(const QString &fp) +{ + QString fn = fileName(fp); + int dot = fn.lastIndexOf(QLatin1Char('.')); + if (dot < 0) + return fp; + return fn.mid(0, dot); +} + +QString FileInfo::path(const QString &fp) +{ + if (fp.isEmpty()) + return QString(); + if (fp.at(fp.size() - 1) == QLatin1Char('/')) + return fp; + int last = fp.lastIndexOf(QLatin1Char('/')); + if (last < 0) + return QLatin1String("."); + return QDir::cleanPath(fp.mid(0, last)); +} + +void FileInfo::splitIntoDirectoryAndFileName(const QString &filePath, QString *dirPath, QString *fileName) +{ + int idx = filePath.lastIndexOf(QLatin1Char('/')); + if (idx < 0) { + dirPath->clear(); + *fileName = filePath; + return; + } + *dirPath = filePath.left(idx); + *fileName = filePath.mid(idx + 1); +} + +void FileInfo::splitIntoDirectoryAndFileName(const QString &filePath, QStringRef *dirPath, QStringRef *fileName) +{ + int idx = filePath.lastIndexOf(QLatin1Char('/')); + if (idx < 0) { + dirPath->clear(); + *fileName = QStringRef(&filePath); + return; + } + *dirPath = filePath.leftRef(idx); + *fileName = filePath.midRef(idx + 1); +} + +bool FileInfo::exists(const QString &fp) +{ + return FileInfo(fp).exists(); +} + +// from creator/src/shared/proparser/ioutils.cpp +bool FileInfo::isAbsolute(const QString &path) +{ + const int n = path.size(); + if (n == 0) + return false; + const QChar at0 = path.at(0); + if (at0 == QLatin1Char('/')) + return true; + if (HostOsInfo::isWindowsHost()) { + if (at0 == QLatin1Char('\\')) + return true; + // Unlike QFileInfo, this won't accept a relative path with a drive letter. + // Such paths result in a royal mess anyway ... + if (n >= 3 && path.at(1) == QLatin1Char(':') && at0.isLetter() + && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) + return true; + } + return false; +} + +bool FileInfo::isPattern(const QString &str) +{ + return isPattern(QStringRef(&str)); +} + +bool FileInfo::isPattern(const QStringRef &str) +{ + for (int i = 0; i < str.size(); ++i) { + const QChar ch = str.at(i); + if (ch == QLatin1Char('*') || ch == QLatin1Char('?') + || ch == QLatin1Char(']') || ch == QLatin1Char('[')) { + return true; + } + } + return false; +} + +/** + * Concatenates the paths \a base and \a rel. + * Base must be an absolute path. + * Double dots at the start of \a rel are handled. + * This function assumes that both paths are clean, that is they don't contain + * double slashes or redundant dot parts. + */ +QString FileInfo::resolvePath(const QString &base, const QString &rel) +{ + QBS_ASSERT(isAbsolute(base), return QString()); + if (isAbsolute(rel)) + return rel; + if (rel.size() == 1 && rel.at(0) == QLatin1Char('.')) + return base; + if (rel.size() == 1 && rel.at(0) == QLatin1Char('~')) + return QDir::homePath(); + if (rel.startsWith(QLatin1String("~/"))) + return QDir::homePath() + rel.mid(1); + + QString r = base; + if (r.endsWith(QLatin1Char('/'))) + r.chop(1); + + QString s = rel; + while (s.startsWith(QLatin1String("../"))) { + s.remove(0, 3); + int idx = r.lastIndexOf(QLatin1Char('/')); + if (idx >= 0) + r.truncate(idx); + } + + r.reserve(r.length() + 1 + s.length()); + r += QLatin1Char('/'); + r += s; + return r; +} + +bool FileInfo::globMatches(const QRegExp ®exp, const QString &fileName) +{ + const QString pattern = regexp.pattern(); + // May be it's simple wildcard, i.e. "*.cpp"? + if (pattern.startsWith(QLatin1Char('*')) && !isPattern(pattern.midRef(1))) { + // Yes, it's rather simple to just check the extension + return fileName.endsWith(pattern.midRef(1)); + } + return regexp.exactMatch(fileName); +} + +bool FileInfo::isFileCaseCorrect(const QString &filePath) +{ +#if defined(Q_OS_WIN) + // QFileInfo::canonicalFilePath() does not return the real case of the file path on Windows. + QFileInfo fi(filePath); + const QString absolute = fi.absoluteFilePath(); + WIN32_FIND_DATA fd; + HANDLE hFindFile = ::FindFirstFile((wchar_t*)absolute.utf16(), &fd); + if (hFindFile == INVALID_HANDLE_VALUE) + return false; + const QString actualFileName = QString::fromWCharArray(fd.cFileName); + FindClose(hFindFile); + return actualFileName == fi.fileName(); +#elif defined(Q_OS_DARWIN) + QFileInfo fi(filePath); + return fi.absoluteFilePath() == fi.canonicalFilePath(); +#else + Q_UNUSED(filePath) + return true; +#endif +} + +#if defined(Q_OS_WIN) + +#define z(x) reinterpret_cast<WIN32_FILE_ATTRIBUTE_DATA*>(const_cast<FileInfo::InternalStatType*>(&x)) + +template<bool> struct CompileTimeAssert; +template<> struct CompileTimeAssert<true> {}; + +FileInfo::FileInfo(const QString &fileName) +{ + static CompileTimeAssert< + sizeof(FileInfo::InternalStatType) == sizeof(WIN32_FILE_ATTRIBUTE_DATA) + > internal_type_has_wrong_size; + Q_UNUSED(internal_type_has_wrong_size); + if (!GetFileAttributesEx(reinterpret_cast<const WCHAR*>(fileName.utf16()), + GetFileExInfoStandard, &m_stat)) + { + ZeroMemory(z(m_stat), sizeof(WIN32_FILE_ATTRIBUTE_DATA)); + z(m_stat)->dwFileAttributes = INVALID_FILE_ATTRIBUTES; + } +} + +bool FileInfo::exists() const +{ + return z(m_stat)->dwFileAttributes != INVALID_FILE_ATTRIBUTES; +} + +FileTime FileInfo::lastModified() const +{ + const FileTime::InternalType* ft_it; + ft_it = reinterpret_cast<const FileTime::InternalType*>(&z(m_stat)->ftLastWriteTime); + return FileTime(*ft_it); +} + +FileTime FileInfo::lastStatusChange() const +{ + return lastModified(); +} + +bool FileInfo::isDir() const +{ + return z(m_stat)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; +} + +static QString resolveSymlinks(const QString &fileName) +{ + QFileInfo fi(fileName); + while (fi.isSymLink()) + fi.setFile(fi.symLinkTarget()); + return fi.absoluteFilePath(); +} + +QString applicationDirPath() +{ + static const QString appDirPath = FileInfo::path(resolveSymlinks(QCoreApplication::applicationFilePath())); + return appDirPath; +} + +#elif defined(Q_OS_UNIX) + +FileInfo::FileInfo(const QString &fileName) +{ + if (stat(fileName.toLocal8Bit(), &m_stat) == -1) + m_stat.st_mtime = 0; +} + +bool FileInfo::exists() const +{ + return m_stat.st_mtime != 0; +} + +FileTime FileInfo::lastModified() const +{ + return m_stat.st_mtime; +} + +FileTime FileInfo::lastStatusChange() const +{ + return m_stat.st_ctime; +} + +bool FileInfo::isDir() const +{ + return S_ISDIR(m_stat.st_mode); +} + +#endif + +// adapted from qtc/plugins/vcsbase/cleandialog.cpp +bool removeFileRecursion(const QFileInfo &f, QString *errorMessage) +{ + if (!f.exists()) + return true; + if (f.isDir()) { + const QDir dir(f.absoluteFilePath()); + foreach(const QFileInfo &fi, dir.entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Hidden)) + removeFileRecursion(fi, errorMessage); + QDir parent = f.absoluteDir(); + if (!parent.rmdir(f.fileName())) { + errorMessage->append(Tr::tr("The directory %1 could not be deleted."). + arg(QDir::toNativeSeparators(f.absoluteFilePath()))); + return false; + } + } else { + QFile file(f.absoluteFilePath()); + file.setPermissions(f.permissions() | QFile::WriteUser); + if (!file.remove()) { + if (!errorMessage->isEmpty()) + errorMessage->append(QLatin1Char('\n')); + errorMessage->append(Tr::tr("The file %1 could not be deleted."). + arg(QDir::toNativeSeparators(f.absoluteFilePath()))); + return false; + } + } + return true; +} + +bool removeDirectoryWithContents(const QString &path, QString *errorMessage) +{ + QFileInfo f(path); + if (f.exists() && !f.isDir()) { + *errorMessage = Tr::tr("%1 is not a directory.").arg(QDir::toNativeSeparators(path)); + return false; + } + return removeFileRecursion(f, errorMessage); +} + +/*! + * Returns the stored link target of the symbolic link \a{filePath}. + * Unlike QFileInfo::symLinkTarget, this will not make the link target an absolute path. + */ +static QByteArray storedLinkTarget(const QString &filePath) +{ + QByteArray result; + +#ifdef Q_OS_UNIX + const QByteArray nativeFilePath = QFile::encodeName(filePath); + ssize_t len; + while (true) { + struct stat sb; + if (lstat(nativeFilePath.constData(), &sb)) { + qWarning("storedLinkTarget: lstat for %s failed with error code %d", + nativeFilePath.constData(), errno); + return QByteArray(); + } + + result.resize(sb.st_size); + len = readlink(nativeFilePath.constData(), result.data(), sb.st_size + 1); + if (len < 0) { + qWarning("storedLinkTarget: readlink for %s failed with error code %d", + nativeFilePath.constData(), errno); + return QByteArray(); + } + + if (len < sb.st_size) { + result.resize(len); + break; + } + if (len == sb.st_size) + break; + } +#else + Q_UNUSED(filePath); +#endif // Q_OS_UNIX + + return result; +} + +static bool createSymLink(const QByteArray &path1, const QString &path2) +{ +#ifdef Q_OS_UNIX + const QByteArray newPath = QFile::encodeName(path2); + unlink(newPath.constData()); + return symlink(path1.constData(), newPath.constData()) == 0; +#else + Q_UNUSED(path1); + Q_UNUSED(path2); + return false; +#endif // Q_OS_UNIX +} + +/*! + Copies the directory specified by \a srcFilePath recursively to \a tgtFilePath. + \a tgtFilePath will contain the target directory, which will be created. Example usage: + + \code + QString error; + book ok = Utils::FileUtils::copyRecursively("/foo/bar", "/foo/baz", &error); + if (!ok) + qDebug() << error; + \endcode + + This will copy the contents of /foo/bar into to the baz directory under /foo, + which will be created in the process. + + \return Whether the operation succeeded. + \note Function was adapted from qtc/src/libs/fileutils.cpp +*/ + +bool copyFileRecursion(const QString &srcFilePath, const QString &tgtFilePath, + bool preserveSymLinks, QString *errorMessage) +{ + QFileInfo srcFileInfo(srcFilePath); + QFileInfo tgtFileInfo(tgtFilePath); + const QString targetDirPath = tgtFileInfo.absoluteDir().path(); + if (!QDir::root().mkpath(targetDirPath)) { + *errorMessage = Tr::tr("The directory '%1' could not be created.") + .arg(QDir::toNativeSeparators(targetDirPath)); + return false; + } + if (HostOsInfo::isAnyUnixHost() && preserveSymLinks && srcFileInfo.isSymLink()) { + // For now, disable symlink preserving copying on Windows. + // MS did a good job to prevent people from using symlinks - even if they are supported. + if (!createSymLink(storedLinkTarget(srcFilePath), tgtFilePath)) { + *errorMessage = Tr::tr("The symlink '%1' could not be created.") + .arg(tgtFilePath); + return false; + } + } else if (srcFileInfo.isDir()) { + QDir sourceDir(srcFilePath); + QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot + | QDir::Hidden | QDir::System); + foreach (const QString &fileName, fileNames) { + const QString newSrcFilePath = srcFilePath + QLatin1Char('/') + fileName; + const QString newTgtFilePath = tgtFilePath + QLatin1Char('/') + fileName; + if (!copyFileRecursion(newSrcFilePath, newTgtFilePath, preserveSymLinks, errorMessage)) + return false; + } + } else { + if (tgtFileInfo.exists() && srcFileInfo.lastModified() <= tgtFileInfo.lastModified()) + return true; + QFile file(srcFilePath); + QFile targetFile(tgtFilePath); + if (targetFile.exists()) { + targetFile.setPermissions(targetFile.permissions() | QFile::WriteUser); + if (!targetFile.remove()) { + *errorMessage = Tr::tr("Could not remove file '%1'. %2") + .arg(QDir::toNativeSeparators(tgtFilePath), targetFile.errorString()); + } + } + if (!file.copy(tgtFilePath)) { + *errorMessage = Tr::tr("Could not copy file '%1' to '%2'. %3") + .arg(QDir::toNativeSeparators(srcFilePath), QDir::toNativeSeparators(tgtFilePath), + file.errorString()); + return false; + } + } + return true; +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/fileinfo.h b/src/lib/corelib/tools/fileinfo.h new file mode 100644 index 000000000..b5731cedd --- /dev/null +++ b/src/lib/corelib/tools/fileinfo.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_FILEINFO_H +#define QBS_FILEINFO_H + +#include "filetime.h" +#include "qbs_export.h" + +#if defined(Q_OS_UNIX) +#include <sys/stat.h> +#endif + +#include <QString> + +QT_FORWARD_DECLARE_CLASS(QFileInfo) + +namespace qbs { +namespace Internal { + +class FileInfo +{ +public: + FileInfo(const QString &fileName); + + bool exists() const; + FileTime lastModified() const; + FileTime lastStatusChange() const; + bool isDir() const; + + static QString fileName(const QString &fp); + static QString baseName(const QString &fp); + static QString completeBaseName(const QString &fp); + static QString path(const QString &fp); + static void splitIntoDirectoryAndFileName(const QString &filePath, QString *dirPath, QString *fileName); + static void splitIntoDirectoryAndFileName(const QString &filePath, QStringRef *dirPath, QStringRef *fileName); + static bool exists(const QString &fp); + static bool isAbsolute(const QString &fp); + static bool isPattern(const QStringRef &str); + static bool isPattern(const QString &str); + static QString resolvePath(const QString &base, const QString &rel); + static bool globMatches(const QRegExp &pattern, const QString &subject); + static bool isFileCaseCorrect(const QString &filePath); + +private: +#if defined(Q_OS_WIN) + struct InternalStatType + { + quint8 z[36]; + }; +#elif defined(Q_OS_UNIX) + typedef struct stat InternalStatType; +#else +# error unknown platform +#endif + InternalStatType m_stat; +}; + +bool removeFileRecursion(const QFileInfo &f, QString *errorMessage); + +// FIXME: Used by tests. +bool QBS_EXPORT removeDirectoryWithContents(const QString &path, QString *errorMessage); +bool QBS_EXPORT copyFileRecursion(const QString &sourcePath, const QString &targetPath, + bool preserveSymLinks, QString *errorMessage); + +} // namespace Internal +} // namespace qbs + +#endif diff --git a/src/lib/corelib/tools/filetime.h b/src/lib/corelib/tools/filetime.h new file mode 100644 index 000000000..0dc0524df --- /dev/null +++ b/src/lib/corelib/tools/filetime.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_FILETIME_H +#define QBS_FILETIME_H + +#include <QDataStream> +#include <QDebug> + +#if defined(Q_OS_UNIX) +#include <time.h> +#endif + +namespace qbs { +namespace Internal { + +class FileTime +{ +public: +#if defined(Q_OS_UNIX) + typedef time_t InternalType; +#elif defined(Q_OS_WIN) + typedef quint64 InternalType; +#else +# error unknown platform +#endif + + FileTime(); + FileTime(const InternalType &ft) + : m_fileTime(ft) + { } + + bool operator < (const FileTime &rhs) const; + bool operator > (const FileTime &rhs) const; + bool operator <= (const FileTime &rhs) const; + bool operator >= (const FileTime &rhs) const; + bool operator == (const FileTime &rhs) const; + bool operator != (const FileTime &rhs) const; + + void clear(); + bool isValid() const; + QString toString() const; + + static FileTime currentTime(); + + friend class FileInfo; + InternalType m_fileTime; +}; + +inline bool FileTime::operator > (const FileTime &rhs) const +{ + return rhs < *this; +} + +inline bool FileTime::operator <= (const FileTime &rhs) const +{ + return operator < (rhs) || operator == (rhs); +} + +inline bool FileTime::operator >= (const FileTime &rhs) const +{ + return operator > (rhs) || operator == (rhs); +} + +inline bool FileTime::operator == (const FileTime &rhs) const +{ + return m_fileTime == rhs.m_fileTime; +} + +inline bool FileTime::operator != (const FileTime &rhs) const +{ + return !operator==(rhs); +} + +} // namespace Internal +} // namespace qbs + +QT_BEGIN_NAMESPACE + +inline QDataStream& operator>>(QDataStream &stream, qbs::Internal::FileTime &ft) +{ + quint64 u; + stream >> u; + ft.m_fileTime = u; + return stream; +} + +inline QDataStream& operator<<(QDataStream &stream, const qbs::Internal::FileTime &ft) +{ + stream << (quint64)ft.m_fileTime; + return stream; +} + +inline QDebug operator<<(QDebug dbg, const qbs::Internal::FileTime &t) +{ + dbg.nospace() << t.toString(); + return dbg.space(); +} + +QT_END_NAMESPACE + +#endif // QBS_FILETIME_H diff --git a/src/lib/corelib/tools/filetime_unix.cpp b/src/lib/corelib/tools/filetime_unix.cpp new file mode 100644 index 000000000..945be8f44 --- /dev/null +++ b/src/lib/corelib/tools/filetime_unix.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "filetime.h" + +#include <QDateTime> +#include <QString> + +#include <time.h> + +namespace qbs { +namespace Internal { + +FileTime::FileTime() + : m_fileTime(0) +{ +} + +bool FileTime::operator < (const FileTime &rhs) const +{ + return m_fileTime < rhs.m_fileTime; +} + +void FileTime::clear() +{ + m_fileTime = 0; +} + +bool FileTime::isValid() const +{ + return m_fileTime != 0; +} + +FileTime FileTime::currentTime() +{ + return time(0); +} + +QString FileTime::toString() const +{ + QDateTime dt; + dt.setTime_t(m_fileTime); + return dt.toString(); +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/filetime_win.cpp b/src/lib/corelib/tools/filetime_win.cpp new file mode 100644 index 000000000..b3a7fab67 --- /dev/null +++ b/src/lib/corelib/tools/filetime_win.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "filetime.h" + +#include <QString> +#include <qt_windows.h> +#ifdef Q_CC_MSVC +#include <strsafe.h> +#endif // Q_CC_MSVC + +namespace qbs { +namespace Internal { + +template<bool> struct CompileTimeAssert; +template<> struct CompileTimeAssert<true> {}; + +FileTime::FileTime() + : m_fileTime(0) +{ + static CompileTimeAssert<sizeof(FileTime::InternalType) == sizeof(FILETIME)> internal_type_has_wrong_size; + Q_UNUSED(internal_type_has_wrong_size); +} + +bool FileTime::operator < (const FileTime &rhs) const +{ + const FILETIME *const t1 = reinterpret_cast<const FILETIME *>(&m_fileTime); + const FILETIME *const t2 = reinterpret_cast<const FILETIME *>(&rhs.m_fileTime); + return CompareFileTime(t1, t2) < 0; +} + +void FileTime::clear() +{ + m_fileTime = 0; +} + +bool FileTime::isValid() const +{ + return m_fileTime != 0; +} + +FileTime FileTime::currentTime() +{ + FileTime result; + SYSTEMTIME st; + GetSystemTime(&st); + FILETIME *const ft = reinterpret_cast<FILETIME *>(&result.m_fileTime); + SystemTimeToFileTime(&st, ft); + return result; +} + +QString FileTime::toString() const +{ + const FILETIME *const ft = reinterpret_cast<const FILETIME *>(&m_fileTime); + SYSTEMTIME stUTC, stLocal; + FileTimeToSystemTime(ft, &stUTC); + SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal); +#ifdef Q_CC_MSVC + WCHAR szString[512]; + HRESULT hr = StringCchPrintf(szString, sizeof(szString) / sizeof(WCHAR), + L"%02d.%02d.%d %02d:%02d:%02d:%02d", + stLocal.wDay, stLocal.wMonth, stLocal.wYear, + stLocal.wHour, stLocal.wMinute, stLocal.wSecond, + stLocal.wMilliseconds); + return SUCCEEDED(hr) ? QString::fromWCharArray(szString) : QString(); +#else // Q_CC_MSVC + const QString result = QString("%1.%2.%3 %4:%5:%6") + .arg(stLocal.wDay, 2, 10, QLatin1Char('0')).arg(stLocal.wMonth, 2, 10, QLatin1Char('0')).arg(stLocal.wYear) + .arg(stLocal.wHour, 2, 10, QLatin1Char('0')).arg(stLocal.wMinute, 2, 10, QLatin1Char('0')).arg(stLocal.wSecond, 2, 10, QLatin1Char('0')); + return result; +#endif // Q_CC_MSVC +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/hostosinfo.h b/src/lib/corelib/tools/hostosinfo.h new file mode 100644 index 000000000..0bf05cbfd --- /dev/null +++ b/src/lib/corelib/tools/hostosinfo.h @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_HOSTOSINFO_H +#define QBS_HOSTOSINFO_H + +#include "qbs_export.h" + +#include <QtGlobal> +#include <QMap> +#include <QString> +#include <QStringList> + +#if defined(Q_OS_WIN) +#define QTC_HOST_EXE_SUFFIX ".exe" +#define QTC_HOST_DYNAMICLIB_PREFIX "" +#define QTC_HOST_DYNAMICLIB_SUFFIX ".dll" +#define QTC_HOST_OBJECT_SUFFIX ".obj" +#elif defined(Q_OS_DARWIN) +#define QTC_HOST_EXE_SUFFIX "" +#define QTC_HOST_DYNAMICLIB_PREFIX "lib" +#define QTC_HOST_DYNAMICLIB_SUFFIX ".dylib" +#define QTC_HOST_OBJECT_SUFFIX ".o" +#else +#define QTC_HOST_EXE_SUFFIX "" +#define QTC_HOST_DYNAMICLIB_PREFIX "lib" +#define QTC_HOST_DYNAMICLIB_SUFFIX ".so" +#define QTC_HOST_OBJECT_SUFFIX ".o" +#endif // Q_OS_WIN + +namespace qbs { +namespace Internal { + +class QBS_EXPORT HostOsInfo // Exported for use by command-line tools. +{ +public: + // Add more as needed. + enum HostOs { HostOsWindows, HostOsLinux, HostOsOsx, HostOsOtherUnix, HostOsOther }; + + static inline HostOs hostOs(); + + static bool isWindowsHost() { return hostOs() == HostOsWindows; } + static bool isLinuxHost() { return hostOs() == HostOsLinux; } + static bool isOsxHost() { return hostOs() == HostOsOsx; } + static inline bool isAnyUnixHost(); + static inline QString canonicalArchitecture(const QString &architecture); + static inline QString defaultEndianness(const QString &architecture); + + static QString appendExecutableSuffix(const QString &executable) + { + QString finalName = executable; + if (isWindowsHost()) + finalName += QLatin1String(QTC_HOST_EXE_SUFFIX); + return finalName; + } + + static QString dynamicLibraryName(const QString &libraryBaseName) + { + return QLatin1String(QTC_HOST_DYNAMICLIB_PREFIX) + libraryBaseName + + QLatin1String(QTC_HOST_DYNAMICLIB_SUFFIX); + } + + static QString objectName(const QString &baseName) + { + return baseName + QLatin1String(QTC_HOST_OBJECT_SUFFIX); + } + + static Qt::CaseSensitivity fileNameCaseSensitivity() + { + return isWindowsHost() ? Qt::CaseInsensitive: Qt::CaseSensitive; + } + + static QChar pathListSeparator() + { + return isWindowsHost() ? QLatin1Char(';') : QLatin1Char(':'); + } + + static Qt::KeyboardModifier controlModifier() + { + return isOsxHost() ? Qt::MetaModifier : Qt::ControlModifier; + } +}; + +HostOsInfo::HostOs HostOsInfo::hostOs() +{ +#if defined(Q_OS_WIN) + return HostOsWindows; +#elif defined(Q_OS_LINUX) + return HostOsLinux; +#elif defined(Q_OS_DARWIN) + return HostOsOsx; +#elif defined(Q_OS_UNIX) + return HostOsOtherUnix; +#else + return HostOsOther; +#endif +} + +bool HostOsInfo::isAnyUnixHost() +{ +#ifdef Q_OS_UNIX + return true; +#else + return false; +#endif +} + +QString HostOsInfo::canonicalArchitecture(const QString &architecture) +{ + QMap<QString, QStringList> archMap; + archMap.insert(QLatin1String("x86"), QStringList() + << QLatin1String("i386") + << QLatin1String("i486") + << QLatin1String("i586") + << QLatin1String("i686") + << QLatin1String("ia32") + << QLatin1String("ia-32") + << QLatin1String("x86_32") + << QLatin1String("x86-32") + << QLatin1String("intel32")); + + archMap.insert(QLatin1String("x86_64"), QStringList() + << QLatin1String("x86-64") + << QLatin1String("x64") + << QLatin1String("amd64") + << QLatin1String("ia32e") + << QLatin1String("em64t") + << QLatin1String("intel64")); + + archMap.insert(QLatin1String("ia64"), QStringList() + << QLatin1String("ia-64") + << QLatin1String("itanium")); + + QMapIterator<QString, QStringList> i(archMap); + while (i.hasNext()) { + i.next(); + if (i.value().contains(architecture.toLower())) + return i.key(); + } + + return architecture; +} + +QString HostOsInfo::defaultEndianness(const QString &architecture) +{ + const QString canonicalArch = canonicalArchitecture(architecture); + + QStringList little = QStringList() + << QLatin1String("x86") + << QLatin1String("x86_64") + << QLatin1String("arm") + << QLatin1String("arm64"); + + if (little.contains(canonicalArch)) + return QLatin1String("little"); + + QStringList big = QStringList() + << QLatin1String("ppc") + << QLatin1String("ppc64"); + + if (big.contains(canonicalArch)) + return QLatin1String("big"); + + return QString(); +} + +} // namespace Internal +} // namespace qbs + +#endif // QBS_HOSTOSINFO_H diff --git a/src/lib/corelib/tools/id.cpp b/src/lib/corelib/tools/id.cpp new file mode 100644 index 000000000..a9dc07cbc --- /dev/null +++ b/src/lib/corelib/tools/id.cpp @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "id.h" +#include "qbsassert.h" + +#include <QByteArray> +#include <QHash> +#include <QVector> + +namespace qbs { +namespace Internal { + +/*! + \class qbs::Internal::Id + + \brief The class Id encapsulates an identifier that is unique + within a specific running process, using the qbs library. + + \c{Id} is used as facility to identify objects of interest + in a more typesafe and faster manner than a plain \c QString or + \c QByteArray would provide. + + An id is internally represented as a 32 bit integer (its \c UID) + and associated with a plain 7-bit-clean ASCII name used + for display and persistency. + + This class is copied from Qt Creator. +*/ + +class StringHolder +{ +public: + StringHolder() + : n(0), str(0) + {} + + StringHolder(const char *s, int length) + : n(length), str(s) + { + if (!n) + length = n = qstrlen(s); + h = 0; + while (length--) { + h = (h << 4) + *s++; + h ^= (h & 0xf0000000) >> 23; + h &= 0x0fffffff; + } + } + int n; + const char *str; + uint h; +}; + +static bool operator==(const StringHolder &sh1, const StringHolder &sh2) +{ + // sh.n is unlikely to discriminate better than the hash. + return sh1.h == sh2.h && sh1.str && sh2.str && strcmp(sh1.str, sh2.str) == 0; +} + + +static uint qHash(const StringHolder &sh) +{ + return sh.h; +} + +struct IdCache : public QHash<StringHolder, int> +{ +#ifndef QBS_ALLOW_STATIC_LEAKS + ~IdCache() + { + for (IdCache::iterator it = begin(); it != end(); ++it) + delete[](const_cast<char *>(it.key().str)); + } +#endif +}; + + +static int firstUnusedId = Id::IdsPerPlugin * Id::ReservedPlugins; + +static QHash<int, StringHolder> stringFromId; +static IdCache idFromString; + +static int theId(const char *str, int n = 0) +{ + QBS_ASSERT(str && *str, return 0); + StringHolder sh(str, n); + int res = idFromString.value(sh, 0); + if (res == 0) { + res = firstUnusedId++; + sh.str = qstrdup(sh.str); + idFromString[sh] = res; + stringFromId[res] = sh; + } + return res; +} + +static int theId(const QByteArray &ba) +{ + return theId(ba.constData(), ba.size()); +} + +/*! + \fn qbs::Internal::Id(int uid) + + \brief Constructs an id given a UID. + + The UID is an integer value that is unique within the running + process. + + It is the callers responsibility to ensure the uniqueness of + the passed integer. The recommended approach is to use + \c{registerId()} with an value taken from the plugin's + private range. + + \sa registerId() + +*/ + +/*! + Constructs an id given its associated name. The internal + representation will be unspecified, but consistent within a + process. + +*/ +Id::Id(const char *name) + : m_id(theId(name, 0)) +{} + +/*! + \overload + +*/ +Id::Id(const QByteArray &name) + : m_id(theId(name)) +{} + +///*! +// \overload +// \deprecated +//*/ +//Id::Id(const QString &name) +// : m_id(theId(name.toUtf8())) +//{} + +/*! + Returns an internal representation of the id. +*/ + +QByteArray Id::name() const +{ + return stringFromId.value(m_id).str; +} + +/*! + Returns a string representation of the id suitable + for UI display. + + This should not be used to create a persistent version + of the Id, use \c{toSetting()} instead. + + \sa fromString(), toSetting() +*/ + +QString Id::toString() const +{ + return QString::fromUtf8(stringFromId.value(m_id).str); +} + +/*! + Creates an id from a string representation. + + This should not be used to handle a persistent version + of the Id, use \c{fromSetting()} instead. + + \deprecated + + \sa toString(), fromSetting() +*/ + +Id Id::fromString(const QString &name) +{ + return Id(theId(name.toUtf8())); +} + +/*! + Creates an id from a string representation. + + This should not be used to handle a persistent version + of the Id, use \c{fromSetting()} instead. + + \deprecated + + \sa toString(), fromSetting() +*/ + +Id Id::fromName(const QByteArray &name) +{ + return Id(theId(name)); +} + +/*! + Returns a persistent value representing the id which is + suitable to be stored in QSettings. + + \sa fromSetting() +*/ + +QVariant Id::toSetting() const +{ + return QVariant(QString::fromUtf8(stringFromId.value(m_id).str)); +} + +/*! + Reconstructs an id from a persistent value. + + \sa toSetting() +*/ + +Id Id::fromSetting(const QVariant &variant) +{ + const QByteArray ba = variant.toString().toUtf8(); + if (ba.isEmpty()) + return Id(); + return Id(theId(ba)); +} + +/*! + Constructs a derived id. + + This can be used to construct groups of ids logically + belonging together. The associated internal name + will be generated by appending \c{suffix}. +*/ + +Id Id::withSuffix(int suffix) const +{ + const QByteArray ba = name() + QByteArray::number(suffix); + return Id(ba.constData()); +} + +/*! + \overload +*/ + +Id Id::withSuffix(const char *suffix) const +{ + const QByteArray ba = name() + suffix; + return Id(ba.constData()); +} + +/*! + Constructs a derived id. + + This can be used to construct groups of ids logically + belonging together. The associated internal name + will be generated by prepending \c{prefix}. +*/ + +Id Id::withPrefix(const char *prefix) const +{ + const QByteArray ba = prefix + name(); + return Id(ba.constData()); +} + + +/*! + Associates a id with its uid and its string + representation. + + The uid should be taken from the plugin's private range. + + \sa fromSetting() +*/ + +void Id::registerId(int uid, const char *name) +{ + StringHolder sh(name, 0); + idFromString[sh] = uid; + stringFromId[uid] = sh; +} + +bool Id::operator==(const char *name) const +{ + const char *string = stringFromId.value(m_id).str; + if (string && name) + return strcmp(string, name) == 0; + else + return false; +} + +bool Id::alphabeticallyBefore(Id other) const +{ + return toString().compare(other.toString(), Qt::CaseInsensitive) < 0; +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/id.h b/src/lib/corelib/tools/id.h new file mode 100644 index 000000000..097a2d89b --- /dev/null +++ b/src/lib/corelib/tools/id.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_TOOLS_ID_H +#define QBS_TOOLS_ID_H + +#include <QMetaType> +#include <QString> +#include <QVariant> + +namespace qbs { +namespace Internal { + +class Id +{ +public: + enum { IdsPerPlugin = 10000, ReservedPlugins = 1000 }; + + Id() : m_id(0) {} + Id(int uid) : m_id(uid) {} + Id(const char *name); +// explicit Id(const QString &name); + explicit Id(const QByteArray &name); + + Id withSuffix(int suffix) const; + Id withSuffix(const char *name) const; + Id withPrefix(const char *name) const; + + QByteArray name() const; + QString toString() const; // Avoid. + QVariant toSetting() const; // Good to use. + bool isValid() const { return m_id; } + bool operator==(Id id) const { return m_id == id.m_id; } + bool operator==(const char *name) const; + bool operator!=(Id id) const { return m_id != id.m_id; } + bool operator!=(const char *name) const { return !operator==(name); } + bool operator<(Id id) const { return m_id < id.m_id; } + bool operator>(Id id) const { return m_id > id.m_id; } + bool alphabeticallyBefore(Id other) const; + int uniqueIdentifier() const { return m_id; } + static Id fromUniqueIdentifier(int uid) { return Id(uid); } + static Id fromString(const QString &str); // FIXME: avoid. + static Id fromName(const QByteArray &ba); // FIXME: avoid. + static Id fromSetting(const QVariant &variant); // Good to use. + static void registerId(int uid, const char *name); + +private: + // Intentionally unimplemented + Id(const QLatin1String &); + int m_id; +}; + +inline uint qHash(const Id &id) { return id.uniqueIdentifier(); } + +} // namespace Internal +} // namespace qbs + +Q_DECLARE_METATYPE(qbs::Internal::Id) +Q_DECLARE_METATYPE(QList<qbs::Internal::Id>) + +#endif // QBS_TOOLS_ID_H diff --git a/src/lib/corelib/tools/installoptions.cpp b/src/lib/corelib/tools/installoptions.cpp new file mode 100644 index 000000000..66e82fd23 --- /dev/null +++ b/src/lib/corelib/tools/installoptions.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "installoptions.h" + +#include <QDir> +#include <QSharedData> + +namespace qbs { +namespace Internal { + +class InstallOptionsPrivate : public QSharedData +{ +public: + InstallOptionsPrivate() + : useSysroot(false), removeExisting(false), dryRun(false), + keepGoing(false), logElapsedTime(false) + {} + + QString installRoot; + bool useSysroot; + bool removeExisting; + bool dryRun; + bool keepGoing; + bool logElapsedTime; +}; + +} // namespace Internal + +/*! + * \class InstallOptions + * \brief The \c InstallOptions class comprises parameters that influence the behavior of + * install operations. + */ + +InstallOptions::InstallOptions() : d(new Internal::InstallOptionsPrivate) +{ +} + +InstallOptions::InstallOptions(const InstallOptions &other) : d(other.d) +{ +} + +InstallOptions &InstallOptions::operator=(const InstallOptions &other) +{ + d = other.d; + return *this; +} + +InstallOptions::~InstallOptions() +{ +} + +/*! + * \brief The default install root, relative to the build directory. + */ +QString InstallOptions::defaultInstallRoot() +{ + return QLatin1String("install-root"); +} + +/*! + * Returns the base directory for the installation. + * The \c qbs.installPrefix path is relative to this root. If the string is empty, either the value of + * qbs.sysroot or "<build dir>/install-root" will be used, depending on what \c installIntoSysroot() + * returns. + * The default is empty. + */ +QString InstallOptions::installRoot() const +{ + return d->installRoot; +} + +/*! + * \brief Sets the base directory for the installation. + * \note The argument must either be an empty string or an absolute path to a directory + * (which might not yet exist, in which case it will be created). + */ +void InstallOptions::setInstallRoot(const QString &installRoot) +{ + d->installRoot = installRoot; + if (!QDir(installRoot).isRoot()) { + while (d->installRoot.endsWith(QLatin1Char('/'))) + d->installRoot.chop(1); + } +} + +/*! + * Returns whether to use the sysroot as the default install root. + * The default is false. + */ +bool InstallOptions::installIntoSysroot() const +{ + return d->useSysroot; +} + +void InstallOptions::setInstallIntoSysroot(bool useSysroot) +{ + d->useSysroot = useSysroot; +} + +/*! + * \brief Returns true iff an existing installation will be removed prior to installing. + * The default is false. + */ +bool InstallOptions::removeExistingInstallation() const +{ + return d->removeExisting; +} + +/*! + * Controls whether to remove an existing installation before installing. + * \note qbs may do some safety checks and refuse to remove certain directories such as + * a user's home directory. You should still be careful with this option, since it + * deletes recursively. + */ +void InstallOptions::setRemoveExistingInstallation(bool removeExisting) +{ + d->removeExisting = removeExisting; +} + +/*! + * \brief Returns true iff qbs will not actually copy any files, but just show what would happen. + * The default is false. + */ +bool InstallOptions::dryRun() const +{ + return d->dryRun; +} + +/*! + * \brief Controls whether installation will actually take place. + * If the argument is true, then qbs will emit information about which files would be copied + * instead of actually doing it. + */ +void InstallOptions::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} + +/*! + * Returns true iff installation will continue if an error occurs. + * The default is false. + */ +bool InstallOptions::keepGoing() const +{ + return d->keepGoing; +} + +/*! + * \brief Controls whether to abort on errors. + * If the argument is true, then if a file cannot be copied e.g. due to a permission problem, + * a warning will be printed and the installation will continue. If the argument is false, + * then the installation will abort immediately in case of an error. + */ +void InstallOptions::setKeepGoing(bool keepGoing) +{ + d->keepGoing = keepGoing; +} + +/*! + * \brief Returns true iff the time the operation takes will be logged. + * The default is false. + */ +bool InstallOptions::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * \brief Controls whether the installation time will be measured and logged. + */ +void InstallOptions::setLogElapsedTime(bool logElapsedTime) +{ + d->logElapsedTime = logElapsedTime; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/installoptions.h b/src/lib/corelib/tools/installoptions.h new file mode 100644 index 000000000..2b6194fb0 --- /dev/null +++ b/src/lib/corelib/tools/installoptions.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_INSTALLOPTIONS_H +#define QBS_INSTALLOPTIONS_H + +#include "qbs_export.h" + +#include <QSharedDataPointer> +#include <QString> + +namespace qbs { +namespace Internal { class InstallOptionsPrivate; } + +class QBS_EXPORT InstallOptions +{ +public: + InstallOptions(); + InstallOptions(const InstallOptions &other); + InstallOptions &operator=(const InstallOptions &other); + ~InstallOptions(); + + static QString defaultInstallRoot(); + QString installRoot() const; + void setInstallRoot(const QString &installRoot); + + bool installIntoSysroot() const; + void setInstallIntoSysroot(bool useSysroot); + + bool removeExistingInstallation() const; + void setRemoveExistingInstallation(bool removeExisting); + + bool dryRun() const; + void setDryRun(bool dryRun); + + bool keepGoing() const; + void setKeepGoing(bool keepGoing); + + bool logElapsedTime() const; + void setLogElapsedTime(bool logElapsedTime); + +private: + QSharedDataPointer<Internal::InstallOptionsPrivate> d; +}; + +} // namespace qbs + +#endif // QBS_INSTALLOPTIONS_H diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp new file mode 100644 index 000000000..aa519cab2 --- /dev/null +++ b/src/lib/corelib/tools/persistence.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "persistence.h" + +#include "fileinfo.h" +#include <logging/translator.h> +#include <tools/error.h> +#include <tools/qbsassert.h> + +#include <QDir> +#include <QScopedPointer> + +namespace qbs { +namespace Internal { + +static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-60"; + +PersistentPool::PersistentPool(const Logger &logger) : m_logger(logger) +{ + m_stream.setVersion(QDataStream::Qt_4_8); +} + +PersistentPool::~PersistentPool() +{ + closeStream(); +} + +void PersistentPool::load(const QString &filePath) +{ + QScopedPointer<QFile> file(new QFile(filePath)); + if (!file->exists()) + throw ErrorInfo(Tr::tr("No build graph exists yet for this configuration.")); + if (!file->open(QFile::ReadOnly)) { + throw ErrorInfo(Tr::tr("Could not open open build graph file '%1': %2") + .arg(filePath, file->errorString())); + } + + m_stream.setDevice(file.data()); + QByteArray magic; + m_stream >> magic; + if (magic != QBS_PERSISTENCE_MAGIC) { + file->close(); + file->remove(); + m_stream.setDevice(0); + throw ErrorInfo(Tr::tr("Cannot use stored build graph at '%1': Incompatible file format. " + "Expected magic token '%2', got '%3'.") + .arg(filePath, QString::fromLatin1(QBS_PERSISTENCE_MAGIC), + QString::fromLatin1(magic))); + } + + m_stream >> m_headData.projectConfig; + file.take(); + m_loadedRaw.clear(); + m_loaded.clear(); + m_storageIndices.clear(); + m_stringStorage.clear(); + m_inverseStringStorage.clear(); +} + +void PersistentPool::setupWriteStream(const QString &filePath) +{ + QString dirPath = FileInfo::path(filePath); + if (!FileInfo::exists(dirPath) && !QDir().mkpath(dirPath)) { + throw ErrorInfo(Tr::tr("Failure storing build graph: Cannot create directory '%1'.") + .arg(dirPath)); + } + + if (QFile::exists(filePath) && !QFile::remove(filePath)) { + throw ErrorInfo(Tr::tr("Failure storing build graph: Cannot remove old file '%1'") + .arg(filePath)); + } + QBS_CHECK(!QFile::exists(filePath)); + QScopedPointer<QFile> file(new QFile(filePath)); + if (!file->open(QFile::WriteOnly)) { + throw ErrorInfo(Tr::tr("Failure storing build graph: " + "Cannot open file '%1' for writing: %2").arg(filePath, file->errorString())); + } + + m_stream.setDevice(file.take()); + m_stream << QByteArray(QBS_PERSISTENCE_MAGIC) << m_headData.projectConfig; + m_lastStoredObjectId = 0; + m_lastStoredStringId = 0; +} + +void PersistentPool::closeStream() +{ + delete m_stream.device(); + m_stream.setDevice(0); +} + +void PersistentPool::store(const PersistentObject *object) +{ + if (!object) { + m_stream << -1; + return; + } + PersistentObjectId id = m_storageIndices.value(object, -1); + if (id < 0) { + id = m_lastStoredObjectId++; + m_storageIndices.insert(object, id); + m_stream << id; + object->store(*this); + } else { + m_stream << id; + } +} + +void PersistentPool::clear() +{ + m_loaded.clear(); + m_storageIndices.clear(); + m_stringStorage.clear(); + m_inverseStringStorage.clear(); +} + +QDataStream &PersistentPool::stream() +{ + return m_stream; +} + +void PersistentPool::storeString(const QString &t) +{ + int id = m_inverseStringStorage.value(t, -1); + if (id < 0) { + id = m_lastStoredStringId++; + m_inverseStringStorage.insert(t, id); + m_stream << id << t; + } else { + m_stream << id; + } +} + +QString PersistentPool::loadString(int id) +{ + QBS_CHECK(id >= 0); + + if (id >= m_stringStorage.count()) { + QString s; + m_stream >> s; + m_stringStorage.resize(id + 1); + m_stringStorage[id] = s; + return s; + } + + return m_stringStorage.at(id); +} + +QString PersistentPool::idLoadString() +{ + int id; + m_stream >> id; + return loadString(id); +} + +void PersistentPool::storeStringSet(const QSet<QString> &t) +{ + m_stream << t.count(); + foreach (const QString &s, t) + storeString(s); +} + +QSet<QString> PersistentPool::idLoadStringSet() +{ + int i; + m_stream >> i; + QSet<QString> result; + for (; --i >= 0;) + result += idLoadString(); + return result; +} + +void PersistentPool::storeStringList(const QStringList &t) +{ + m_stream << t.count(); + foreach (const QString &s, t) + storeString(s); +} + +QStringList PersistentPool::idLoadStringList() +{ + int i; + m_stream >> i; + QStringList result; + for (; --i >= 0;) + result += idLoadString(); + return result; +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/persistence.h b/src/lib/corelib/tools/persistence.h new file mode 100644 index 000000000..1afea6d80 --- /dev/null +++ b/src/lib/corelib/tools/persistence.h @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_PERSISTENCE +#define QBS_PERSISTENCE + +#include "persistentobject.h" +#include <logging/logger.h> + +#include <QDataStream> +#include <QSharedPointer> +#include <QString> +#include <QVariantMap> +#include <QVector> + +namespace qbs { +namespace Internal { + +class PersistentPool +{ +public: + PersistentPool(const Logger &logger); + ~PersistentPool(); + + class HeadData + { + public: + QVariantMap projectConfig; + }; + + void load(const QString &filePath); + void setupWriteStream(const QString &filePath); + void closeStream(); + void clear(); + QDataStream &stream(); + + template <typename T> T *idLoad(); + template <typename T> void loadContainer(T &container); + template <class T> QSharedPointer<T> idLoadS(); + template <typename T> void loadContainerS(T &container); + + void store(const QSharedPointer<const PersistentObject> &ptr) { store(ptr.data()); } + void store(const PersistentObject *object); + template <typename T> void storeContainer(T &container); + + void storeString(const QString &t); + QString loadString(int id); + QString idLoadString(); + + void storeStringSet(const QSet<QString> &t); + QSet<QString> loadStringSet(const QList<int> &id); + QSet<QString> idLoadStringSet(); + + void storeStringList(const QStringList &t); + QStringList loadStringList(const QList<int> &ids); + QStringList idLoadStringList(); + + const HeadData &headData() const { return m_headData; } + void setHeadData(const HeadData &hd) { m_headData = hd; } + +private: + typedef int PersistentObjectId; + + template<typename T> struct RemovePointer { typedef T Type; }; + template<typename T> struct RemovePointer<T*> { typedef T Type; }; + template <class T> struct RemoveConst { typedef T Type; }; + template <class T> struct RemoveConst<const T> { typedef T Type; }; + + template <class T> T *loadRaw(PersistentObjectId id); + template <class T> QSharedPointer<T> load(PersistentObjectId id); + + QDataStream m_stream; + HeadData m_headData; + QVector<PersistentObject *> m_loadedRaw; + QVector<QSharedPointer<PersistentObject> > m_loaded; + QHash<const PersistentObject *, int> m_storageIndices; + PersistentObjectId m_lastStoredObjectId; + + QVector<QString> m_stringStorage; + QHash<QString, int> m_inverseStringStorage; + PersistentObjectId m_lastStoredStringId; + Logger m_logger; +}; + +template <typename T> inline T *PersistentPool::idLoad() +{ + PersistentObjectId id; + stream() >> id; + return loadRaw<T>(id); +} + +template <typename T> inline void PersistentPool::loadContainer(T &container) +{ + int count; + stream() >> count; + container.clear(); + container.reserve(count); + for (int i = count; --i >= 0;) + container += idLoad<typename RemovePointer<typename T::value_type>::Type>(); +} + +template <class T> inline QSharedPointer<T> PersistentPool::idLoadS() +{ + PersistentObjectId id; + m_stream >> id; + return load<T>(id); +} + +template <typename T> inline void PersistentPool::loadContainerS(T &container) +{ + int count; + stream() >> count; + container.clear(); + container.reserve(count); + for (int i = count; --i >= 0;) + container += idLoadS<typename RemoveConst<typename T::value_type::value_type>::Type>(); +} + +template <typename T> inline void PersistentPool::storeContainer(T &container) +{ + stream() << container.count(); + typename T::const_iterator it = container.constBegin(); + const typename T::const_iterator itEnd = container.constEnd(); + for (; it != itEnd; ++it) + store(*it); +} + +template <class T> inline T *PersistentPool::loadRaw(PersistentObjectId id) +{ + if (id < 0) + return 0; + + if (id < m_loadedRaw.count()) { + PersistentObject *obj = m_loadedRaw.value(id); + return dynamic_cast<T*>(obj); + } + + int i = m_loadedRaw.count(); + m_loadedRaw.resize(id + 1); + for (; i < m_loadedRaw.count(); ++i) + m_loadedRaw[i] = 0; + + T * const t = new T; + PersistentObject * const po = t; + m_loadedRaw[id] = po; + po->load(*this); + return t; +} + +template <class T> inline QSharedPointer<T> PersistentPool::load(PersistentObjectId id) +{ + if (id < 0) + return QSharedPointer<T>(); + + if (id < m_loaded.count()) { + QSharedPointer<PersistentObject> obj = m_loaded.value(id); + return obj.dynamicCast<T>(); + } + + m_loaded.resize(id + 1); + const QSharedPointer<T> t = T::create(); + m_loaded[id] = t; + PersistentObject * const po = t.data(); + po->load(*this); + return t; +} + +} // namespace Internal +} // namespace qbs + +#endif diff --git a/src/lib/corelib/tools/persistentobject.h b/src/lib/corelib/tools/persistentobject.h new file mode 100644 index 000000000..0d9b588c0 --- /dev/null +++ b/src/lib/corelib/tools/persistentobject.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_PERSISTENTOBJECT_H +#define QBS_PERSISTENTOBJECT_H + +namespace qbs { +namespace Internal { + +class PersistentPool; + +class PersistentObject +{ +public: + virtual ~PersistentObject() {} + virtual void load(PersistentPool &) = 0; + virtual void store(PersistentPool &) const = 0; +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_PERSISTENTOBJECT_H diff --git a/src/lib/corelib/tools/preferences.cpp b/src/lib/corelib/tools/preferences.cpp new file mode 100644 index 000000000..bdff7c67b --- /dev/null +++ b/src/lib/corelib/tools/preferences.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "preferences.h" + +#include "buildoptions.h" +#include "hostosinfo.h" +#include "profile.h" +#include "settings.h" + +namespace qbs { + +/*! + * \class Preferences + * \brief The \c Preferences class gives access to all general qbs preferences. + * If a non-empty \c profileName is given, the profile's preferences take precedence over global + * ones. Otherwise, the global preferences are used. + */ +Preferences::Preferences(Settings *settings, const QString &profileName) + : m_settings(settings), m_profile(profileName) +{ +} + + +/*! + * \brief Returns true <=> colored output should be used for printing messages. + * This is only relevant for command-line frontends. + */ +bool Preferences::useColoredOutput() const +{ + return getPreference(QLatin1String("useColoredOutput"), true).toBool(); +} + +/*! + * \brief Returns the number of parallel jobs to use for building. + * Uses a sensible default value if there is no such setting. + */ +int Preferences::jobs() const +{ + return getPreference(QLatin1String("jobs"), BuildOptions::defaultMaxJobCount()).toInt(); +} + +/*! + * \brief Returns the shell to use for the "qbs shell" command. + * This is only relevant for command-line frontends. + */ +QString Preferences::shell() const +{ + return getPreference(QLatin1String("shell")).toString(); +} + +/*! + * \brief Returns the default build directory used by Qbs if none is specified. + */ +QString Preferences::defaultBuildDirectory() const +{ + return getPreference(QLatin1String("defaultBuildDirectory")).toString(); +} + +/*! + * \brief Returns the list of paths where qbs looks for module definitions and such. + * If there is no such setting, \c qbsRootPath will be used to look up a fallback location. + */ +QStringList Preferences::searchPaths(const QString &qbsRootPath) const +{ + const QStringList searchPaths = pathList(QLatin1String("qbsSearchPaths"), + qbsRootPath + QLatin1String("/share/qbs")); + + // TODO: Remove in 1.2. + const QStringList deprecatedSearchPaths = getPreference(QLatin1String("qbsPath")).toString() + .split(Internal::HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); + if (!deprecatedSearchPaths.isEmpty()) { + qDebug("Warning: preferences.qbsPath is deprecated, " + "use preferences.qbsSearchPaths instead."); + } + return deprecatedSearchPaths + searchPaths; +} + +/*! + * \brief Returns the list of paths where qbs looks for plugins. + * If there is no such setting, \c qbsRootPath will be used to look up a fallback location. + */ +QStringList Preferences::pluginPaths(const QString &qbsRootPath) const +{ + return pathList(QLatin1String("pluginsPath"), qbsRootPath + QLatin1String("/lib/qbs/plugins")); +} + +QVariant Preferences::getPreference(const QString &key, const QVariant &defaultValue) const +{ + const QString fullKey = QLatin1String("preferences.") + key; + if (!m_profile.isEmpty()) { + const QVariant value = Profile(m_profile, m_settings).value(fullKey); + if (value.isValid()) + return value; + } + + return m_settings->value(fullKey, defaultValue); +} + +QStringList Preferences::pathList(const QString &key, const QString &defaultValue) const +{ + QStringList paths = getPreference(key).toString().split( + Internal::HostOsInfo::pathListSeparator(), QString::SkipEmptyParts); + paths << defaultValue; + return paths; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/preferences.h b/src/lib/corelib/tools/preferences.h new file mode 100644 index 000000000..e5e6c9bb6 --- /dev/null +++ b/src/lib/corelib/tools/preferences.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_PREFERENCES_H +#define QBS_PREFERENCES_H + +#include "qbs_export.h" + +#include <QStringList> +#include <QVariant> + +namespace qbs { +class Settings; + +class QBS_EXPORT Preferences +{ +public: + explicit Preferences(Settings *settings, const QString &profileName = QString()); + + bool useColoredOutput() const; + int jobs() const; + QString shell() const; + QString defaultBuildDirectory() const; + QStringList searchPaths(const QString &qbsRootPath = QString()) const; + QStringList pluginPaths(const QString &qbsRootPath = QString()) const; + +private: + QVariant getPreference(const QString &key, const QVariant &defaultValue = QVariant()) const; + QStringList pathList(const QString &key, const QString &defaultValue) const; + + Settings *m_settings; + QString m_profile; +}; + +} // namespace qbs + + +#endif // Header guard diff --git a/src/lib/corelib/tools/processresult.cpp b/src/lib/corelib/tools/processresult.cpp new file mode 100644 index 000000000..885d7ffee --- /dev/null +++ b/src/lib/corelib/tools/processresult.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "processresult.h" +#include "processresult_p.h" + +/*! + * \class SetupProjectParameters + * \brief The \c ProcessResult class describes a finished qbs process command. + */ + +namespace qbs { + +ProcessResult::ProcessResult() : d(new Internal::ProcessResultPrivate) +{ +} + +ProcessResult::ProcessResult(const ProcessResult &other) : d(other.d) +{ +} + +ProcessResult &ProcessResult::operator=(const ProcessResult &other) +{ + d = other.d; + return *this; +} + +ProcessResult::~ProcessResult() +{ +} + +/*! + * \brief Returns true iff the command finished successfully. + */ +bool ProcessResult::success() const +{ + return d->success; +} + +/*! + * \brief Returns the file path of the executable that was run. + */ +QString ProcessResult::executableFilePath() const +{ + return d->executableFilePath; +} + +/*! + * \brief Returns the command-line arguments with which the command was invoked. + */ +QStringList ProcessResult::arguments() const +{ + return d->arguments; +} + +/*! + * \brief Returns the working directory of the invoked command. + */ +QString ProcessResult::workingDirectory() const +{ + return d->workingDirectory; +} + +/*! + * \brief Returns the exit status of the command. + */ +QProcess::ExitStatus ProcessResult::exitStatus() const +{ + return d->exitStatus; +} + +/*! + * \brief Returns the exit code of the command. + */ +int ProcessResult::exitCode() const +{ + return d->exitCode; +} + +/*! + * \brief Returns the data the command wrote to the standard output channel. + */ +QStringList ProcessResult::stdOut() const +{ + return d->stdOut; +} + +/*! + * \brief Returns the data the command wrote to the standard error channel. + */ +QStringList ProcessResult::stdErr() const +{ + return d->stdErr; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/processresult.h b/src/lib/corelib/tools/processresult.h new file mode 100644 index 000000000..b8de9ddd2 --- /dev/null +++ b/src/lib/corelib/tools/processresult.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_PROCESSRESULT_H +#define QBS_PROCESSRESULT_H + +#include "qbs_export.h" + +#include <QExplicitlySharedDataPointer> +#include <QMetaType> +#include <QProcess> +#include <QString> +#include <QStringList> + +namespace qbs { +namespace Internal { +class ProcessCommandExecutor; +class ProcessResultPrivate; +} + +class QBS_EXPORT ProcessResult +{ + friend class qbs::Internal::ProcessCommandExecutor; +public: + ProcessResult(); + ProcessResult(const ProcessResult &other); + ProcessResult &operator=(const ProcessResult &other); + ~ProcessResult(); + + bool success() const; + QString executableFilePath() const; + QStringList arguments() const; + QString workingDirectory() const; + QProcess::ExitStatus exitStatus() const; + int exitCode() const; + QStringList stdOut() const; + QStringList stdErr() const; + +private: + QExplicitlySharedDataPointer<Internal::ProcessResultPrivate> d; +}; + +} // namespace qbs + +Q_DECLARE_METATYPE(qbs::ProcessResult) + +#endif // QBS_PROCESSRESULT_H diff --git a/src/lib/corelib/tools/processresult_p.h b/src/lib/corelib/tools/processresult_p.h new file mode 100644 index 000000000..db2475b44 --- /dev/null +++ b/src/lib/corelib/tools/processresult_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_PROCESSRESULT_P_H +#define QBS_PROCESSRESULT_P_H + +#include <QSharedData> +#include <QStringList> +#include <QProcess> + +namespace qbs { +namespace Internal { +class ProcessResultPrivate : public QSharedData +{ +public: + bool success; + + QString executableFilePath; + QStringList arguments; + QString workingDirectory; + + QProcess::ExitStatus exitStatus; + int exitCode; + QStringList stdOut; + QStringList stdErr; +}; + +} // namespace Internal +} // namespace qbs + +#endif // Include guard. diff --git a/src/lib/corelib/tools/profile.cpp b/src/lib/corelib/tools/profile.cpp new file mode 100644 index 000000000..cb3186ae4 --- /dev/null +++ b/src/lib/corelib/tools/profile.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "profile.h" +#include "qbsassert.h" +#include "settings.h" + +#include <logging/translator.h> +#include <tools/error.h> + +namespace qbs { + +/*! + * \class Profile + * \brief The \c Profile class gives access to the settings of a given profile. + */ + + /*! + * \enum Profile::KeySelection + * This enum type specifies whether to enumerate keys recursively. + * \value KeySelectionRecursive Indicates that key enumeration should happen recursively, i.e. + * it should go up the base profile chain. + * \value KeySelectionNonRecursive Indicates that only keys directly attached to a profile + * should be listed. + */ + +/*! + * \brief Creates an object giving access to the settings for profile \c name. + */ +Profile::Profile(const QString &name, Settings *settings) : m_name(name), m_settings(settings) +{ + QBS_ASSERT(name == cleanName(name), return); +} + +bool Profile::exists() const +{ + return !m_settings->allKeysWithPrefix(profileKey()).isEmpty(); +} + +/*! + * \brief Returns the value for property \c key in this profile. + */ +QVariant Profile::value(const QString &key, const QVariant &defaultValue) const +{ + return possiblyInheritedValue(key, defaultValue, QStringList()); +} + +/*! + * \brief Gives value \c value to the property \c key in this profile. + */ +void Profile::setValue(const QString &key, const QVariant &value) +{ + m_settings->setValue(fullyQualifiedKey(key), value); + + if (key == baseProfileKey()) { + QBS_ASSERT(value.toString() == cleanName(value.toString()), return); + } +} + +/*! + * \brief Removes a key and the associated value from this profile. + */ +void Profile::remove(const QString &key) +{ + m_settings->remove(fullyQualifiedKey(key)); +} + +/*! + * \brief Returns the name of this profile. + */ +QString Profile::name() const +{ + return m_name; +} + +/*! + * \brief Returns all property keys in this profile. + * If and only if selection is Profile::KeySelectionRecursive, this will also list keys defined + * in base profiles. + */ +QStringList Profile::allKeys(KeySelection selection) const +{ + return allKeysInternal(selection, QStringList()); +} + +/*! + * \brief Returns the name of this profile's base profile. + * The returned value is empty if the profile does not have a base profile. + */ +QString Profile::baseProfile() const +{ + return localValue(baseProfileKey()).toString(); +} + +/*! + * \brief Sets a new base profile for this profile. + */ +void Profile::setBaseProfile(const QString &baseProfile) +{ + setValue(baseProfileKey(), baseProfile); +} + +/*! + * \brief Removes this profile's base profile setting. + */ +void Profile::removeBaseProfile() +{ + remove(baseProfileKey()); +} + +/*! + * \brief Removes this profile from the settings. + */ +void Profile::removeProfile() +{ + m_settings->remove(profileKey()); +} + +/*! + * \brief Returns a string suitiable as a profile name. + * Removes all dots and replaces them with hyphens. + */ +QString Profile::cleanName(const QString &name) +{ + QString newName = name; + return newName.replace(QLatin1Char('.'), QLatin1Char('-')); +} + +QString Profile::profileKey() const +{ + return QLatin1String("profiles.") + m_name; +} + +QString Profile::baseProfileKey() +{ + return QLatin1String("baseProfile"); +} + +void Profile::checkBaseProfileExistence(const Profile &baseProfile) const +{ + if (!baseProfile.exists()) + throw ErrorInfo(Internal::Tr::tr("Profile \"%1\" has a non-existent base profile \"%2\".").arg( + name(), baseProfile.name())); +} + +QVariant Profile::localValue(const QString &key) const +{ + return m_settings->value(fullyQualifiedKey(key)); +} + +QString Profile::fullyQualifiedKey(const QString &key) const +{ + return profileKey() + QLatin1Char('.') + key; +} + +QVariant Profile::possiblyInheritedValue(const QString &key, const QVariant &defaultValue, + QStringList profileChain) const +{ + extendAndCheckProfileChain(profileChain); + const QVariant v = localValue(key); + if (v.isValid()) + return v; + const QString baseProfileName = baseProfile(); + if (baseProfileName.isEmpty()) + return defaultValue; + Profile parentProfile(baseProfileName, m_settings); + checkBaseProfileExistence(parentProfile); + return parentProfile.possiblyInheritedValue(key, defaultValue, profileChain); +} + +QStringList Profile::allKeysInternal(Profile::KeySelection selection, + QStringList profileChain) const +{ + extendAndCheckProfileChain(profileChain); + QStringList keys = m_settings->allKeysWithPrefix(profileKey()); + if (selection == KeySelectionNonRecursive) + return keys; + const QString baseProfileName = baseProfile(); + if (baseProfileName.isEmpty()) + return keys; + Profile parentProfile(baseProfileName, m_settings); + checkBaseProfileExistence(parentProfile); + keys += parentProfile.allKeysInternal(KeySelectionRecursive, profileChain); + keys.removeDuplicates(); + keys.removeOne(baseProfileKey()); + keys.sort(); + return keys; +} + +void Profile::extendAndCheckProfileChain(QStringList &chain) const +{ + chain << m_name; + if (Q_UNLIKELY(chain.count(m_name) > 1)) { + throw ErrorInfo(Internal::Tr::tr("Circular profile inheritance. Cycle is '%1'.") + .arg(chain.join(QLatin1String(" -> ")))); + } +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/profile.h b/src/lib/corelib/tools/profile.h new file mode 100644 index 000000000..c3b0bbfe8 --- /dev/null +++ b/src/lib/corelib/tools/profile.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_PROFILE_H +#define QBS_PROFILE_H + +#include "qbs_export.h" + +#include <QString> +#include <QStringList> +#include <QVariant> + +namespace qbs { +class Settings; + +class QBS_EXPORT Profile +{ +public: + explicit Profile(const QString &name, Settings *settings); + + bool exists() const; + QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; + void setValue(const QString &key, const QVariant &value); + void remove(const QString &key); + + QString name() const; + + QString baseProfile() const; + void setBaseProfile(const QString &baseProfile); + void removeBaseProfile(); + + void removeProfile(); + + enum KeySelection { KeySelectionRecursive, KeySelectionNonRecursive }; + QStringList allKeys(KeySelection selection) const; + + static QString cleanName(const QString &name); + +private: + static QString baseProfileKey(); + void checkBaseProfileExistence(const Profile &baseProfile) const; + QString profileKey() const; + QVariant localValue(const QString &key) const; + QString fullyQualifiedKey(const QString &key) const; + QVariant possiblyInheritedValue(const QString &key, const QVariant &defaultValue, + QStringList profileChain) const; + QStringList allKeysInternal(KeySelection selection, QStringList profileChain) const; + void extendAndCheckProfileChain(QStringList &chain) const; + + QString m_name; + Settings *m_settings; +}; + +} // namespace qbs + +#endif // Header guard diff --git a/src/lib/corelib/tools/progressobserver.cpp b/src/lib/corelib/tools/progressobserver.cpp new file mode 100644 index 000000000..f18aefcfb --- /dev/null +++ b/src/lib/corelib/tools/progressobserver.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "progressobserver.h" + +namespace qbs { +namespace Internal { + +/*! + * \class ProgressObserver + * The \c ProgressObserver class is used in long running qbs operations. It serves two purposes: + * Firstly, it allows operations to indicate progress to a client. Secondly, a client can + * signal to an operation that is should exit prematurely. + * Clients of the qbs library are supposed to subclass this class and implement the virtual + * functions in a way that lets users know about the current operation and its progress. + */ + +/*! + * \fn virtual void initialize(const QString &task, int maximum) = 0 + * \brief Indicates that a new operation is starting. + * Library code calls this function to indicate that it is starting a new task. + * The \a task parameter is a textual description of that task suitable for presentation to a user. + * The \a maximum parameter is an estimate of the maximum effort the operation is going to take. + * This is helpful if the client wants to set up some sort of progress bar showing the + * percentage of the work already done. + */ + +/*! + * \fn virtual void setProgressValue(int value) = 0 + * \brief Sets the new progress value. + * Library code calls this function to indicate that the current operation has progressed. + * It will try hard to ensure that \a value will not exceed \c maximum(). + * \sa ProgressObserver::maximum(). + */ + +/*! + * \fn virtual int progressValue() = 0 + * \brief The current progress value. + * Will typically reflect the \a value from the last call to \c setProgressValue() and should not + * exceed \c maximum(). + * \sa setProgressvalue() + * \sa maximum() + */ + +void ProgressObserver::incrementProgressValue(int increment) +{ + setProgressValue(progressValue() + increment); +} + +/*! + * \fn virtual bool canceled() const = 0 + * \brief Indicates whether the current operation should be canceled. + * Library code will periodically call this function and abort the current operation + * if it returns true. + */ + +/*! + * \fn virtual int maximum() const = 0 + * \brief The expected maximum progress value. + * This will typically be the value of \c maximum passed to \c initialize(). + * \sa ProgressObserver::initialize() + */ + +void ProgressObserver::setFinished() +{ + setProgressValue(maximum()); +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/progressobserver.h b/src/lib/corelib/tools/progressobserver.h new file mode 100644 index 000000000..66d552a02 --- /dev/null +++ b/src/lib/corelib/tools/progressobserver.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_PROGRESSOBSERVER_H +#define QBS_PROGRESSOBSERVER_H + +#include <QtGlobal> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +namespace qbs { +namespace Internal { + +class ProgressObserver +{ +public: + virtual ~ProgressObserver() { } + + virtual void initialize(const QString &task, int maximum) = 0; + virtual void setProgressValue(int value) = 0; + virtual int progressValue() = 0; + virtual bool canceled() const = 0; + virtual void setMaximum(int maximum) = 0; + virtual int maximum() const = 0; + + void incrementProgressValue(int increment = 1); + + // Call this to ensure that the progress bar always goes to 100%. + void setFinished(); +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_PROGRESSOBSERVER_H diff --git a/src/lib/corelib/tools/propertyfinder.cpp b/src/lib/corelib/tools/propertyfinder.cpp new file mode 100644 index 000000000..96c081f01 --- /dev/null +++ b/src/lib/corelib/tools/propertyfinder.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "propertyfinder.h" + +#include "qbsassert.h" + +namespace qbs { +namespace Internal { + +QVariantList PropertyFinder::propertyValues(const QVariantMap &properties, + const QString &moduleName, const QString &key, MergeType mergeType) +{ + m_moduleName = moduleName; + m_key = key; + m_values.clear(); + findModuleValues(properties, true); + if (mergeType == DoMergeLists) + mergeLists(&m_values); + return m_values; +} + +QVariant PropertyFinder::propertyValue(const QVariantMap &properties, const QString &moduleName, + const QString &key) +{ + m_moduleName = moduleName; + m_key = key; + m_values.clear(); + findModuleValues(properties, false); + + QBS_ASSERT(m_values.count() <= 1, return QVariant()); + return m_values.isEmpty() ? QVariant() : m_values.first(); +} + +void PropertyFinder::findModuleValues(const QVariantMap &properties, bool searchRecursively) +{ + QVariantMap moduleProperties = properties.value(QLatin1String("modules")).toMap(); + + // Direct hits come first. + const QVariantMap::Iterator modIt = moduleProperties.find(m_moduleName); + if (modIt != moduleProperties.end()) { + const QVariantMap moduleMap = modIt->toMap(); + const QVariant property = moduleMap.value(m_key); + addToList(property); + moduleProperties.erase(modIt); + } + + if (!searchRecursively) + return; + + // These are the non-matching modules. + for (QVariantMap::ConstIterator it = moduleProperties.constBegin(); + it != moduleProperties.constEnd(); ++it) { + findModuleValues(it->toMap(), true); + } +} + +void PropertyFinder::addToList(const QVariant &value) +{ + // Note: This means that manually setting a property to "null" will not lead to a "hit". + if (!value.isNull() && !m_values.contains(value)) + m_values << value; +} + +void PropertyFinder::mergeLists(QVariantList *values) +{ + QVariantList::iterator it = values->begin(); + while (it != values->end()) { + if (it->canConvert<QVariantList>()) { + QVariantList sublist = it->toList(); + mergeLists(&sublist); + it = values->erase(it); + for (int k = sublist.count(); --k >= 0;) + it = values->insert(it, sublist.at(k)); + } else { + ++it; + } + } +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/propertyfinder.h b/src/lib/corelib/tools/propertyfinder.h new file mode 100644 index 000000000..0db0ba39f --- /dev/null +++ b/src/lib/corelib/tools/propertyfinder.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_PROPERTY_FINDER_H +#define QBS_PROPERTY_FINDER_H + +#include <QVariantList> +#include <QVariantMap> + +namespace qbs { +namespace Internal { + +class PropertyFinder +{ +public: + enum MergeType { DoMergeLists, DoNotMergeLists }; + QVariantList propertyValues(const QVariantMap &properties, const QString &moduleName, + const QString &key, MergeType mergeType = DoMergeLists); + + // Note that this can still be a list if the property type itself is one. + QVariant propertyValue(const QVariantMap &properties, const QString &moduleName, + const QString &key); + +private: + void findModuleValues(const QVariantMap &properties, bool searchRecursively); + void addToList(const QVariant &value); + static void mergeLists(QVariantList *values); + + QString m_moduleName; + QString m_key; + QVariantList m_values; +}; + +} // namespace Internal +} // namespace qbs + +#endif // Include guard diff --git a/src/lib/corelib/tools/qbs_export.h b/src/lib/corelib/tools/qbs_export.h new file mode 100644 index 000000000..da6779088 --- /dev/null +++ b/src/lib/corelib/tools/qbs_export.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_EXPORT_H +#define QBS_EXPORT_H + +#include <qglobal.h> + +#ifdef QBS_STATIC_LIB +# define QBS_EXPORT +#else +# ifdef QBS_LIBRARY +# define QBS_EXPORT Q_DECL_EXPORT +# else +# define QBS_EXPORT Q_DECL_IMPORT +# endif +#endif + +#endif // Include guard. diff --git a/src/lib/corelib/tools/qbsassert.cpp b/src/lib/corelib/tools/qbsassert.cpp new file mode 100644 index 000000000..46ea58b83 --- /dev/null +++ b/src/lib/corelib/tools/qbsassert.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "qbsassert.h" +#include "error.h" + +#include <QString> + +namespace qbs { +namespace Internal { + +void writeAssertLocation(const char *condition, const char *file, int line) +{ + qDebug("SOFT ASSERT: %s in %s:%d", condition, file, line); +} + +void throwAssertLocation(const char *condition, const char *file, int line) +{ + throw ErrorInfo(QString(QLatin1String("ASSERT: %1")).arg(condition), + CodeLocation(QString::fromLocal8Bit(file), line), true); +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/qbsassert.h b/src/lib/corelib/tools/qbsassert.h new file mode 100644 index 000000000..25c00ae1a --- /dev/null +++ b/src/lib/corelib/tools/qbsassert.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_QBSASSERT_H +#define QBS_QBSASSERT_H + +#include "qbs_export.h" + +namespace qbs { +namespace Internal { + +void QBS_EXPORT writeAssertLocation(const char *condition, const char *file, int line); +void QBS_EXPORT throwAssertLocation(const char *condition, const char *file, int line); + +} // namespace Internal +} // namespace qbs + +#define QBS_ASSERT(cond, action)\ + if (Q_LIKELY(cond)) {} else {\ + ::qbs::Internal::writeAssertLocation(#cond, __FILE__, __LINE__); action;\ + } do {} while (0) + +// The do {} while (0) is here to enforce the use of a semicolon after QBS_ASSERT. +// action can also be continue or break. Copied from qtcassert.h in Qt Creator. + +#define QBS_CHECK(cond)\ + do {\ + if (Q_LIKELY(cond)) {} else {\ + ::qbs::Internal::throwAssertLocation(#cond, __FILE__, __LINE__);\ + }\ + } while (0) + +#endif // QBS_QBSASSERT_H diff --git a/src/lib/corelib/tools/qttools.cpp b/src/lib/corelib/tools/qttools.cpp new file mode 100644 index 000000000..21fef9b8f --- /dev/null +++ b/src/lib/corelib/tools/qttools.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "qttools.h" + +QT_BEGIN_NAMESPACE +uint qHash(const QStringList &list) +{ + uint s = 0; + foreach (const QString &n, list) + s ^= qHash(n) + 0x9e3779b9 + (s << 6) + (s >> 2); + return s; +} +QT_END_NAMESPACE diff --git a/src/lib/corelib/tools/qttools.h b/src/lib/corelib/tools/qttools.h new file mode 100644 index 000000000..bef545c0e --- /dev/null +++ b/src/lib/corelib/tools/qttools.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBSQTTOOLS_H +#define QBSQTTOOLS_H + +#include <QHash> +#include <QStringList> + +QT_BEGIN_NAMESPACE +uint qHash(const QStringList &list); +QT_END_NAMESPACE + +#endif // QBSQTTOOLS_H diff --git a/src/lib/corelib/tools/scannerpluginmanager.cpp b/src/lib/corelib/tools/scannerpluginmanager.cpp new file mode 100644 index 000000000..3c5dad702 --- /dev/null +++ b/src/lib/corelib/tools/scannerpluginmanager.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "scannerpluginmanager.h" + +#include <logging/logger.h> +#include <logging/translator.h> +#include <tools/hostosinfo.h> + +#include <QCoreApplication> +#include <QDirIterator> +#include <QLibrary> + +namespace qbs { +namespace Internal { + +ScannerPluginManager::~ScannerPluginManager() +{ + foreach (QLibrary * const lib, m_libs) { + lib->unload(); + delete lib; + } +} + +ScannerPluginManager *ScannerPluginManager::instance() +{ + static ScannerPluginManager scannerPlugin; + return &scannerPlugin; +} + +ScannerPluginManager::ScannerPluginManager() +{ +} + +QList<ScannerPlugin *> ScannerPluginManager::scannersForFileTag(const FileTag &fileTag) +{ + return instance()->m_scannerPlugins.value(fileTag); +} + +void ScannerPluginManager::loadPlugins(const QStringList &pluginPaths, const Logger &logger) +{ + QStringList filters; + + if (HostOsInfo::isWindowsHost()) + filters << "*.dll"; + else if (HostOsInfo::isOsxHost()) + filters << "*.dylib"; + else + filters << "*.so"; + + foreach (const QString &pluginPath, pluginPaths) { + logger.qbsTrace() << QString::fromLocal8Bit("pluginmanager: loading plugins from '%1'.") + .arg(QDir::toNativeSeparators(pluginPath)); + QDirIterator it(pluginPath, filters, QDir::Files); + while (it.hasNext()) { + const QString fileName = it.next(); + QScopedPointer<QLibrary> lib(new QLibrary(fileName)); + if (!lib->load()) { + logger.qbsWarning() << Tr::tr("pluginmanager: couldn't load plugin '%1': %2") + .arg(QDir::toNativeSeparators(fileName), lib->errorString()); + continue; + } + + getScanners_f getScanners = reinterpret_cast<getScanners_f>(lib->resolve("getScanners")); + if (!getScanners) { + logger.qbsWarning() << Tr::tr("pluginmanager: couldn't resolve " + "symbol in '%1'.").arg(QDir::toNativeSeparators(fileName)); + continue; + } + + ScannerPlugin **plugins = getScanners(); + if (plugins == 0) { + logger.qbsWarning() << Tr::tr("pluginmanager: no scanners " + "returned from '%1'.").arg(QDir::toNativeSeparators(fileName)); + continue; + } + + logger.qbsTrace() << QString::fromLocal8Bit("pluginmanager: scanner plugin '%1' " + "loaded.").arg(QDir::toNativeSeparators(fileName)); + + for (int i = 0; plugins[i] != 0; ++i) + m_scannerPlugins[FileTag(plugins[i]->fileTag)] += plugins[i]; + m_libs.append(lib.take()); + } + } +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/scannerpluginmanager.h b/src/lib/corelib/tools/scannerpluginmanager.h new file mode 100644 index 000000000..ce1ab2d2d --- /dev/null +++ b/src/lib/corelib/tools/scannerpluginmanager.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_PLUGINS_H +#define QBS_PLUGINS_H + +#include <language/filetags.h> +#include <plugins/scanner/scanner.h> + +#include <QHash> +#include <QString> + +QT_BEGIN_NAMESPACE +class QLibrary; +QT_END_NAMESPACE + +namespace qbs { +namespace Internal { +class Logger; + +class ScannerPluginManager +{ +public: + ~ScannerPluginManager(); + static ScannerPluginManager *instance(); + static QList<ScannerPlugin *> scannersForFileTag(const FileTag &fileTag); + void loadPlugins(const QStringList &paths, const Logger &logger); + +private: + ScannerPluginManager(); + +private: + QList<QLibrary *> m_libs; + QHash<FileTag, QList<ScannerPlugin*> > m_scannerPlugins; +}; + +} // namespace Internal +} // namespace qbs + +#endif diff --git a/src/lib/corelib/tools/scripttools.cpp b/src/lib/corelib/tools/scripttools.cpp new file mode 100644 index 000000000..c87898da5 --- /dev/null +++ b/src/lib/corelib/tools/scripttools.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "scripttools.h" + +#include <QScriptEngine> +#include <QScriptValueIterator> + +QT_BEGIN_NAMESPACE + +QDataStream &operator<< (QDataStream &s, const QScriptProgram &script) +{ + s << script.sourceCode() + << script.fileName() + << script.firstLineNumber(); + return s; +} + +QDataStream &operator>> (QDataStream &s, QScriptProgram &script) +{ + QString fileName, sourceCode; + int lineNumber; + s >> sourceCode + >> fileName + >> lineNumber; + script = QScriptProgram(sourceCode, fileName, lineNumber); + return s; +} + +QT_END_NAMESPACE + +namespace qbs { +namespace Internal { + +void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value) +{ + if (name.length() == 1) { + cfg.insert(name.first(), value); + } else { + QVariant &subCfg = cfg[name.first()]; + QVariantMap subCfgMap = subCfg.toMap(); + setConfigProperty(subCfgMap, name.mid(1), value); + subCfg = subCfgMap; + } +} + +QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name) +{ + if (name.length() == 1) + return cfg.value(name.first()); + else + return getConfigProperty(cfg.value(name.first()).toMap(), name.mid(1)); +} + +QString toJSLiteral(const bool b) +{ + return b ? "true" : "false"; +} + +QString toJSLiteral(const QString &str) +{ + QString js = str; + js.replace(QRegExp("([\\\\\"])"), "\\\\1"); + js.prepend('"'); + js.append('"'); + return js; +} + +QString toJSLiteral(const QStringList &strs) +{ + QString js = "["; + for (int i = 0; i < strs.count(); ++i) { + if (i != 0) + js.append(", "); + js.append(toJSLiteral(strs.at(i))); + } + js.append(']'); + return js; +} + +QString toJSLiteral(const QVariant &val) +{ + if (!val.isValid()) { + return "undefined"; + } else if (val.type() == QVariant::List || val.type() == QVariant::StringList) { + QString res; + foreach (const QVariant &child, val.toList()) { + if (res.length()) res.append(", "); + res.append(toJSLiteral(child)); + } + res.prepend("["); + res.append("]"); + return res; + } else if (val.type() == QVariant::Bool) { + return val.toBool() ? "true" : "false"; + } else if (val.canConvert(QVariant::String)) { + return QLatin1Char('"') + val.toString() + QLatin1Char('"'); + } else { + return QString("Unconvertible type %1").arg(val.typeName()); + } +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/scripttools.h b/src/lib/corelib/tools/scripttools.h new file mode 100644 index 000000000..4230c898c --- /dev/null +++ b/src/lib/corelib/tools/scripttools.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_SCRIPTTOOLS_H +#define QBS_SCRIPTTOOLS_H + +#include <tools/qbs_export.h> + +#include <QScriptEngine> +#include <QScriptProgram> +#include <QScriptValue> +#include <QSet> +#include <QStringList> +#include <QVariantMap> + +QT_BEGIN_NAMESPACE + +QDataStream &operator<< (QDataStream &s, const QScriptProgram &script); +QDataStream &operator>> (QDataStream &s, QScriptProgram &script); + +QT_END_NAMESPACE + +namespace qbs { +namespace Internal { + +template <typename C> +QScriptValue toScriptValue(QScriptEngine *scriptEngine, const C &container) +{ + QScriptValue v = scriptEngine->newArray(container.count()); + int i = 0; + foreach (const typename C::value_type &item, container) + v.setProperty(i++, scriptEngine->toScriptValue(item)); + return v; +} + +void setConfigProperty(QVariantMap &cfg, const QStringList &name, const QVariant &value); +QVariant getConfigProperty(const QVariantMap &cfg, const QStringList &name); + +QString toJSLiteral(const bool b); +QString toJSLiteral(const QString &str); +QString toJSLiteral(const QStringList &strs); +QString toJSLiteral(const QVariant &val); + +/** + * @brief push/pop a QScriptEngine's context the RAII way. + */ +class ScriptEngineContextPusher +{ +public: + ScriptEngineContextPusher(QScriptEngine *scriptEngine) + : m_scriptEngine(scriptEngine) + { + m_scriptEngine->pushContext(); + } + + ~ScriptEngineContextPusher() + { + m_scriptEngine->popContext(); + } + +private: + QScriptEngine *m_scriptEngine; +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_SCRIPTTOOLS_H diff --git a/src/lib/corelib/tools/settings.cpp b/src/lib/corelib/tools/settings.cpp new file mode 100644 index 000000000..95d27ba24 --- /dev/null +++ b/src/lib/corelib/tools/settings.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#include "settings.h" + +#include "error.h" +#include <logging/translator.h> +#include <tools/hostosinfo.h> + +#include <QSettings> + +#include <algorithm> + +namespace qbs { +using namespace Internal; + +static QSettings::Format format() +{ + return HostOsInfo::isWindowsHost() ? QSettings::IniFormat : QSettings::NativeFormat; +} + +static void migrateValue(QSettings *settings, const QString &key) +{ + const QVariant v = settings->value(key); + if (!v.isValid()) + return; + settings->setValue(QLatin1String("org/qt-project/qbs/") + key, v); + settings->remove(key); +} + +static void migrateGroup(QSettings *settings, const QString &group) +{ + QStringList fullKeys; + settings->beginGroup(group); + foreach (const QString &key, settings->allKeys()) + fullKeys += group + QLatin1Char('/') + key; + settings->endGroup(); + foreach (const QString &key, fullKeys) + migrateValue(settings, key); +} + +Settings::Settings(const QString &organization, const QString &application) + : m_settings(new QSettings(format(), QSettings::UserScope, organization, application)) +{ + if (HostOsInfo::isOsxHost()) { + // Migrate settings to internal group. + // ### remove in qbs 1.3 + if (!m_settings->childGroups().contains(QLatin1String("org/qt-project/qbs"))) { + migrateValue(m_settings, QLatin1String("defaultProfile")); + migrateGroup(m_settings, QLatin1String("profiles")); + migrateGroup(m_settings, QLatin1String("preferences")); + } + // Actual qbs settings are stored within a group, because QSettings sees extra system global + // settings on OS X we're not interested in. + m_settings->beginGroup(QLatin1String("org/qt-project/qbs")); + } +} + +Settings::~Settings() +{ + delete m_settings; +} + +QVariant Settings::value(const QString &key, const QVariant &defaultValue) const +{ + return m_settings->value(internalRepresentation(key), defaultValue); +} + +QStringList Settings::allKeys() const +{ + QStringList keys = m_settings->allKeys(); + fixupKeys(keys); + return keys; +} + +QStringList Settings::directChildren(const QString &parentGroup) +{ + m_settings->beginGroup(internalRepresentation(parentGroup)); + QStringList children = m_settings->childGroups(); + children << m_settings->childKeys(); + m_settings->endGroup(); + fixupKeys(children); + return children; +} + +QStringList Settings::allKeysWithPrefix(const QString &group) const +{ + m_settings->beginGroup(internalRepresentation(group)); + QStringList keys = m_settings->allKeys(); + m_settings->endGroup(); + fixupKeys(keys); + return keys; +} + +void Settings::setValue(const QString &key, const QVariant &value) +{ + m_settings->setValue(internalRepresentation(key), value); + checkStatus(); +} + +void Settings::remove(const QString &key) +{ + m_settings->remove(internalRepresentation(key)); + checkStatus(); +} + +void Settings::clear() +{ + m_settings->clear(); +} + +QString Settings::defaultProfile() const +{ + return value(QLatin1String("defaultProfile")).toString(); +} + +QStringList Settings::profiles() const +{ + m_settings->beginGroup(QLatin1String("profiles")); + QStringList result = m_settings->childGroups(); + m_settings->endGroup(); + return result; +} + +QString Settings::internalRepresentation(const QString &externalKey) const +{ + QString internalKey = externalKey; + return internalKey.replace(QLatin1Char('.'), QLatin1Char('/')); +} + +QString Settings::externalRepresentation(const QString &internalKey) const +{ + QString externalKey = internalKey; + return externalKey.replace(QLatin1Char('/'), QLatin1Char('.')); +} + +void Settings::fixupKeys(QStringList &keys) const +{ + keys.sort(); + keys.removeDuplicates(); + for (QStringList::Iterator it = keys.begin(); it != keys.end(); ++it) + *it = externalRepresentation(*it); +} + +void Settings::checkStatus() +{ + m_settings->sync(); + switch (m_settings->status()) { + case QSettings::NoError: + break; + case QSettings::AccessError: + throw ErrorInfo(Tr::tr("%1 is not accessible.").arg(m_settings->fileName())); + case QSettings::FormatError: + throw ErrorInfo(Tr::tr("Format error in %1.").arg(m_settings->fileName())); + } +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/settings.h b/src/lib/corelib/tools/settings.h new file mode 100644 index 000000000..2542df4fb --- /dev/null +++ b/src/lib/corelib/tools/settings.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ + +#ifndef QBS_SETTINGS_H +#define QBS_SETTINGS_H + +#include "qbs_export.h" + +#include <QStringList> +#include <QVariant> + +QT_BEGIN_NAMESPACE +class QSettings; +QT_END_NAMESPACE + +namespace qbs { + +class QBS_EXPORT Settings +{ +public: + Settings(const QString &organization, const QString &application); + ~Settings(); + + QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; + QStringList allKeys() const; + QStringList directChildren(const QString &parentGroup); // Keys and groups. + QStringList allKeysWithPrefix(const QString &group) const; + void setValue(const QString &key, const QVariant &value); + void remove(const QString &key); + void clear(); + + QString defaultProfile() const; + QStringList profiles() const; + +private: + QString internalRepresentation(const QString &externalKey) const; + QString externalRepresentation(const QString &internalKey) const; + void fixupKeys(QStringList &keys) const; + void checkStatus(); + + QSettings * const m_settings; +}; + +} // namespace qbs + +#endif // QBS_SETTINGS_H diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp new file mode 100644 index 000000000..c3b00f3c4 --- /dev/null +++ b/src/lib/corelib/tools/setupprojectparameters.cpp @@ -0,0 +1,434 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "setupprojectparameters.h" + +#include <logging/translator.h> +#include <tools/profile.h> +#include <tools/qbsassert.h> +#include <tools/scripttools.h> +#include <tools/settings.h> + +namespace qbs { +namespace Internal { + +/*! + * \class SetupProjectParameters + * \brief The \c SetupProjectParameters class comprises data required to set up a qbs project. + */ + +class SetupProjectParametersPrivate : public QSharedData +{ +public: + SetupProjectParametersPrivate() + : ignoreDifferentProjectFilePath(false) + , dryRun(false) + , logElapsedTime(false) + , restoreBehavior(SetupProjectParameters::RestoreAndTrackChanges) + , environment(QProcessEnvironment::systemEnvironment()) + { + } + + QString projectFilePath; + QString buildRoot; + QStringList searchPaths; + QStringList pluginPaths; + QVariantMap overriddenValues; + QVariantMap buildConfiguration; + mutable QVariantMap overriddenValuesTree; + mutable QVariantMap buildConfigurationTree; + mutable QVariantMap finalBuildConfigtree; + bool ignoreDifferentProjectFilePath; + bool dryRun; + bool logElapsedTime; + SetupProjectParameters::RestoreBehavior restoreBehavior; + QProcessEnvironment environment; +}; + +} // namespace Internal + +SetupProjectParameters::SetupProjectParameters() : d(new Internal::SetupProjectParametersPrivate) +{ +} + +SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) : d(other.d) +{ +} + +SetupProjectParameters::~SetupProjectParameters() +{ +} + +SetupProjectParameters &SetupProjectParameters::operator=(const SetupProjectParameters &other) +{ + d = other.d; + return *this; +} + +/*! + * \brief Returns the absolute path to the qbs project file. + * This file typically has a ".qbs" suffix. + */ +QString SetupProjectParameters::projectFilePath() const +{ + return d->projectFilePath; +} + +/*! + * \brief Sets the path to the main project file. + * \note The argument must be an absolute file path. + */ +void SetupProjectParameters::setProjectFilePath(const QString &projectFilePath) +{ + d->projectFilePath = projectFilePath; +} + +/*! + * \brief Returns the base path of where to put the build artifacts and store the build graph. + */ +QString SetupProjectParameters::buildRoot() const +{ + return d->buildRoot; +} + +/*! + * \brief Sets the base path of where to put the build artifacts and store the build graph. + * The same base path can be used for several build profiles of the same project without them + * interfering with each other. + * It might look as if this parameter would not be needed at the time of setting up the project, + * but keep in mind that the project information could already exist on disk, in which case + * loading it will be much faster than setting up the project from scratch. + * \note The argument must be an absolute path to a directory. + */ +void SetupProjectParameters::setBuildRoot(const QString &buildRoot) +{ + d->buildRoot = buildRoot; +} + +/*! + * \brief Where to look for modules and items to import. + */ +QStringList SetupProjectParameters::searchPaths() const +{ + return d->searchPaths; +} + +/*! + * \brief Sets the information about where to look for modules and items to import. + * \note The elements of the list must be absolute paths to directories. + */ +void SetupProjectParameters::setSearchPaths(const QStringList &searchPaths) +{ + d->searchPaths = searchPaths; +} + +/*! + * \brief Where to look for plugins. + */ +QStringList SetupProjectParameters::pluginPaths() const +{ + return d->pluginPaths; +} + +/*! + * \brief Sets the information about where to look for plugins. + * \note The elements of the list must be absolute paths to directories. + */ +void SetupProjectParameters::setPluginPaths(const QStringList &pluginPaths) +{ + d->pluginPaths = pluginPaths; +} + +/*! + * Returns the overridden values of the build configuration. + */ +QVariantMap SetupProjectParameters::overriddenValues() const +{ + return d->overriddenValues; +} + +/*! + * Set the overridden values of the build configuration. + */ +void SetupProjectParameters::setOverriddenValues(const QVariantMap &values) +{ + // warn if somebody tries to set a build configuration tree: + for (QVariantMap::const_iterator i = values.constBegin(); + i != values.constEnd(); ++i) { + QBS_ASSERT(i.value().type() != QVariant::Map, return); + } + d->overriddenValues = values; + d->overriddenValuesTree.clear(); + d->finalBuildConfigtree.clear(); +} + +static void provideValuesTree(const QVariantMap &values, QVariantMap *valueTree) +{ + if (!valueTree->isEmpty() || values.isEmpty()) + return; + + valueTree->clear(); + for (QVariantMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it) { + QStringList nameElements = it.key().split(QLatin1Char('.')); + if (nameElements.count() > 2) { // ### workaround for submodules being represented internally as a single module of name "module/submodule" rather than two nested modules "module" and "submodule" + const QString last = nameElements.takeLast(); + nameElements = QStringList(nameElements.join(QLatin1String("/"))); + nameElements.append(last); + } + Internal::setConfigProperty(*valueTree, nameElements, it.value()); + } +} + +QVariantMap SetupProjectParameters::overriddenValuesTree() const +{ + provideValuesTree(d->overriddenValues, &d->overriddenValuesTree); + return d->overriddenValuesTree; +} + +/*! + * \brief The collection of properties to use for resolving the project. + */ +QVariantMap SetupProjectParameters::buildConfiguration() const +{ + return d->buildConfiguration; +} + +/*! + * Sets the collection of properties to use for resolving the project. + * + * Keys are expected to be in dotted syntax (e.g. Qt.declarative.qmlDebugging) that is + * used by "qbs config". + */ +void SetupProjectParameters::setBuildConfiguration(const QVariantMap &buildConfiguration) +{ + // warn if somebody tries to set a build configuration tree: + for (QVariantMap::const_iterator i = buildConfiguration.constBegin(); + i != buildConfiguration.constEnd(); ++i) { + QBS_ASSERT(i.value().type() != QVariant::Map, return); + } + d->buildConfiguration = buildConfiguration; + d->buildConfigurationTree.clear(); + d->finalBuildConfigtree.clear(); +} + +/*! + * \brief Returns the build configuration in tree form. + * \return the tree form of the build configuration. + */ +QVariantMap SetupProjectParameters::buildConfigurationTree() const +{ + provideValuesTree(d->buildConfiguration, &d->buildConfigurationTree); + return d->buildConfigurationTree; +} + +/*! + * \brief Expands the build configuration based on the given settings. + * + * Expansion is the process by which the build configuration is completed based on the given + * settings. E.g. the information configured in a profile is filled into the build + * configuration by this step. + * + * This method returns an Error. The list of entries in this error will be empty is the + * expansion was successful. + */ +ErrorInfo SetupProjectParameters::expandBuildConfiguration(Settings *settings) +{ + ErrorInfo err; + + // Generates a full build configuration from user input, using the settings. + QVariantMap expandedConfig = d->buildConfiguration; + + const QString buildVariant = expandedConfig.value(QLatin1String("qbs.buildVariant")).toString(); + if (buildVariant.isEmpty()) + return ErrorInfo(Internal::Tr::tr("No build variant set.")); + if (buildVariant != QLatin1String("debug") && buildVariant != QLatin1String("release")) { + err.append(Internal::Tr::tr("Invalid build variant '%1'. Must be 'debug' or 'release'.") + .arg(buildVariant)); + return err; + } + + // Fill in buildCfg in this order (making sure not to overwrite a key already set by a previous stage) + // 1) Things specified on command line (already in buildCfg at this point) + // 2) Everything from the profile key + QString profileName = expandedConfig.value("qbs.profile").toString(); + if (profileName.isNull()) { + profileName = settings->defaultProfile(); + if (profileName.isNull()) { + const QString profileNames = settings->profiles().join(QLatin1String(", ")); + err.append(Internal::Tr::tr("No profile given and no default profile set.\n" + "Either set the configuration value 'defaultProfile' to a " + "valid profile name\n" + "or specify the profile with the command line parameter " + "'profile:name'.\n" + "The following profiles are available:\n%1") + .arg(profileNames)); + return err; + } + expandedConfig.insert("qbs.profile", profileName); + } + + // (2) + const Profile profile(profileName, settings); + const QStringList profileKeys = profile.allKeys(Profile::KeySelectionRecursive); + if (profileKeys.isEmpty()) { + err.append(Internal::Tr::tr("Unknown or empty profile '%1'.").arg(profileName)); + return err; + } + foreach (const QString &profileKey, profileKeys) { + if (!expandedConfig.contains(profileKey)) + expandedConfig.insert(profileKey, profile.value(profileKey)); + } + + if (d->buildConfiguration != expandedConfig) { + d->buildConfigurationTree.clear(); + d->buildConfiguration = expandedConfig; + } + return err; +} + +/*! + * \brief Returns the build configuration in tree form, with overridden values taken into account. + */ +QVariantMap SetupProjectParameters::finalBuildConfigurationTree() const +{ + if (d->finalBuildConfigtree.isEmpty()) { + QVariantMap finalMap = d->buildConfiguration; + for (QVariantMap::ConstIterator it = d->overriddenValues.constBegin(); + it != d->overriddenValues.constEnd(); ++it) { + finalMap.insert(it.key(), it.value()); + } + provideValuesTree(finalMap, &d->finalBuildConfigtree); + } + return d->finalBuildConfigtree; +} + +/*! + * \variable SetupProjectParameters::ignoreDifferentProjectFilePath + * \brief Returns true iff the saved build graph should be used even if its path to the + * project file is different from \c SetupProjectParameters::projectFilePath() + */ +bool SetupProjectParameters::ignoreDifferentProjectFilePath() const +{ + return d->ignoreDifferentProjectFilePath; +} + +/*! + * \brief Controls whether the path to the main project file may be different from the one + * stored in a possible build graph file. + * The default is false. + */ +void SetupProjectParameters::setIgnoreDifferentProjectFilePath(bool doIgnore) +{ + d->ignoreDifferentProjectFilePath = doIgnore; +} + + /*! + * \brief if true, qbs will not store the build graph of the resolved project. + */ +bool SetupProjectParameters::dryRun() const +{ + return d->dryRun; +} + + /*! + * \brief Controls whether the build graph will be stored. + * If the argument is true, qbs will not store the build graph after resolving the project. + * The default is false. + */ +void SetupProjectParameters::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} + + /*! + * \brief Returns true iff the time the operation takes should be logged + */ +bool SetupProjectParameters::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * Controls whether to log the time taken up for resolving the project. + * The default is false. + */ +void SetupProjectParameters::setLogElapsedTime(bool logElapsedTime) +{ + d->logElapsedTime = logElapsedTime; +} + +/*! + * \brief Gets the environment used while resolving the project. + */ +QProcessEnvironment SetupProjectParameters::environment() const +{ + return d->environment; +} + +/*! + * \brief Sets the environment used while resolving the project. + */ +void SetupProjectParameters::setEnvironment(const QProcessEnvironment &env) +{ + d->environment = env; +} + + +/*! + * \enum SetupProjectParamaters::RestoreBehavior + * This enum type specifies how to deal with existing on-disk build information. + * \value RestoreOnly Indicates that a stored build graph is to be loaded and the information + * therein assumed to be up to date. It is then considered an error if no + * such build graph exists. + * \value ResolveOnly Indicates that no attempt should be made to restore an existing build graph. + * Instead, the project is to be resolved from scratch. + * \value RestoreAndTrackChanges Indicates that the build graph should be restored from disk + * if possible and otherwise set up from scratch. In the first case, + * (parts of) the project might still be re-resolved if certain + * parameters have changed (e.g. environment variables used in the + * project files). + */ + + +/*! + * Returns information about how restored build data will be handled. + */ +SetupProjectParameters::RestoreBehavior SetupProjectParameters::restoreBehavior() const +{ + return d->restoreBehavior; +} + +/*! + * Controls how restored build data will be handled. + */ +void SetupProjectParameters::setRestoreBehavior(SetupProjectParameters::RestoreBehavior behavior) +{ + d->restoreBehavior = behavior; +} + +} // namespace qbs diff --git a/src/lib/corelib/tools/setupprojectparameters.h b/src/lib/corelib/tools/setupprojectparameters.h new file mode 100644 index 000000000..d6d8bf88c --- /dev/null +++ b/src/lib/corelib/tools/setupprojectparameters.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_SETUPPROJECTPARAMETERS_H +#define QBS_SETUPPROJECTPARAMETERS_H + +#include "qbs_export.h" + +#include <tools/error.h> + +#include <QProcessEnvironment> +#include <QSharedDataPointer> +#include <QStringList> +#include <QVariantMap> + +namespace qbs { + +class Settings; + +namespace Internal { class SetupProjectParametersPrivate; } + +class QBS_EXPORT SetupProjectParameters +{ +public: + SetupProjectParameters(); + SetupProjectParameters(const SetupProjectParameters &other); + ~SetupProjectParameters(); + + SetupProjectParameters &operator=(const SetupProjectParameters &other); + + QString projectFilePath() const; + void setProjectFilePath(const QString &projectFilePath); + + QString buildRoot() const; + void setBuildRoot(const QString &buildRoot); + + QStringList searchPaths() const; + void setSearchPaths(const QStringList &searchPaths); + + QStringList pluginPaths() const; + void setPluginPaths(const QStringList &pluginPaths); + + QVariantMap overriddenValues() const; + void setOverriddenValues(const QVariantMap &values); + QVariantMap overriddenValuesTree() const; + + QVariantMap buildConfiguration() const; + void setBuildConfiguration(const QVariantMap &buildConfiguration); + QVariantMap buildConfigurationTree() const; + ErrorInfo expandBuildConfiguration(Settings *settings); + + QVariantMap finalBuildConfigurationTree() const; + + bool ignoreDifferentProjectFilePath() const; + void setIgnoreDifferentProjectFilePath(bool doIgnore); + + bool dryRun() const; + void setDryRun(bool dryRun); + + bool logElapsedTime() const; + void setLogElapsedTime(bool logElapsedTime); + + QProcessEnvironment environment() const; + void setEnvironment(const QProcessEnvironment &env); + + enum RestoreBehavior { RestoreOnly, ResolveOnly, RestoreAndTrackChanges }; + RestoreBehavior restoreBehavior() const; + void setRestoreBehavior(RestoreBehavior behavior); + +private: + QSharedDataPointer<Internal::SetupProjectParametersPrivate> d; +}; + +} // namespace qbs + +#endif // Include guard diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri new file mode 100644 index 000000000..fca3d8f4b --- /dev/null +++ b/src/lib/corelib/tools/tools.pri @@ -0,0 +1,79 @@ +INCLUDEPATH += $$PWD/../.. # for plugins + +HEADERS += \ + $$PWD/codelocation.h \ + $$PWD/error.h \ + $$PWD/fileinfo.h \ + $$PWD/filetime.h \ + $$PWD/id.h \ + $$PWD/persistence.h \ + $$PWD/scannerpluginmanager.h \ + $$PWD/scripttools.h \ + $$PWD/settings.h \ + $$PWD/preferences.h \ + $$PWD/profile.h \ + $$PWD/processresult.h \ + $$PWD/processresult_p.h \ + $$PWD/progressobserver.h \ + $$PWD/propertyfinder.h \ + $$PWD/hostosinfo.h \ + $$PWD/buildoptions.h \ + $$PWD/installoptions.h \ + $$PWD/cleanoptions.h \ + $$PWD/setupprojectparameters.h \ + $$PWD/persistentobject.h \ + $$PWD/weakpointer.h \ + $$PWD/qbs_export.h \ + $$PWD/qbsassert.h \ + $$PWD/qttools.h + +SOURCES += \ + $$PWD/codelocation.cpp \ + $$PWD/error.cpp \ + $$PWD/fileinfo.cpp \ + $$PWD/id.cpp \ + $$PWD/persistence.cpp \ + $$PWD/scannerpluginmanager.cpp \ + $$PWD/scripttools.cpp \ + $$PWD/settings.cpp \ + $$PWD/preferences.cpp \ + $$PWD/processresult.cpp \ + $$PWD/profile.cpp \ + $$PWD/progressobserver.cpp \ + $$PWD/propertyfinder.cpp \ + $$PWD/buildoptions.cpp \ + $$PWD/installoptions.cpp \ + $$PWD/cleanoptions.cpp \ + $$PWD/setupprojectparameters.cpp \ + $$PWD/qbsassert.cpp \ + $$PWD/qttools.cpp + +win32 { + SOURCES += $$PWD/filetime_win.cpp +} + +unix { + SOURCES += $$PWD/filetime_unix.cpp +} + +all_tests { + HEADERS += $$PWD/tst_tools.h + SOURCES += $$PWD/tst_tools.cpp +} + +!qbs_no_dev_install { + tools_headers.files = \ + $$PWD/cleanoptions.h \ + $$PWD/codelocation.h \ + $$PWD/error.h \ + $$PWD/settings.h \ + $$PWD/preferences.h \ + $$PWD/profile.h \ + $$PWD/processresult.h \ + $$PWD/qbs_export.h \ + $$PWD/buildoptions.h \ + $$PWD/installoptions.h \ + $$PWD/setupprojectparameters.h + tools_headers.path = $${QBS_INSTALL_PREFIX}/include/qbs/tools + INSTALLS += tools_headers +} diff --git a/src/lib/corelib/tools/tst_tools.cpp b/src/lib/corelib/tools/tst_tools.cpp new file mode 100644 index 000000000..c1af58f70 --- /dev/null +++ b/src/lib/corelib/tools/tst_tools.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "tst_tools.h" + +#include <tools/buildoptions.h> +#include <tools/error.h> +#include <tools/fileinfo.h> +#include <tools/hostosinfo.h> +#include <tools/profile.h> +#include <tools/settings.h> +#include <tools/setupprojectparameters.h> + +#include <QFileInfo> +#include <QTemporaryFile> +#include <QTest> + +namespace qbs { +namespace Internal { + +TestTools::TestTools(Settings *settings) : m_settings(settings) +{ +} + +void TestTools::testFileInfo() +{ + QCOMPARE(FileInfo::fileName("C:/waffl/copter.exe"), QString("copter.exe")); + QCOMPARE(FileInfo::baseName("C:/waffl/copter.exe.lib"), QString("copter")); + QCOMPARE(FileInfo::completeBaseName("C:/waffl/copter.exe.lib"), QString("copter.exe")); + QCOMPARE(FileInfo::path("abc"), QString(".")); + QCOMPARE(FileInfo::path("/abc/lol"), QString("/abc")); + QVERIFY(!FileInfo::isAbsolute("bla/lol")); + QVERIFY(FileInfo::isAbsolute("/bla/lol")); + if (HostOsInfo::isWindowsHost()) + QVERIFY(FileInfo::isAbsolute("C:\\bla\\lol")); + QCOMPARE(FileInfo::resolvePath("/abc/lol", "waffl"), QString("/abc/lol/waffl")); + QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../foo/bar"), QString("/abc/def/ghi/foo/bar")); + QCOMPARE(FileInfo::resolvePath("/abc/def/ghi/jkl/", "../../foo/bar"), QString("/abc/def/foo/bar")); + QCOMPARE(FileInfo::resolvePath("/abc", "../../../foo/bar"), QString("/foo/bar")); + QCOMPARE(FileInfo("/does/not/exist").lastModified(), FileTime()); +} + +void TestTools::fileCaseCheck() +{ + QTemporaryFile tempFile(QLatin1String("CamelCase")); + QVERIFY(tempFile.open()); + QFileInfo tempFileInfo(tempFile.fileName()); + const QString lowerFilePath = tempFileInfo.absolutePath() + QLatin1Char('/') + + tempFileInfo.fileName().toLower(); + const QString upperFilePath = tempFileInfo.absolutePath() + QLatin1Char('/') + + tempFileInfo.fileName().toUpper(); + QVERIFY(FileInfo::isFileCaseCorrect(tempFileInfo.absoluteFilePath())); + if (QFile::exists(lowerFilePath)) + QVERIFY(!FileInfo::isFileCaseCorrect(lowerFilePath)); + if (QFile::exists(upperFilePath)) + QVERIFY(!FileInfo::isFileCaseCorrect(upperFilePath)); +} + +void TestTools::testProfiles() +{ + bool exceptionCaught; + Profile parentProfile("parent", m_settings); + Profile childProfile("child", m_settings); + try { + parentProfile.removeBaseProfile(); + parentProfile.remove("testKey"); + QCOMPARE(parentProfile.value("testKey", "none").toString(), QLatin1String("none")); + parentProfile.setValue("testKey", "testValue"); + QCOMPARE(parentProfile.value("testKey").toString(), QLatin1String("testValue")); + + childProfile.remove("testKey"); + childProfile.removeBaseProfile(); + QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("none")); + childProfile.setBaseProfile("parent"); + QCOMPARE(childProfile.value("testKey").toString(), QLatin1String("testValue")); + + // Change base profile and check if the inherited value also changes. + Profile fooProfile("foo", m_settings); + fooProfile.setValue("testKey", "gnampf"); + childProfile.setBaseProfile("foo"); + QCOMPARE(childProfile.value("testKey", "none").toString(), QLatin1String("gnampf")); + exceptionCaught = false; + } catch (ErrorInfo &) { + exceptionCaught = true; + } + QVERIFY(!exceptionCaught); + + try { + childProfile.setBaseProfile("SmurfAlongWithMe"); + childProfile.value("blubb"); + exceptionCaught = false; + } catch (ErrorInfo &) { + exceptionCaught = true; + } + QVERIFY(exceptionCaught); + + try { + childProfile.setBaseProfile("parent"); + parentProfile.setBaseProfile("child"); + QVERIFY(!childProfile.value("blubb").isValid()); + exceptionCaught = false; + } catch (ErrorInfo &) { + exceptionCaught = true; + } + QVERIFY(exceptionCaught); + + try { + QVERIFY(!childProfile.allKeys(Profile::KeySelectionNonRecursive).isEmpty()); + exceptionCaught = false; + } catch (ErrorInfo &) { + exceptionCaught = true; + } + QVERIFY(!exceptionCaught); + + try { + QVERIFY(!childProfile.allKeys(Profile::KeySelectionRecursive).isEmpty()); + exceptionCaught = false; + } catch (ErrorInfo &) { + exceptionCaught = true; + } + QVERIFY(exceptionCaught); +} + +void TestTools::testBuildConfigMerging() +{ + QVariantMap buildConfigMap; + buildConfigMap.insert(QLatin1String("topLevelKey"), QLatin1String("topLevelValue")); + buildConfigMap.insert(QLatin1String("qbs.toolchain"), QLatin1String("gcc")); + buildConfigMap.insert(QLatin1String("qbs.architecture"), + QLatin1String("Jean-Claude Pillemann")); + buildConfigMap.insert(QLatin1String("cpp.treatWarningsAsErrors"), true); + QVariantMap overrideMap; + overrideMap.insert(QLatin1String("qbs.toolchain"), QLatin1String("clang")); + SetupProjectParameters params; + params.setBuildConfiguration(buildConfigMap); + params.setOverriddenValues(overrideMap); + const QVariantMap finalMap = params.finalBuildConfigurationTree(); + QCOMPARE(finalMap.count(), 3); + QCOMPARE(finalMap.value(QLatin1String("topLevelKey")).toString(), + QString::fromLatin1("topLevelValue")); + const QVariantMap finalQbsMap = finalMap.value(QLatin1String("qbs")).toMap(); + QCOMPARE(finalQbsMap.count(), 2); + QCOMPARE(finalQbsMap.value(QLatin1String("toolchain")).toString(), + QString::fromLatin1("clang")); + QCOMPARE(finalQbsMap.value(QLatin1String("architecture")).toString(), + QString::fromLatin1("Jean-Claude Pillemann")); + const QVariantMap finalCppMap = finalMap.value(QLatin1String("cpp")).toMap(); + QCOMPARE(finalCppMap.count(), 1); + QCOMPARE(finalCppMap.value(QLatin1String("treatWarningsAsErrors")).toBool(), true); +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/tst_tools.h b/src/lib/corelib/tools/tst_tools.h new file mode 100644 index 000000000..c7168a686 --- /dev/null +++ b/src/lib/corelib/tools/tst_tools.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#include "qbs_export.h" + +#include <QObject> + +namespace qbs { +class Settings; + +namespace Internal { + +class QBS_EXPORT TestTools : public QObject +{ + Q_OBJECT + +public: + TestTools(Settings *settings); + +private slots: + void testFileInfo(); + void fileCaseCheck(); + void testProfiles(); + void testBuildConfigMerging(); + +private: + Settings * const m_settings; +}; + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/weakpointer.h b/src/lib/corelib/tools/weakpointer.h new file mode 100644 index 000000000..3da1abd6d --- /dev/null +++ b/src/lib/corelib/tools/weakpointer.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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. +** +****************************************************************************/ +#ifndef QBS_WEAKPOINTER_H +#define QBS_WEAKPOINTER_H + +#include <QWeakPointer> + +namespace qbs { +namespace Internal { + +template<typename T> class WeakPointer : public QWeakPointer<T> +{ +public: + WeakPointer() : QWeakPointer<T>() {} + WeakPointer(const QSharedPointer<T> &sharedPointer) : QWeakPointer<T>(sharedPointer) {} + template <class X> WeakPointer(const QSharedPointer<X> &sp) : QWeakPointer<T>(sp) { } + + + operator T*() const { return checkedData(); } + T *operator->() const { return checkedData(); } + T operator*() const { return *checkedData(); } + +private: + T *checkedData() const { + T * const d = QWeakPointer<T>::data(); + Q_ASSERT(d); // Calling code is not expecting this situation. + return d; + } +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_WEAKPOINTER_H |