Browse Source

CMakePresets.json: Add matches condition

Kyle Edwards 4 years ago
parent
commit
5ac8b923f5

+ 16 - 0
Help/manual/cmake-presets.7.rst

@@ -864,6 +864,22 @@ object, it has the following fields:
       A required list of strings to search. This field supports macro
       expansion, and uses short-circuit evaluation.
 
+  ``"matches"``
+
+  ``"notMatches"``
+
+    Indicates that the condition searches for a regular expression in a string.
+    The condition object will have the following additional fields:
+
+    ``string``
+
+      A required string to search. This field supports macro expansion.
+
+    ``regex``
+
+      A required regular expression to search for. This field supports macro
+      expansion.
+
   ``"anyOf"``
 
   ``"allOf"``

+ 48 - 0
Help/manual/presets/schema.json

@@ -1108,6 +1108,54 @@
           ],
           "additionalProperties": false
         },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "matches"
+            },
+            "string": {
+              "type": "string",
+              "description": "A required string to search. This field supports macro expansion."
+            },
+            "regex": {
+              "type": "string",
+              "description": "A required regular expression to search for. This field supports macro expansion."
+            }
+          },
+          "required": [
+            "type",
+            "string",
+            "regex"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "notMatches"
+            },
+            "string": {
+              "type": "string",
+              "description": "A required string to search. This field supports macro expansion."
+            },
+            "regex": {
+              "type": "string",
+              "description": "A required regular expression to search for. This field supports macro expansion."
+            }
+          },
+          "required": [
+            "type",
+            "string",
+            "regex"
+          ],
+          "additionalProperties": false
+        },
         {
           "type": "object",
           "properties": {

+ 20 - 0
Source/cmCMakePresetsFile.cxx

@@ -11,6 +11,8 @@
 
 #include <cm/string_view>
 
+#include "cmsys/RegularExpression.hxx"
+
 #include "cmCMakePresetsFileInternal.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -561,6 +563,24 @@ bool cmCMakePresetsFileInternal::InListCondition::Evaluate(
   return true;
 }
 
+bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate(
+  const std::vector<MacroExpander>& expanders, int version,
+  cm::optional<bool>& out) const
+{
+  std::string str = this->String;
+  CHECK_EXPAND(out, str, expanders, version);
+  std::string regexStr = this->Regex;
+  CHECK_EXPAND(out, regexStr, expanders, version);
+
+  cmsys::RegularExpression regex;
+  if (!regex.compile(regexStr)) {
+    return false;
+  }
+
+  out = regex.find(str);
+  return true;
+}
+
 bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate(
   const std::vector<MacroExpander>& expanders, int version,
   cm::optional<bool>& out) const

+ 10 - 0
Source/cmCMakePresetsFileInternal.h

@@ -81,6 +81,16 @@ public:
   std::vector<std::string> List;
 };
 
+class MatchesCondition : public cmCMakePresetsFile::Condition
+{
+public:
+  bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+                cm::optional<bool>& out) const override;
+
+  std::string String;
+  std::string Regex;
+};
+
 class AnyAllOfCondition : public cmCMakePresetsFile::Condition
 {
 public:

+ 20 - 0
Source/cmCMakePresetsFileReadJSON.cxx

@@ -93,6 +93,16 @@ auto const InListConditionHelper =
     .Bind("list"_s, &cmCMakePresetsFileInternal::InListCondition::List,
           ConditionStringListHelper, true);
 
+auto const MatchesConditionHelper =
+  cmJSONObjectHelper<cmCMakePresetsFileInternal::MatchesCondition,
+                     ReadFileResult>(ReadFileResult::READ_OK,
+                                     ReadFileResult::INVALID_CONDITION, false)
+    .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+    .Bind("string"_s, &cmCMakePresetsFileInternal::MatchesCondition::String,
+          ConditionStringHelper, true)
+    .Bind("regex"_s, &cmCMakePresetsFileInternal::MatchesCondition::Regex,
+          ConditionStringHelper, true);
+
 ReadFileResult SubConditionHelper(
   std::unique_ptr<cmCMakePresetsFile::Condition>& out,
   const Json::Value* value);
@@ -177,6 +187,16 @@ ReadFileResult ConditionHelper(
       return ReadFileResult::READ_OK;
     }
 
+    if (type == "matches" || type == "notMatches") {
+      auto c = cm::make_unique<cmCMakePresetsFileInternal::MatchesCondition>();
+      CHECK_OK(MatchesConditionHelper(*c, value));
+      out = std::move(c);
+      if (type == "notMatches") {
+        out = InvertCondition(std::move(out));
+      }
+      return ReadFileResult::READ_OK;
+    }
+
     if (type == "anyOf" || type == "allOf") {
       auto c =
         cm::make_unique<cmCMakePresetsFileInternal::AnyAllOfCondition>();

+ 57 - 0
Tests/RunCMake/CMakePresets/Conditions.json.in

@@ -180,6 +180,63 @@
         ]
       }
     },
+    {
+      "name": "MatchesTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "aaa",
+        "regex": "^a*$"
+      }
+    },
+    {
+      "name": "MatchesFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "aab",
+        "regex": "^a*$"
+      }
+    },
+    {
+      "name": "MatchesMacroString",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "${presetName}",
+        "regex": "^Matches"
+      }
+    },
+    {
+      "name": "MatchesMacroRegex",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "stuff",
+        "regex": "$env{CONDITION_REGEX}"
+      },
+      "environment": {
+        "CONDITION_REGEX": "^stuf*$"
+      }
+    },
+    {
+      "name": "NotMatchesTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "notMatches",
+        "string": "aab",
+        "regex": "^a*$"
+      }
+    },
+    {
+      "name": "NotMatchesFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "notMatches",
+        "string": "aaa",
+        "regex": "^a*$"
+      }
+    },
     {
       "name": "AnyOfTrue1",
       "inherits": "Base",

+ 1 - 0
Tests/RunCMake/CMakePresets/InvalidRegex-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidRegex: Invalid macro expansion$

+ 15 - 0
Tests/RunCMake/CMakePresets/InvalidRegex.json.in

@@ -0,0 +1,15 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "InvalidRegex",
+      "binaryDir": "${sourceDir}/build",
+      "generator": "@RunCMake_GENERATOR@",
+      "condition": {
+        "type": "matches",
+        "string": "a",
+        "regex": "+"
+      }
+    }
+  ]
+}

+ 4 - 0
Tests/RunCMake/CMakePresets/ListConditions-stdout.txt

@@ -12,6 +12,10 @@ Available configure presets:
   "InListMacroList"
   "InListShortCircuit"
   "NotInListTrue"
+  "MatchesTrue"
+  "MatchesMacroString"
+  "MatchesMacroRegex"
+  "NotMatchesTrue"
   "AnyOfTrue1"
   "AnyOfTrue2"
   "AnyOfShortCircuit"

+ 1 - 0
Tests/RunCMake/CMakePresets/RunCMakeTest.cmake

@@ -117,6 +117,7 @@ run_cmake_presets(NoSuchMacro)
 run_cmake_presets(EnvCycle)
 run_cmake_presets(EmptyEnv)
 run_cmake_presets(EmptyPenv)
+run_cmake_presets(InvalidRegex)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
 run_cmake_presets(ConditionFuture)
 run_cmake_presets(SubConditionNull)