Browse Source

Merge topic 'list-FILTER-command'

0205f882 list: Add FILTER subcommand (#3986)
Brad King 9 years ago
parent
commit
7b1fbcc4b0
29 changed files with 191 additions and 3 deletions
  1. 10 3
      Help/command/list.rst
  2. 5 0
      Help/release/dev/list-FILTER-command.rst
  3. 109 0
      Source/cmListCommand.cxx
  4. 6 0
      Source/cmListCommand.h
  5. 1 0
      Tests/RunCMake/list/EmptyFilterRegex-result.txt
  6. 0 0
      Tests/RunCMake/list/EmptyFilterRegex-stderr.txt
  7. 2 0
      Tests/RunCMake/list/EmptyFilterRegex.cmake
  8. 1 0
      Tests/RunCMake/list/FILTER-NotList-result.txt
  9. 4 0
      Tests/RunCMake/list/FILTER-NotList-stderr.txt
  10. 2 0
      Tests/RunCMake/list/FILTER-NotList.cmake
  11. 1 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidMode-result.txt
  12. 4 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidMode-stderr.txt
  13. 2 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidMode.cmake
  14. 1 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidOperator-result.txt
  15. 4 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidOperator-stderr.txt
  16. 2 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidOperator.cmake
  17. 1 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidRegex-result.txt
  18. 4 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidRegex-stderr.txt
  19. 2 0
      Tests/RunCMake/list/FILTER-REGEX-InvalidRegex.cmake
  20. 1 0
      Tests/RunCMake/list/FILTER-REGEX-TooManyArguments-result.txt
  21. 4 0
      Tests/RunCMake/list/FILTER-REGEX-TooManyArguments-stderr.txt
  22. 2 0
      Tests/RunCMake/list/FILTER-REGEX-TooManyArguments.cmake
  23. 1 0
      Tests/RunCMake/list/FILTER-REGEX-Valid0-result.txt
  24. 2 0
      Tests/RunCMake/list/FILTER-REGEX-Valid0-stderr.txt
  25. 4 0
      Tests/RunCMake/list/FILTER-REGEX-Valid0.cmake
  26. 1 0
      Tests/RunCMake/list/FILTER-REGEX-Valid1-result.txt
  27. 2 0
      Tests/RunCMake/list/FILTER-REGEX-Valid1-stderr.txt
  28. 4 0
      Tests/RunCMake/list/FILTER-REGEX-Valid1.cmake
  29. 9 0
      Tests/RunCMake/list/RunCMakeTest.cmake

+ 10 - 3
Help/command/list.rst

@@ -9,6 +9,7 @@ List operations.
   list(GET <list> <element index> [<element index> ...]
        <output variable>)
   list(APPEND <list> [<element> ...])
+  list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)
   list(FIND <list> <value> <output variable>)
   list(INSERT <list> <element_index> <element> [<element> ...])
   list(REMOVE_ITEM <list> <value> [<value> ...])
@@ -23,6 +24,12 @@ List operations.
 
 ``APPEND`` will append elements to the list.
 
+``FILTER`` will include or remove items from the list that match the
+mode's pattern.
+In ``REGEX`` mode, items will be matched against the given regular expression.
+For more information on regular expressions see also the :command:`string`
+command.
+
 ``FIND`` will return the index of the element specified in the list or -1
 if it wasn't found.
 
@@ -38,9 +45,9 @@ difference is that ``REMOVE_ITEM`` will remove the given items, while
 
 ``SORT`` sorts the list in-place alphabetically.
 
-The list subcommands ``APPEND``, ``INSERT``, ``REMOVE_AT``, ``REMOVE_ITEM``,
-``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create new values for
-the list within the current CMake variable scope.  Similar to the
+The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``REMOVE_AT``,
+``REMOVE_ITEM``, ``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create new
+values for the list within the current CMake variable scope.  Similar to the
 :command:`set` command, the LIST command creates new variable values in the
 current scope, even if the list itself is actually defined in a parent
 scope.  To propagate the results of these operations upwards, use

+ 5 - 0
Help/release/dev/list-FILTER-command.rst

@@ -0,0 +1,5 @@
+list-FILTER-command
+-------------------
+
+* The :command:`list` command gained a ``FILTER`` sub-command to filter
+  list elements by regular expression.

+ 109 - 0
Source/cmListCommand.cxx

@@ -14,6 +14,7 @@
 #include <cmsys/SystemTools.hxx>
 #include "cmAlgorithms.h"
 
+#include <algorithm>
 #include <stdlib.h> // required for atoi
 #include <ctype.h>
 #include <assert.h>
@@ -68,6 +69,10 @@ bool cmListCommand
     {
     return this->HandleReverseCommand(args);
     }
+  if(subCommand == "FILTER")
+    {
+    return this->HandleFilterCommand(args);
+    }
 
   std::string e = "does not recognize sub-command "+subCommand;
   this->SetError(e);
