diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2019-03-18 15:02:53 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2019-09-18 15:07:54 +0000 |
commit | 9f3a9830162f379d6f856c84668c3664df6d6477 (patch) | |
tree | b32a126840ca81a0881e71051f5c09443ede5a05 /src/lib | |
parent | 41d8b09239ce0ace2fd8674aaecae1528b1985e4 (diff) |
Introduce the session command
Offers a JSON-based API for interaction with other tools via stdin/
stdout.
This allows for proper qbs support in IDEs that do not use Qt or even
C++.
Change-Id: Ib051a40b7ebe1c6e0c3147cca9bd96e7daec1fde
Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
Diffstat (limited to 'src/lib')
22 files changed, 491 insertions, 25 deletions
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp index 3ffd6b2e9..d0fe7296e 100644 --- a/src/lib/corelib/api/project.cpp +++ b/src/lib/corelib/api/project.cpp @@ -726,7 +726,7 @@ void ProjectPrivate::updateExternalCodeLocations(const ProjectData &project, void ProjectPrivate::prepareChangeToProject() { if (internalProject->locked) - throw ErrorInfo(Tr::tr("A job is currently in process.")); + throw ErrorInfo(Tr::tr("A job is currently in progress.")); if (!m_projectData.isValid()) retrieveProjectData(m_projectData, internalProject); } @@ -766,7 +766,7 @@ RuleCommandList ProjectPrivate::ruleCommands(const ProductData &product, const QString &inputFilePath, const QString &outputFileTag) { if (internalProject->locked) - throw ErrorInfo(Tr::tr("A job is currently in process.")); + throw ErrorInfo(Tr::tr("A job is currently in progress.")); const ResolvedProductConstPtr resolvedProduct = internalProduct(product); if (!resolvedProduct) throw ErrorInfo(Tr::tr("No such product '%1'.").arg(product.name())); @@ -896,7 +896,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData, } for (const ResolvedProductPtr &resolvedDependentProduct : qAsConst(resolvedProduct->dependencies)) { - product.d->dependencies << resolvedDependentProduct->name; + product.d->dependencies << resolvedDependentProduct->name; // FIXME: Shouldn't this be a unique name? } std::sort(product.d->type.begin(), product.d->type.end()); std::sort(product.d->groups.begin(), product.d->groups.end()); @@ -1252,6 +1252,22 @@ Project::BuildGraphInfo Project::getBuildGraphInfo(const QString &bgFilePath, return info; } +Project::BuildGraphInfo Project::getBuildGraphInfo() const +{ + QBS_ASSERT(isValid(), return {}); + BuildGraphInfo info; + try { + if (d->internalProject->locked) + throw ErrorInfo(Tr::tr("A job is currently in progress.")); + info.bgFilePath = d->internalProject->buildGraphFilePath(); + info.overriddenProperties = d->internalProject->overriddenValues; + info.profileData = d->internalProject->profileConfigs; + } catch (const ErrorInfo &e) { + info.error = e; + } + return info; +} + #ifdef QBS_ENABLE_PROJECT_FILE_UPDATES /*! * \brief Adds a new empty group to the given product. diff --git a/src/lib/corelib/api/project.h b/src/lib/corelib/api/project.h index 05f08deee..9000d6548 100644 --- a/src/lib/corelib/api/project.h +++ b/src/lib/corelib/api/project.h @@ -155,6 +155,9 @@ public: static BuildGraphInfo getBuildGraphInfo(const QString &bgFilePath, const QStringList &requestedProperties); + // Use with loaded project. Does not set requestedProperties. + BuildGraphInfo getBuildGraphInfo() const; + #ifdef QBS_ENABLE_PROJECT_FILE_UPDATES ErrorInfo addGroup(const ProductData &product, const QString &groupName); diff --git a/src/lib/corelib/api/projectdata.cpp b/src/lib/corelib/api/projectdata.cpp index 56700b8be..7c64bf6ff 100644 --- a/src/lib/corelib/api/projectdata.cpp +++ b/src/lib/corelib/api/projectdata.cpp @@ -45,21 +45,57 @@ #include <tools/fileinfo.h> #include <tools/jsliterals.h> #include <tools/qbsassert.h> +#include <tools/stringconstants.h> #include <tools/qttools.h> #include <tools/stringconstants.h> #include <QtCore/qdir.h> +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> #include <algorithm> namespace qbs { +using namespace Internal; + +template<typename T> static QJsonArray toJsonArray(const QList<T> &list, + const QStringList &moduleProperties) +{ + QJsonArray jsonArray; + std::transform(list.begin(), list.end(), std::back_inserter(jsonArray), + [&moduleProperties](const T &v) { return v.toJson(moduleProperties);}); + return jsonArray; +} + +static QVariant getModuleProperty(const PropertyMap &properties, const QString &fullPropertyName) +{ + const int lastDotIndex = fullPropertyName.lastIndexOf(QLatin1Char('.')); + if (lastDotIndex == -1) + return QVariant(); + return properties.getModuleProperty(fullPropertyName.left(lastDotIndex), + fullPropertyName.mid(lastDotIndex + 1)); +} + +static void addModuleProperties(QJsonObject &obj, const PropertyMap &properties, + const QStringList &propertyNames) +{ + QJsonObject propertyValues; + for (const QString &prop : propertyNames) { + const QVariant v = getModuleProperty(properties, prop); + if (v.isValid()) + propertyValues.insert(prop, QJsonValue::fromVariant(v)); + } + if (!propertyValues.isEmpty()) + obj.insert(StringConstants::modulePropertiesKey(), propertyValues); +} + /*! * \class GroupData * \brief The \c GroupData class corresponds to the Group item in a qbs source file. */ -GroupData::GroupData() : d(new Internal::GroupDataPrivate) +GroupData::GroupData() : d(new GroupDataPrivate) { } @@ -81,6 +117,22 @@ bool GroupData::isValid() const return d->isValid; } +QJsonObject GroupData::toJson(const QStringList &moduleProperties) const +{ + QJsonObject obj; + if (isValid()) { + obj.insert(StringConstants::locationKey(), location().toJson()); + obj.insert(StringConstants::nameProperty(), name()); + obj.insert(StringConstants::prefixProperty(), prefix()); + obj.insert(StringConstants::isEnabledKey(), isEnabled()); + obj.insert(QStringLiteral("source-artifacts"), toJsonArray(sourceArtifacts(), {})); + obj.insert(QStringLiteral("source-artifacts-from-wildcards"), + toJsonArray(sourceArtifactsFromWildcards(), {})); + addModuleProperties(obj, properties(), moduleProperties); + } + return obj; +} + /*! * \brief The location at which the group is defined in the respective source file. */ @@ -204,7 +256,7 @@ bool operator<(const GroupData &lhs, const GroupData &rhs) * or it gets generated during the build process. */ -ArtifactData::ArtifactData() : d(new Internal::ArtifactDataPrivate) +ArtifactData::ArtifactData() : d(new ArtifactDataPrivate) { } @@ -226,6 +278,21 @@ bool ArtifactData::isValid() const return d->isValid; } +QJsonObject ArtifactData::toJson(const QStringList &moduleProperties) const +{ + QJsonObject obj; + if (isValid()) { + obj.insert(StringConstants::filePathKey(), filePath()); + obj.insert(QStringLiteral("file-tags"), QJsonArray::fromStringList(fileTags())); + obj.insert(QStringLiteral("is-generated"), isGenerated()); + obj.insert(QStringLiteral("is-executable"), isExecutable()); + obj.insert(QStringLiteral("is-target"), isTargetArtifact()); + obj.insert(QStringLiteral("install-data"), installData().toJson()); + addModuleProperties(obj, properties(), moduleProperties); + } + return obj; +} + /*! * \brief The full path of this file. */ @@ -256,8 +323,8 @@ bool ArtifactData::isExecutable() const { const bool isBundle = d->properties.getModuleProperty( QStringLiteral("bundle"), QStringLiteral("isBundle")).toBool(); - return Internal::isRunnableArtifact( - Internal::FileTags::fromStringList(d->fileTags), isBundle); + return isRunnableArtifact( + FileTags::fromStringList(d->fileTags), isBundle); } /*! @@ -309,7 +376,7 @@ bool operator<(const ArtifactData &ta1, const ArtifactData &ta2) * \brief The \c InstallData class provides the installation-related data of an artifact. */ -InstallData::InstallData() : d(new Internal::InstallDataPrivate) +InstallData::InstallData() : d(new InstallDataPrivate) { } @@ -331,6 +398,19 @@ bool InstallData::isValid() const return d->isValid; } +QJsonObject InstallData::toJson() const +{ + QJsonObject obj; + if (isValid()) { + obj.insert(QStringLiteral("is-installable"), isInstallable()); + if (isInstallable()) { + obj.insert(QStringLiteral("install-file-path"), installFilePath()); + obj.insert(QStringLiteral("install-root"), installRoot()); + } + } + return obj; +} + /*! \brief Returns true if and only if \c{qbs.install} is \c true for the artifact. */ @@ -348,7 +428,7 @@ bool InstallData::isInstallable() const QString InstallData::installDir() const { QBS_ASSERT(isValid(), return {}); - return Internal::FileInfo::path(installFilePath()); + return FileInfo::path(installFilePath()); } /*! @@ -392,7 +472,7 @@ QString InstallData::localInstallFilePath() const * \brief The \c ProductData class corresponds to the Product item in a qbs source file. */ -ProductData::ProductData() : d(new Internal::ProductDataPrivate) +ProductData::ProductData() : d(new ProductDataPrivate) { } @@ -414,6 +494,39 @@ bool ProductData::isValid() const return d->isValid; } +QJsonObject ProductData::toJson(const QStringList &propertyNames) const +{ + QJsonObject obj; + if (!isValid()) + return obj; + obj.insert(StringConstants::typeProperty(), QJsonArray::fromStringList(type())); + obj.insert(StringConstants::dependenciesProperty(), + QJsonArray::fromStringList(dependencies())); + obj.insert(StringConstants::nameProperty(), name()); + obj.insert(StringConstants::fullDisplayNameKey(), fullDisplayName()); + obj.insert(QStringLiteral("target-name"), targetName()); + obj.insert(StringConstants::versionProperty(), version()); + obj.insert(QStringLiteral("multiplex-configuration-id"), multiplexConfigurationId()); + obj.insert(StringConstants::locationKey(), location().toJson()); + obj.insert(StringConstants::buildDirectoryKey(), buildDirectory()); + obj.insert(QStringLiteral("generated-artifacts"), toJsonArray(generatedArtifacts(), + propertyNames)); + obj.insert(QStringLiteral("target-executable"), targetExecutable()); + QJsonArray groupArray; + for (const GroupData &g : groups()) { + const QStringList groupPropNames = g.properties() == moduleProperties() + ? QStringList() : propertyNames; + groupArray << g.toJson(groupPropNames); + } + obj.insert(QStringLiteral("groups"), groupArray); + obj.insert(QStringLiteral("properties"), QJsonObject::fromVariantMap(properties())); + obj.insert(StringConstants::isEnabledKey(), isEnabled()); + obj.insert(QStringLiteral("is-runnable"), isRunnable()); + obj.insert(QStringLiteral("is-multiplexed"), isMultiplexed()); + addModuleProperties(obj, moduleProperties(), propertyNames); + return obj; +} + /*! * \brief The product type, which is the list of file tags matching the product's target artifacts. */ @@ -445,7 +558,7 @@ QString ProductData::name() const */ QString ProductData::fullDisplayName() const { - return Internal::ResolvedProduct::fullDisplayName(name(), multiplexConfigurationId()); + return ResolvedProduct::fullDisplayName(name(), multiplexConfigurationId()); } /*! @@ -470,8 +583,8 @@ QString ProductData::version() const QString ProductData::profile() const { return d->moduleProperties.getModuleProperty( - Internal::StringConstants::qbsModule(), - Internal::StringConstants::profileProperty()).toString(); + StringConstants::qbsModule(), + StringConstants::profileProperty()).toString(); } QString ProductData::multiplexConfigurationId() const @@ -661,7 +774,7 @@ bool operator<(const ProductData &lhs, const ProductData &rhs) * \brief The products in this project. */ -ProjectData::ProjectData() : d(new Internal::ProjectDataPrivate) +ProjectData::ProjectData() : d(new ProjectDataPrivate) { } @@ -683,6 +796,19 @@ bool ProjectData::isValid() const return d->isValid; } +QJsonObject ProjectData::toJson(const QStringList &moduleProperties) const +{ + QJsonObject obj; + if (!isValid()) + return obj; + obj.insert(StringConstants::nameProperty(), name()); + obj.insert(StringConstants::locationKey(), location().toJson()); + obj.insert(StringConstants::isEnabledKey(), isEnabled()); + obj.insert(StringConstants::productsKey(), toJsonArray(products(), moduleProperties)); + obj.insert(QStringLiteral("sub-projects"), toJsonArray(subProjects(), moduleProperties)); + return obj; +} + /*! * \brief The name of this project. */ @@ -788,14 +914,14 @@ bool operator<(const ProjectData &lhs, const ProjectData &rhs) */ PropertyMap::PropertyMap() - : d(std::make_unique<Internal::PropertyMapPrivate>()) + : d(std::make_unique<PropertyMapPrivate>()) { - static Internal::PropertyMapPtr defaultInternalMap = Internal::PropertyMapInternal::create(); + static PropertyMapPtr defaultInternalMap = PropertyMapInternal::create(); d->m_map = defaultInternalMap; } PropertyMap::PropertyMap(const PropertyMap &other) - : d(std::make_unique<Internal::PropertyMapPrivate>(*other.d)) + : d(std::make_unique<PropertyMapPrivate>(*other.d)) { } @@ -806,7 +932,7 @@ PropertyMap::~PropertyMap() = default; PropertyMap &PropertyMap::operator =(const PropertyMap &other) { if (this != &other) - d = std::make_unique<Internal::PropertyMapPrivate>(*other.d); + d = std::make_unique<PropertyMapPrivate>(*other.d); return *this; } diff --git a/src/lib/corelib/api/projectdata.h b/src/lib/corelib/api/projectdata.h index 3bd1c4540..a285f8570 100644 --- a/src/lib/corelib/api/projectdata.h +++ b/src/lib/corelib/api/projectdata.h @@ -110,6 +110,7 @@ public: ~ArtifactData(); bool isValid() const; + QJsonObject toJson(const QStringList &moduleProperties = {}) const; QString filePath() const; QStringList fileTags() const; @@ -135,6 +136,7 @@ public: ~InstallData(); bool isValid() const; + QJsonObject toJson() const; bool isInstallable() const; QString installDir() const; @@ -162,6 +164,7 @@ public: ~GroupData(); bool isValid() const; + QJsonObject toJson(const QStringList &moduleProperties = {}) const; CodeLocation location() const; QString name() const; @@ -193,6 +196,7 @@ public: ~ProductData(); bool isValid() const; + QJsonObject toJson(const QStringList &propertyNames = {}) const; QStringList type() const; QStringList dependencies() const; @@ -235,6 +239,7 @@ public: ~ProjectData(); bool isValid() const; + QJsonObject toJson(const QStringList &moduleProperties = {}) const; QString name() const; CodeLocation location() const; diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index 92d7eb052..2f0ced926 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -418,6 +418,7 @@ QbsLibrary { "joblimits.cpp", "jsliterals.cpp", "jsliterals.h", + "jsonhelper.h", "installoptions.cpp", "launcherinterface.cpp", "launcherinterface.h", diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp index 5507e0842..75417ab0b 100644 --- a/src/lib/corelib/tools/buildoptions.cpp +++ b/src/lib/corelib/tools/buildoptions.cpp @@ -38,6 +38,9 @@ ****************************************************************************/ #include "buildoptions.h" +#include "jsonhelper.h" + +#include <QtCore/qjsonobject.h> #include <QtCore/qshareddata.h> #include <QtCore/qthread.h> @@ -413,4 +416,56 @@ bool operator==(const BuildOptions &bo1, const BuildOptions &bo2) && bo1.removeExistingInstallation() == bo2.removeExistingInstallation(); } +namespace Internal { +template<> JobLimits fromJson(const QJsonValue &limitsData) +{ + JobLimits limits; + const QJsonArray &limitsArray = limitsData.toArray(); + for (const QJsonValue &v : limitsArray) { + const QJsonObject limitData = v.toObject(); + QString pool; + int limit = 0; + setValueFromJson(pool, limitData, "pool"); + setValueFromJson(limit, limitData, "limit"); + if (!pool.isEmpty() && limit > 0) + limits.setJobLimit(pool, limit); + } + return limits; +} + +template<> CommandEchoMode fromJson(const QJsonValue &modeData) +{ + const QString modeString = modeData.toString(); + if (modeString == QLatin1String("silent")) + return CommandEchoModeSilent; + if (modeString == QLatin1String("command-line")) + return CommandEchoModeCommandLine; + if (modeString == QLatin1String("command-line-with-environment")) + return CommandEchoModeCommandLineWithEnvironment; + return CommandEchoModeSummary; +} +} // namespace Internal + +qbs::BuildOptions qbs::BuildOptions::fromJson(const QJsonObject &data) +{ + using namespace Internal; + BuildOptions opt; + setValueFromJson(opt.d->changedFiles, data, "changed-files"); + setValueFromJson(opt.d->filesToConsider, data, "files-to-consider"); + setValueFromJson(opt.d->activeFileTags, data, "active-file-tags"); + setValueFromJson(opt.d->jobLimits, data, "job-limits"); + setValueFromJson(opt.d->maxJobCount, data, "max-job-count"); + setValueFromJson(opt.d->dryRun, data, "dry-run"); + setValueFromJson(opt.d->keepGoing, data, "keep-going"); + setValueFromJson(opt.d->forceTimestampCheck, data, "check-timestamps"); + setValueFromJson(opt.d->forceOutputCheck, data, "check-outputs"); + setValueFromJson(opt.d->logElapsedTime, data, "log-time"); + setValueFromJson(opt.d->echoMode, data, "command-echo-mode"); + setValueFromJson(opt.d->install, data, "install"); + setValueFromJson(opt.d->removeExistingInstallation, data, "clean-install-root"); + setValueFromJson(opt.d->onlyExecuteRules, data, "only-execute-rules"); + setValueFromJson(opt.d->jobLimitsFromProjectTakePrecedence, data, "enforce-project-job-limits"); + return opt; +} + } // namespace qbs diff --git a/src/lib/corelib/tools/buildoptions.h b/src/lib/corelib/tools/buildoptions.h index cea89d0ea..bd0fb22cb 100644 --- a/src/lib/corelib/tools/buildoptions.h +++ b/src/lib/corelib/tools/buildoptions.h @@ -47,6 +47,7 @@ #include <QtCore/qshareddata.h> QT_BEGIN_NAMESPACE +class QJsonObject; class QStringList; QT_END_NAMESPACE @@ -61,6 +62,8 @@ public: BuildOptions &operator=(const BuildOptions &other); ~BuildOptions(); + static BuildOptions fromJson(const QJsonObject &data); + QStringList filesToConsider() const; void setFilesToConsider(const QStringList &files); diff --git a/src/lib/corelib/tools/cleanoptions.cpp b/src/lib/corelib/tools/cleanoptions.cpp index 4fbe77b5d..b888fb1e8 100644 --- a/src/lib/corelib/tools/cleanoptions.cpp +++ b/src/lib/corelib/tools/cleanoptions.cpp @@ -38,6 +38,8 @@ ****************************************************************************/ #include "cleanoptions.h" +#include "jsonhelper.h" + #include <QtCore/qshareddata.h> namespace qbs { @@ -151,4 +153,14 @@ void CleanOptions::setLogElapsedTime(bool log) d->logElapsedTime = log; } +qbs::CleanOptions qbs::CleanOptions::fromJson(const QJsonObject &data) +{ + CleanOptions opt; + using namespace Internal; + setValueFromJson(opt.d->dryRun, data, "dry-run"); + setValueFromJson(opt.d->keepGoing, data, "keep-going"); + setValueFromJson(opt.d->logElapsedTime, data, "log-time"); + return opt; +} + } // namespace qbs diff --git a/src/lib/corelib/tools/cleanoptions.h b/src/lib/corelib/tools/cleanoptions.h index 3f67cf5a5..7827697bb 100644 --- a/src/lib/corelib/tools/cleanoptions.h +++ b/src/lib/corelib/tools/cleanoptions.h @@ -43,6 +43,10 @@ #include <QtCore/qshareddata.h> +QT_BEGIN_NAMESPACE +class QJsonObject; +QT_END_NAMESPACE + namespace qbs { namespace Internal { class CleanOptionsPrivate; } @@ -56,6 +60,8 @@ public: CleanOptions &operator=(CleanOptions &&other) Q_DECL_NOEXCEPT; ~CleanOptions(); + static CleanOptions fromJson(const QJsonObject &data); + bool dryRun() const; void setDryRun(bool dryRun); diff --git a/src/lib/corelib/tools/codelocation.cpp b/src/lib/corelib/tools/codelocation.cpp index 2c6ade3b0..5eff378e1 100644 --- a/src/lib/corelib/tools/codelocation.cpp +++ b/src/lib/corelib/tools/codelocation.cpp @@ -41,9 +41,12 @@ #include <tools/fileinfo.h> #include <tools/persistence.h> #include <tools/qbsassert.h> +#include <tools/stringconstants.h> #include <QtCore/qdatastream.h> #include <QtCore/qdir.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qjsonvalue.h> #include <QtCore/qregexp.h> #include <QtCore/qshareddata.h> #include <QtCore/qstring.h> @@ -134,6 +137,18 @@ QString CodeLocation::toString() const return str; } +QJsonObject CodeLocation::toJson() const +{ + QJsonObject obj; + if (!filePath().isEmpty()) + obj.insert(Internal::StringConstants::filePathKey(), filePath()); + if (line() != -1) + obj.insert(QStringLiteral("line"), line()); + if (column() != -1) + obj.insert(QStringLiteral("column"), column()); + return obj; +} + void CodeLocation::load(Internal::PersistentPool &pool) { const bool isValid = pool.load<bool>(); diff --git a/src/lib/corelib/tools/codelocation.h b/src/lib/corelib/tools/codelocation.h index 3dc8f26b1..3e84ce2d1 100644 --- a/src/lib/corelib/tools/codelocation.h +++ b/src/lib/corelib/tools/codelocation.h @@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE class QDataStream; +class QJsonObject; class QString; QT_END_NAMESPACE @@ -70,6 +71,7 @@ public: bool isValid() const; QString toString() const; + QJsonObject toJson() const; void load(Internal::PersistentPool &pool); void store(Internal::PersistentPool &pool) const; diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp index 185dc0531..fc0b9377e 100644 --- a/src/lib/corelib/tools/error.cpp +++ b/src/lib/corelib/tools/error.cpp @@ -41,7 +41,10 @@ #include "persistence.h" #include "qttools.h" +#include "stringconstants.h" +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> #include <QtCore/qshareddata.h> #include <QtCore/qstringlist.h> @@ -156,6 +159,14 @@ QString ErrorItem::toString() const return str += description(); } +QJsonObject ErrorItem::toJson() const +{ + QJsonObject data; + data.insert(Internal::StringConstants::descriptionProperty(), description()); + data.insert(Internal::StringConstants::locationKey(), codeLocation().toJson()); + return data; +} + class ErrorInfo::ErrorInfoPrivate : public QSharedData { @@ -248,7 +259,7 @@ void ErrorInfo::prepend(const QString &description, const CodeLocation &location * 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 +const QList<ErrorItem> ErrorInfo::items() const { return d->items; } @@ -282,6 +293,17 @@ QString ErrorInfo::toString() const return lines.join(QLatin1Char('\n')); } +QJsonObject ErrorInfo::toJson() const +{ + QJsonObject data; + data.insert(QLatin1String("is-internal"), isInternalError()); + QJsonArray itemsArray; + for (const ErrorItem &item : items()) + itemsArray.append(item.toJson()); + data.insert(QLatin1String("items"), itemsArray); + return data; +} + /*! * \brief Returns true if this error represents a bug in qbs, false otherwise. */ diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h index 4832499af..abad85bad 100644 --- a/src/lib/corelib/tools/error.h +++ b/src/lib/corelib/tools/error.h @@ -47,6 +47,7 @@ #include <QtCore/qshareddata.h> QT_BEGIN_NAMESPACE +class QJsonObject; template <class T> class QList; class QString; class QStringList; @@ -68,6 +69,7 @@ public: QString description() const; CodeLocation codeLocation() const; QString toString() const; + QJsonObject toJson() const; bool isBacktraceItem() const; @@ -97,10 +99,11 @@ public: void append(const ErrorItem &item); void append(const QString &description, const CodeLocation &location = CodeLocation()); void prepend(const QString &description, const CodeLocation &location = CodeLocation()); - QList<ErrorItem> items() const; + const QList<ErrorItem> items() const; bool hasError() const { return !items().empty(); } void clear(); QString toString() const; + QJsonObject toJson() const; bool isInternalError() const; bool hasLocation() const; diff --git a/src/lib/corelib/tools/installoptions.cpp b/src/lib/corelib/tools/installoptions.cpp index 5cddae4ad..93fd54efe 100644 --- a/src/lib/corelib/tools/installoptions.cpp +++ b/src/lib/corelib/tools/installoptions.cpp @@ -36,9 +36,13 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #include "installoptions.h" -#include "language/language.h" -#include <tools/stringconstants.h> + +#include "jsonhelper.h" +#include "stringconstants.h" + +#include <language/language.h> #include <QtCore/qdir.h> #include <QtCore/qshareddata.h> @@ -230,4 +234,17 @@ void InstallOptions::setLogElapsedTime(bool logElapsedTime) d->logElapsedTime = logElapsedTime; } +qbs::InstallOptions qbs::InstallOptions::fromJson(const QJsonObject &data) +{ + using namespace Internal; + InstallOptions opt; + setValueFromJson(opt.d->installRoot, data, "install-root"); + setValueFromJson(opt.d->useSysroot, data, "use-sysroot"); + setValueFromJson(opt.d->removeExisting, data, "clean-install-root"); + setValueFromJson(opt.d->dryRun, data, "dry-run"); + setValueFromJson(opt.d->keepGoing, data, "keep-going"); + setValueFromJson(opt.d->logElapsedTime, data, "log-time"); + return opt; +} + } // namespace qbs diff --git a/src/lib/corelib/tools/installoptions.h b/src/lib/corelib/tools/installoptions.h index 69e00aae5..16511aa3d 100644 --- a/src/lib/corelib/tools/installoptions.h +++ b/src/lib/corelib/tools/installoptions.h @@ -44,6 +44,7 @@ #include <QtCore/qshareddata.h> QT_BEGIN_NAMESPACE +class QJsonObject; class QString; QT_END_NAMESPACE @@ -65,6 +66,8 @@ public: InstallOptions &operator=(InstallOptions &&other) Q_DECL_NOEXCEPT; ~InstallOptions(); + static InstallOptions fromJson(const QJsonObject &data); + static QString defaultInstallRoot(); QString installRoot() const; void setInstallRoot(const QString &installRoot); diff --git a/src/lib/corelib/tools/jsonhelper.h b/src/lib/corelib/tools/jsonhelper.h new file mode 100644 index 000000000..d87802c0a --- /dev/null +++ b/src/lib/corelib/tools/jsonhelper.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBS_JSON_HELPER_H +#define QBS_JSON_HELPER_H + +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qjsonvalue.h> +#include <QtCore/qprocess.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qvariant.h> + +#include <algorithm> +#include <iterator> + +namespace qbs { +namespace Internal { + +template<typename T> inline T fromJson(const QJsonValue &v); +template<> inline bool fromJson(const QJsonValue &v) { return v.toBool(); } +template<> inline int fromJson(const QJsonValue &v) { return v.toInt(); } +template<> inline QString fromJson(const QJsonValue &v) { return v.toString(); } +template<> inline QStringList fromJson(const QJsonValue &v) +{ + const QJsonArray &jsonList = v.toArray(); + QStringList stringList; + std::transform(jsonList.begin(), jsonList.end(), std::back_inserter(stringList), + [](const QVariant &v) { return v.toString(); }); + return stringList; +} +template<> inline QVariantMap fromJson(const QJsonValue &v) { return v.toObject().toVariantMap(); } +template<> inline QProcessEnvironment fromJson(const QJsonValue &v) +{ + const QJsonObject obj = v.toObject(); + QProcessEnvironment env; + for (auto it = obj.begin(); it != obj.end(); ++it) + env.insert(it.key(), it.value().toString()); + return env; +} + +template<typename T> inline void setValueFromJson(T &targetValue, const QJsonObject &data, + const char *jsonProperty) +{ + const QJsonValue v = data.value(QLatin1String(jsonProperty)); + if (!v.isNull()) + targetValue = fromJson<T>(v); +} + +} // namespace Internal +} // namespace qbs + +#endif // Include guard diff --git a/src/lib/corelib/tools/processresult.cpp b/src/lib/corelib/tools/processresult.cpp index 12e45b251..3fb2f8dbc 100644 --- a/src/lib/corelib/tools/processresult.cpp +++ b/src/lib/corelib/tools/processresult.cpp @@ -39,6 +39,9 @@ #include "processresult.h" #include "processresult_p.h" +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> + /*! * \class SetupProjectParameters * \brief The \c ProcessResult class describes a finished qbs process command. @@ -129,4 +132,31 @@ QStringList ProcessResult::stdErr() const return d->stdErr; } +static QJsonValue processErrorToJson(QProcess::ProcessError error) +{ + switch (error) { + case QProcess::FailedToStart: return QLatin1String("failed-to-start"); + case QProcess::Crashed: return QLatin1String("crashed"); + case QProcess::Timedout: return QLatin1String("timed-out"); + case QProcess::WriteError: return QLatin1String("write-error"); + case QProcess::ReadError: return QLatin1String("read-error"); + case QProcess::UnknownError: return QStringLiteral("unknown-error"); + } + return {}; // For dumb compilers. +} + +QJsonObject qbs::ProcessResult::toJson() const +{ + return QJsonObject{ + {QStringLiteral("success"), success()}, + {QStringLiteral("executable-file-path"), executableFilePath()}, + {QStringLiteral("arguments"), QJsonArray::fromStringList(arguments())}, + {QStringLiteral("working-directory"), workingDirectory()}, + {QStringLiteral("error"), processErrorToJson(error())}, + {QStringLiteral("exit-code"), exitCode()}, + {QStringLiteral("stdout"), QJsonArray::fromStringList(stdOut())}, + {QStringLiteral("stderr"), QJsonArray::fromStringList(stdErr())} + }; +} + } // namespace qbs diff --git a/src/lib/corelib/tools/processresult.h b/src/lib/corelib/tools/processresult.h index 2d2ebbfb4..92408aa31 100644 --- a/src/lib/corelib/tools/processresult.h +++ b/src/lib/corelib/tools/processresult.h @@ -46,6 +46,7 @@ #include <QtCore/qprocess.h> QT_BEGIN_NAMESPACE +class QJsonObject; class QString; class QStringList; QT_END_NAMESPACE @@ -65,6 +66,8 @@ public: ProcessResult &operator=(const ProcessResult &other); ~ProcessResult(); + QJsonObject toJson() const; + bool success() const; QString executableFilePath() const; QStringList arguments() const; diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp index 6d817c8f3..41af7b926 100644 --- a/src/lib/corelib/tools/setupprojectparameters.cpp +++ b/src/lib/corelib/tools/setupprojectparameters.cpp @@ -42,6 +42,7 @@ #include <logging/translator.h> #include <tools/buildgraphlocker.h> #include <tools/installoptions.h> +#include <tools/jsonhelper.h> #include <tools/profile.h> #include <tools/qbsassert.h> #include <tools/scripttools.h> @@ -50,6 +51,7 @@ #include <QtCore/qdir.h> #include <QtCore/qfileinfo.h> #include <QtCore/qprocess.h> +#include <QtCore/qjsonobject.h> namespace qbs { namespace Internal { @@ -69,14 +71,14 @@ public: , forceProbeExecution(false) , waitLockBuildGraph(false) , restoreBehavior(SetupProjectParameters::RestoreAndTrackChanges) - , propertyCheckingMode(ErrorHandlingMode::Relaxed) + , propertyCheckingMode(ErrorHandlingMode::Strict) , productErrorMode(ErrorHandlingMode::Strict) { } QString projectFilePath; QString topLevelProfile; - QString configurationName; + QString configurationName = QLatin1String("default"); QString buildRoot; QStringList searchPaths; QStringList pluginPaths; @@ -121,6 +123,47 @@ SetupProjectParameters &SetupProjectParameters::operator=(const SetupProjectPara return *this; } +namespace Internal { +template<> ErrorHandlingMode fromJson(const QJsonValue &v) +{ + if (v.toString() == QLatin1String("relaxed")) + return ErrorHandlingMode::Relaxed; + return ErrorHandlingMode::Strict; +} + +template<> SetupProjectParameters::RestoreBehavior fromJson(const QJsonValue &v) +{ + const QString value = v.toString(); + if (value == QLatin1String("restore-only")) + return SetupProjectParameters::RestoreOnly; + if (value == QLatin1String("resolve-only")) + return SetupProjectParameters::ResolveOnly; + return SetupProjectParameters::RestoreAndTrackChanges; +} +} // namespace Internal + +SetupProjectParameters SetupProjectParameters::fromJson(const QJsonObject &data) +{ + using namespace Internal; + SetupProjectParameters params; + setValueFromJson(params.d->topLevelProfile, data, "top-level-profile"); + setValueFromJson(params.d->configurationName, data, "configuration-name"); + setValueFromJson(params.d->projectFilePath, data, "project-file-path"); + setValueFromJson(params.d->buildRoot, data, "build-root"); + setValueFromJson(params.d->settingsBaseDir, data, "settings-directory"); + setValueFromJson(params.d->overriddenValues, data, "overridden-properties"); + setValueFromJson(params.d->dryRun, data, "dry-run"); + setValueFromJson(params.d->logElapsedTime, data, "log-time"); + setValueFromJson(params.d->forceProbeExecution, data, "force-probe-execution"); + setValueFromJson(params.d->waitLockBuildGraph, data, "wait-lock-build-graph"); + setValueFromJson(params.d->fallbackProviderEnabled, data, "fallback-provider-enabled"); + setValueFromJson(params.d->environment, data, "environment"); + setValueFromJson(params.d->restoreBehavior, data, "restore-behavior"); + setValueFromJson(params.d->propertyCheckingMode, data, "error-handling-mode"); + params.d->productErrorMode = params.d->propertyCheckingMode; + return params; +} + SetupProjectParameters &SetupProjectParameters::operator=(SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default; /*! diff --git a/src/lib/corelib/tools/setupprojectparameters.h b/src/lib/corelib/tools/setupprojectparameters.h index cf3b200cb..a4d090ec5 100644 --- a/src/lib/corelib/tools/setupprojectparameters.h +++ b/src/lib/corelib/tools/setupprojectparameters.h @@ -71,6 +71,8 @@ public: SetupProjectParameters &operator=(const SetupProjectParameters &other); SetupProjectParameters &operator=(SetupProjectParameters &&other) Q_DECL_NOEXCEPT; + static SetupProjectParameters fromJson(const QJsonObject &data); + QString topLevelProfile() const; void setTopLevelProfile(const QString &profile); diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h index cd41f3768..79cbcd125 100644 --- a/src/lib/corelib/tools/stringconstants.h +++ b/src/lib/corelib/tools/stringconstants.h @@ -69,6 +69,7 @@ public: QBS_STRING_CONSTANT(baseNameProperty, "baseName") QBS_STRING_CONSTANT(baseProfileProperty, "baseProfile") QBS_STRING_CONSTANT(buildDirectoryProperty, "buildDirectory") + QBS_STRING_CONSTANT(buildDirectoryKey, "build-directory") QBS_STRING_CONSTANT(builtByDefaultProperty, "builtByDefault") QBS_STRING_CONSTANT(classNameProperty, "className") QBS_STRING_CONSTANT(completeBaseNameProperty, "completeBaseName") @@ -90,11 +91,13 @@ public: static const QString &fileNameProperty() { return fileName(); } static const QString &filePathProperty() { return filePath(); } static const QString &filePathVar() { return filePath(); } + QBS_STRING_CONSTANT(filePathKey, "file-path") QBS_STRING_CONSTANT(fileTagsFilterProperty, "fileTagsFilter") QBS_STRING_CONSTANT(fileTagsProperty, "fileTags") QBS_STRING_CONSTANT(filesProperty, "files") QBS_STRING_CONSTANT(filesAreTargetsProperty, "filesAreTargets") QBS_STRING_CONSTANT(foundProperty, "found") + QBS_STRING_CONSTANT(fullDisplayNameKey, "full-display-name") QBS_STRING_CONSTANT(imports, "imports") static const QString &importsDir() { return imports(); } static const QString &importsProperty() { return imports(); } @@ -106,12 +109,16 @@ public: QBS_STRING_CONSTANT(installPrefixProperty, "installPrefix") QBS_STRING_CONSTANT(installDirProperty, "installDir") QBS_STRING_CONSTANT(installSourceBaseProperty, "installSourceBase") + QBS_STRING_CONSTANT(isEnabledKey, "is-enabled") QBS_STRING_CONSTANT(jobCountProperty, "jobCount") QBS_STRING_CONSTANT(jobPoolProperty, "jobPool") QBS_STRING_CONSTANT(lengthProperty, "length") QBS_STRING_CONSTANT(limitToSubProjectProperty, "limitToSubProject") + QBS_STRING_CONSTANT(locationKey, "location") + QBS_STRING_CONSTANT(messageKey, "message") QBS_STRING_CONSTANT(minimumQbsVersionProperty, "minimumQbsVersion") QBS_STRING_CONSTANT(moduleNameProperty, "moduleName") + QBS_STRING_CONSTANT(modulePropertiesKey, "module-properties") QBS_STRING_CONSTANT(moduleProviders, "moduleProviders") QBS_STRING_CONSTANT(multiplexByQbsPropertiesProperty, "multiplexByQbsProperties") QBS_STRING_CONSTANT(multiplexConfigurationIdProperty, "multiplexConfigurationId") @@ -135,6 +142,7 @@ public: QBS_STRING_CONSTANT(profileProperty, "profile") static const QString &profilesProperty() { return profiles(); } QBS_STRING_CONSTANT(productTypesProperty, "productTypes") + QBS_STRING_CONSTANT(productsKey, "products") QBS_STRING_CONSTANT(qbsSearchPathsProperty, "qbsSearchPaths") QBS_STRING_CONSTANT(referencesProperty, "references") QBS_STRING_CONSTANT(recursiveProperty, "recursive") @@ -149,7 +157,8 @@ public: QBS_STRING_CONSTANT(sourceDirectoryProperty, "sourceDirectory") QBS_STRING_CONSTANT(submodulesProperty, "submodules") QBS_STRING_CONSTANT(targetNameProperty, "targetName") - QBS_STRING_CONSTANT(typeProperty, "type") + static const QString &typeProperty() { return type(); } + QBS_STRING_CONSTANT(type, "type") QBS_STRING_CONSTANT(validateProperty, "validate") QBS_STRING_CONSTANT(versionProperty, "version") QBS_STRING_CONSTANT(versionAtLeastProperty, "versionAtLeast") diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri index f9c6be9a5..89d752671 100644 --- a/src/lib/corelib/tools/tools.pri +++ b/src/lib/corelib/tools/tools.pri @@ -23,6 +23,7 @@ HEADERS += \ $$PWD/iosutils.h \ $$PWD/joblimits.h \ $$PWD/jsliterals.h \ + $$PWD/jsonhelper.h \ $$PWD/launcherinterface.h \ $$PWD/launcherpackets.h \ $$PWD/launchersocket.h \ |