#include "cmInstrumentationQuery.h" #include #include #include #include #include #include #include #include #include "cmJSONHelpers.h" #include "cmStringAlgorithms.h" std::vector const cmInstrumentationQuery::OptionString{ "staticSystemInformation", "dynamicSystemInformation", "captureOutput", "processMetrics", "compileTrace", "cdashSubmit", "cdashVerbose", "trace" }; std::vector const cmInstrumentationQuery::HookString{ "postGenerate", "preBuild", "postBuild", "preCMakeBuild", "postCMakeBuild", "postCTest", "postCMakeInstall", "postCMakeWorkflow", "prepareForCDash", "manual" }; namespace ErrorMessages { using ErrorGenerator = std::function; ErrorGenerator ErrorGeneratorBuilder(std::string const& errorMessage) { return [errorMessage](Json::Value const* value, cmJSONState* state) -> void { state->AddErrorAtValue(errorMessage, value); }; }; static ErrorGenerator InvalidArray = ErrorGeneratorBuilder("Invalid Array"); JsonErrors::ErrorGenerator InvalidRootQueryObject( JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) { return JsonErrors::INVALID_NAMED_OBJECT( [](Json::Value const*, cmJSONState*) -> std::string { return "root object"; })(errorType, extraFields); } }; using JSONHelperBuilder = cmJSONHelperBuilder; using Version = cmInstrumentationQuery::Version; template static std::function EnumHelper( std::vector const toString, std::string const& type) { return [toString, type](E& out, Json::Value const* value, cmJSONState* state) -> bool { for (size_t i = 0; i < toString.size(); ++i) { if (value->asString() == toString[i]) { out = (E)i; return true; } } state->AddErrorAtValue( cmStrCat("Not a valid ", type, ": \"", value->asString(), '"'), value); return false; }; } static auto const OptionHelper = EnumHelper( cmInstrumentationQuery::OptionString, "option"); static auto const OptionListHelper = JSONHelperBuilder::Vector( ErrorMessages::InvalidArray, OptionHelper); static auto const HookHelper = EnumHelper( cmInstrumentationQuery::HookString, "hook"); static auto const HookListHelper = JSONHelperBuilder::Vector( ErrorMessages::InvalidArray, HookHelper); static auto const CallbackHelper = JSONHelperBuilder::String(); static auto const CallbackListHelper = JSONHelperBuilder::Vector( ErrorMessages::InvalidArray, CallbackHelper); JsonErrors::ErrorGenerator InvalidVersionObject( JsonErrors::ObjectError errorType, Json::Value::Members const& extraFields) { return JsonErrors::INVALID_NAMED_OBJECT( [](Json::Value const*, cmJSONState*) -> std::string { return "version object"; })(errorType, extraFields); } static auto const VersionObjectHelper = JSONHelperBuilder::Object(InvalidVersionObject, false) .Bind("major"_s, &Version::Major, JSONHelperBuilder::Int(), true) .Bind("minor"_s, &Version::Minor, JSONHelperBuilder::Int(), false); bool VersionHelper(Version& out, Json::Value const* value, cmJSONState* state) { out.Minor = 0; if (value->isInt()) { out.Major = value->asInt(); } else if (value->isObject()) { if (!VersionObjectHelper(out, value, state)) { return false; } } else { state->AddErrorAtValue("Version must be an integer or object", value); return false; } return true; } using QueryRoot = cmInstrumentationQuery::QueryJSONRoot; static auto const QueryRootHelper = JSONHelperBuilder::Object(ErrorMessages::InvalidRootQueryObject, false) .Bind("version"_s, &QueryRoot::version, VersionHelper, true) .Bind("options"_s, &QueryRoot::options, OptionListHelper, false) .Bind("hooks"_s, &QueryRoot::hooks, HookListHelper, false) .Bind("callbacks"_s, &QueryRoot::callbacks, CallbackListHelper, false); static auto const QueryRootVersionOnlyHelper = JSONHelperBuilder::Object(ErrorMessages::InvalidRootQueryObject, true) .Bind("version"_s, &QueryRoot::version, VersionHelper, true); bool cmInstrumentationQuery::ReadJSON(std::string const& filename, std::string& errorMessage, std::set