@@ -517,3 +522,107 @@ bool cmListCommand::HandleRemoveAtCommand(
   return true;
 }
 
+//----------------------------------------------------------------------------
+bool cmListCommand::HandleFilterCommand(
+  std::vector<std::string> const& args)
+{
+  if(args.size() < 2)
+    {
+    this->SetError("sub-command FILTER requires a list to be specified.");
+    return false;
+    }
+
+  if(args.size() < 3)
+    {
+    this->SetError("sub-command FILTER requires an operator to be specified.");
+    return false;
+    }
+
+  if(args.size() < 4)
+    {
+    this->SetError("sub-command FILTER requires a mode to be specified.");
+    return false;
+    }
+
+  const std::string& listName = args[1];
+  // expand the variable
+  std::vector<std::string> varArgsExpanded;
+  if ( !this->GetList(varArgsExpanded, listName) )
+    {
+    this->SetError("sub-command FILTER requires list to be present.");
+    return false;
+    }
+
+  const std::string& op = args[2];
+  bool includeMatches;
+  if(op == "INCLUDE")
+    {
+    includeMatches = true;
+    }
+  else if(op == "EXCLUDE")
+    {
+    includeMatches = false;
+    }
+  else
+    {
+    this->SetError("sub-command FILTER does not recognize operator " + op);
+    return false;
+    }
+
+  const std::string& mode = args[3];
+  if(mode == "REGEX")
+    {
+    if(args.size() != 5)
+      {
+      this->SetError("sub-command FILTER, mode REGEX "
+          "requires five arguments.");
+      return false;
+      }
+    return this->FilterRegex(args, includeMatches, listName, varArgsExpanded);
+    }
+
+  this->SetError("sub-command FILTER does not recognize mode " + mode);
+  return false;
+}
+
+//----------------------------------------------------------------------------
+class MatchesRegex {
+public:
+  MatchesRegex(cmsys::RegularExpression& in_regex, bool in_includeMatches)
+    : regex(in_regex), includeMatches(in_includeMatches) {}
+
+  bool operator()(const std::string& target) {
+    return regex.find(target) ^ includeMatches;
+  }
+
+private:
+  cmsys::RegularExpression& regex;
+  const bool includeMatches;
+};
+
+bool cmListCommand::FilterRegex(std::vector<std::string> const& args,
+    bool includeMatches,
+    std::string const& listName,
+    std::vector<std::string>& varArgsExpanded)
+{
+  const std::string& pattern = args[4];
+  cmsys::RegularExpression regex(pattern);
+  if(!regex.is_valid())
+    {
+    std::string error = "sub-command FILTER, mode REGEX ";
+    error += "failed to compile regex \"";
+    error += pattern;
+    error += "\".";
+    this->SetError(error);
+    return false;
+    }
+
+  std::vector<std::string>::iterator argsBegin = varArgsExpanded.begin();
+  std::vector<std::string>::iterator argsEnd = varArgsExpanded.end();
+  std::vector<std::string>::iterator newArgsEnd =
+      std::remove_if(argsBegin, argsEnd, MatchesRegex(regex, includeMatches));
+
+  std::string value = cmJoin(cmMakeRange(argsBegin, newArgsEnd), ";");
+  this->Makefile->AddDefinition(listName, value.c_str());
+  return true;
+}

+ 6 - 0
Source/cmListCommand.h

@@ -58,6 +58,12 @@ protected:
   bool HandleRemoveDuplicatesCommand(std::vector<std::string> const& args);
   bool HandleSortCommand(std::vector<std::string> const& args);
   bool HandleReverseCommand(std::vector<std::string> const& args);
+  bool HandleFilterCommand(std::vector<std::string> const& args);
+  bool FilterRegex(std::vector<std::string> const& args,
+      bool includeMatches,
+      std::string const& listName,
+      std::vector<std::string>& varArgsExpanded
+      );
 
 
   bool GetList(std::vector<std::string>& list, const std::string& var);

+ 1 - 0
Tests/RunCMake/list/EmptyFilterRegex-result.txt

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

+ 0 - 0
Tests/RunCMake/list/EmptyFilterRegex-stderr.txt


+ 2 - 0
Tests/RunCMake/list/EmptyFilterRegex.cmake

@@ -0,0 +1,2 @@
+set(mylist "")
+list(FILTER mylist INCLUDE REGEX "^FILTER_THIS_.+")

+ 1 - 0
Tests/RunCMake/list/FILTER-NotList-result.txt

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

+ 4 - 0
Tests/RunCMake/list/FILTER-NotList-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at FILTER-NotList.cmake:2 \(list\):
+  list sub-command FILTER requires list to be present.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/list/FILTER-NotList.cmake

@@ -0,0 +1,2 @@
+unset(nosuchlist)
+list(FILTER nosuchlist EXCLUDE REGEX "^FILTER_THIS_.+")

+ 1 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidMode-result.txt

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

+ 4 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidMode-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at FILTER-REGEX-InvalidMode.cmake:2 \(list\):
+  list sub-command FILTER does not recognize mode NOOP
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidMode.cmake

@@ -0,0 +1,2 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+list(FILTER mylist EXCLUDE NOOP "^FILTER_THIS_.+")

+ 1 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidOperator-result.txt

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

+ 4 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidOperator-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at FILTER-REGEX-InvalidOperator.cmake:2 \(list\):
+  list sub-command FILTER does not recognize operator RM
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidOperator.cmake

@@ -0,0 +1,2 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+list(FILTER mylist RM REGEX "^FILTER_THIS_.+")

+ 1 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidRegex-result.txt

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

+ 4 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidRegex-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at FILTER-REGEX-InvalidRegex.cmake:2 \(list\):
+  list sub-command FILTER, mode REGEX failed to compile regex "UHOH!\)\(".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/list/FILTER-REGEX-InvalidRegex.cmake

@@ -0,0 +1,2 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+list(FILTER mylist EXCLUDE REGEX "UHOH!)(")

+ 1 - 0
Tests/RunCMake/list/FILTER-REGEX-TooManyArguments-result.txt

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

+ 4 - 0
Tests/RunCMake/list/FILTER-REGEX-TooManyArguments-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at FILTER-REGEX-TooManyArguments.cmake:2 \(list\):
+  list sub-command FILTER, mode REGEX requires five arguments.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/list/FILTER-REGEX-TooManyArguments.cmake

@@ -0,0 +1,2 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+list(FILTER mylist EXCLUDE REGEX "^FILTER_THIS_.+" one_too_many)

+ 1 - 0
Tests/RunCMake/list/FILTER-REGEX-Valid0-result.txt

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

+ 2 - 0
Tests/RunCMake/list/FILTER-REGEX-Valid0-stderr.txt

@@ -0,0 +1,2 @@
+^mylist was: FILTER_THIS_BIT;DO_NOT_FILTER_THIS;thisisanitem;FILTER_THIS_THING
+mylist is: DO_NOT_FILTER_THIS;thisisanitem$

+ 4 - 0
Tests/RunCMake/list/FILTER-REGEX-Valid0.cmake

@@ -0,0 +1,4 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+message("mylist was: ${mylist}")
+list(FILTER mylist EXCLUDE REGEX "^FILTER_THIS_.+")
+message("mylist is: ${mylist}")

+ 1 - 0
Tests/RunCMake/list/FILTER-REGEX-Valid1-result.txt

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

+ 2 - 0
Tests/RunCMake/list/FILTER-REGEX-Valid1-stderr.txt

@@ -0,0 +1,2 @@
+^mylist was: FILTER_THIS_BIT;DO_NOT_FILTER_THIS;thisisanitem;FILTER_THIS_THING
+mylist is: FILTER_THIS_BIT;FILTER_THIS_THING$

+ 4 - 0
Tests/RunCMake/list/FILTER-REGEX-Valid1.cmake

@@ -0,0 +1,4 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+message("mylist was: ${mylist}")
+list(FILTER mylist INCLUDE REGEX "^FILTER_THIS_.+")
+message("mylist is: ${mylist}")

+ 9 - 0
Tests/RunCMake/list/RunCMakeTest.cmake

@@ -1,5 +1,6 @@
 include(RunCMake)
 
+run_cmake(EmptyFilterRegex)
 run_cmake(EmptyGet0)
 run_cmake(EmptyRemoveAt0)
 run_cmake(EmptyInsert-1)
@@ -8,17 +9,25 @@ run_cmake(NoArguments)
 run_cmake(InvalidSubcommand)
 run_cmake(GET-CMP0007-WARN)
 
+run_cmake(FILTER-REGEX-InvalidRegex)
 run_cmake(GET-InvalidIndex)
 run_cmake(INSERT-InvalidIndex)
 run_cmake(REMOVE_AT-InvalidIndex)
 
+run_cmake(FILTER-REGEX-TooManyArguments)
 run_cmake(LENGTH-TooManyArguments)
 run_cmake(REMOVE_DUPLICATES-TooManyArguments)
 run_cmake(REVERSE-TooManyArguments)
 run_cmake(SORT-TooManyArguments)
 
+run_cmake(FILTER-NotList)
 run_cmake(REMOVE_AT-NotList)
 run_cmake(REMOVE_DUPLICATES-NotList)
 run_cmake(REMOVE_ITEM-NotList)
 run_cmake(REVERSE-NotList)
 run_cmake(SORT-NotList)
+
+run_cmake(FILTER-REGEX-InvalidMode)
+run_cmake(FILTER-REGEX-InvalidOperator)
+run_cmake(FILTER-REGEX-Valid0)
+run_cmake(FILTER-REGEX-Valid1)