Author: stsp
Date: Tue Sep 11 18:35:51 2012
New Revision: 1383518

URL: http://svn.apache.org/viewvc?rev=1383518&view=rev
Log:
Add a new --search-and option to allow combination of search patterns.
Combined search patterns match in union (i.e. logical AND).

Suggested by: philip

* subversion/svn/log-cmd.c
  (match_search_patterns): Match search patterns as groups. Any group can
   match a log message, but all patterns from a group must match.
   Search pattern data passed in from the main code is now a nested array.
   The first-level array represents pattern groups, each of which contains
   an array of search patterns.

* subversion/svn/main.c
  (svn_cl__longopt_t, svn_cl__options): Add opt_search_and and opt_isearch_and.
  (svn_cl__cmd_table): Explain combining of search patterns in 'svn help log'
   and add the corresponding options to 'svn log'.
  (add_search_pattern): Replaced by...
  (add_search_pattern_group, add_search_pattern_to_latest_group): ... these
   new helper functions for grouping patterns as required.
  (sub_main): Use new helpers to process the various --search option variants.

* subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout: Adjust
   for changed 'svn help log' output.

* subversion/tests/cmdline/log_tests.py
  (log_search): Add a simple test case for combined search patterns.

Modified:
    subversion/trunk/subversion/svn/log-cmd.c
    subversion/trunk/subversion/svn/main.c
    
subversion/trunk/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
    subversion/trunk/subversion/tests/cmdline/log_tests.py

Modified: subversion/trunk/subversion/svn/log-cmd.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/log-cmd.c?rev=1383518&r1=1383517&r2=1383518&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/log-cmd.c (original)
+++ subversion/trunk/subversion/svn/log-cmd.c Tue Sep 11 18:35:51 2012
@@ -219,14 +219,27 @@ match_search_patterns(apr_array_header_t
 
   for (i = 0; i < search_patterns->nelts; i++)
     {
-      svn_cl__search_pattern_t p;
+      apr_array_header_t *pattern_group;
+      int j;
 
-      svn_pool_clear(iterpool);
-      
-      p = APR_ARRAY_IDX(search_patterns, i, svn_cl__search_pattern_t);
-      match = match_search_pattern(p.pattern, author, date,
-                                   message, changed_paths,
-                                   p.case_insensitive, iterpool);
+      pattern_group = APR_ARRAY_IDX(search_patterns, i, apr_array_header_t *);
+
+      /* All patterns within the group must match. */
+      for (j = 0; j < pattern_group->nelts; j++)
+        {
+          svn_cl__search_pattern_t p;
+
+          svn_pool_clear(iterpool);
+          
+          p = APR_ARRAY_IDX(pattern_group, j, svn_cl__search_pattern_t);
+          match = match_search_pattern(p.pattern, author, date,
+                                       message, changed_paths,
+                                       p.case_insensitive, iterpool);
+          if (!match)
+            break;
+        }
+
+      match = (match && j == pattern_group->nelts);
       if (match)
         break;
     }

Modified: subversion/trunk/subversion/svn/main.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/main.c?rev=1383518&r1=1383517&r2=1383518&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/main.c (original)
+++ subversion/trunk/subversion/svn/main.c Tue Sep 11 18:35:51 2012
@@ -131,6 +131,8 @@ typedef enum svn_cl__longopt_t {
   opt_include_externals,
   opt_search,
   opt_isearch,
+  opt_search_and,
+  opt_isearch_and,
 } svn_cl__longopt_t;
 
 
@@ -375,11 +377,21 @@ const apr_getopt_option_t svn_cl__option
                        "                             "
                        "fixed revision. (See the svn:externals property)")},
   {"search", opt_search, 1,
-                       N_("use ARG as search pattern (glob syntax)")},
+                       N_("use ARG as search pattern (glob syntax)\n"
+                       "                             "
+                       "Multiple search patterns match independently.")},
 
   {"isearch", opt_isearch, 1,
                        N_("like --search, but case-insensitive")}, 
 
+  {"search-and", opt_search_and, 1,
+                       N_("combine ARG with any previous search pattern\n"
+                       "                             "
+                       "Combined search patterns match unitedly.")},
+
+  {"isearch-and", opt_isearch_and, 1,
+                       N_("like --search-and, but case-insensitive")}, 
+
   /* Long-opt Aliases
    *
    * These have NULL desriptions, but an option code that matches some
@@ -691,7 +703,10 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "      *      matches a sequence of arbitrary characters\n"
      "      [...]  matches any of the characters listed inside the brackets\n"
      "  If multiple --search options are provided, a log message is shown if\n"
-     "  it matches any of the provided search patterns.\n"
+     "  it matches any of the provided search patterns. If the --search-and\n"
+     "  option is used, that option's argument is combined with the pattern\n"
+     "  from any previous --search or --search-and option, and a log message\n"
+     "  is shown only if it matches any of the combined search patterns.\n"
      "  If --limit is used in combination with --search, --limit restricts 
the\n"
      "  number of log messages searched, rather than restricting the output\n"
      "  to a particular number of matching log messages.\n"
@@ -724,7 +739,7 @@ const svn_opt_subcommand_desc2_t svn_cl_
     {'r', 'q', 'v', 'g', 'c', opt_targets, opt_stop_on_copy, opt_incremental,
      opt_xml, 'l', opt_with_all_revprops, opt_with_no_revprops, 
opt_with_revprop,
      opt_depth, opt_diff, opt_diff_cmd, opt_internal_diff, 'x', opt_search,
-     opt_isearch},
+     opt_search_and, opt_isearch, opt_isearch_and},
     {{opt_with_revprop, N_("retrieve revision property ARG")},
      {'c', N_("the change made in revision ARG")}} },
 
@@ -1581,22 +1596,52 @@ svn_cl__check_cancel(void *baton)
     return SVN_NO_ERROR;
 }
 
-/* Add a --search or --isearch argument to OPT_STATE. */
+/* Add a --search or --isearch argument to OPT_STATE.
+ * These options start a new search pattern group. */
+static void
+add_search_pattern_group(svn_cl__opt_state_t *opt_state,
+                         const char *pattern,
+                         svn_boolean_t case_insensitive,
+                         apr_pool_t *result_pool)
+{
+  svn_cl__search_pattern_t p;
+  apr_array_header_t *group = NULL;
+
+  if (opt_state->search_patterns == NULL)
+    opt_state->search_patterns = apr_array_make(result_pool, 1,
+                                                sizeof(apr_array_header_t *));
+
+  group = apr_array_make(result_pool, 1, sizeof(svn_cl__search_pattern_t));
+  p.pattern = pattern;
+  p.case_insensitive = case_insensitive;
+  APR_ARRAY_PUSH(group, svn_cl__search_pattern_t) = p;
+  APR_ARRAY_PUSH(opt_state->search_patterns, apr_array_header_t *) = group;
+}
+
+/* Add a --search-and or --isearch-and argument to OPT_STATE.
+ * These patterns are added to an existing pattern group, if any. */
 static void
-add_search_pattern(svn_cl__opt_state_t *opt_state,
-                   const char *pattern,
-                   svn_boolean_t case_insensitive,
-                   apr_pool_t *result_pool)
+add_search_pattern_to_latest_group(svn_cl__opt_state_t *opt_state,
+                                   const char *pattern,
+                                   svn_boolean_t case_insensitive,
+                                   apr_pool_t *result_pool)
 {
   svn_cl__search_pattern_t p;
+  apr_array_header_t *group;
 
   if (opt_state->search_patterns == NULL)
-    opt_state->search_patterns = apr_array_make(
-                                   result_pool, 1,
-                                   sizeof(svn_cl__search_pattern_t));
+    {
+      add_search_pattern_group(opt_state, pattern, case_insensitive,
+                               result_pool);
+      return;
+    }
+
+  group = APR_ARRAY_IDX(opt_state->search_patterns,
+                        opt_state->search_patterns->nelts - 1,
+                        apr_array_header_t *);
   p.pattern = pattern;
   p.case_insensitive = case_insensitive;
-  APR_ARRAY_PUSH(opt_state->search_patterns, svn_cl__search_pattern_t) = p;
+  APR_ARRAY_PUSH(group, svn_cl__search_pattern_t) = p;
 }
 
 
@@ -2149,10 +2194,15 @@ sub_main(int argc, const char *argv[], a
         opt_state.diff.properties_only = TRUE;
         break;
       case opt_search:
-        add_search_pattern(&opt_state, opt_arg, FALSE, pool);
+        add_search_pattern_group(&opt_state, opt_arg, FALSE, pool);
         break;
       case opt_isearch:
-        add_search_pattern(&opt_state, opt_arg, TRUE, pool);
+        add_search_pattern_group(&opt_state, opt_arg, TRUE, pool);
+        break;
+      case opt_search_and:
+        add_search_pattern_to_latest_group(&opt_state, opt_arg, FALSE, pool);
+      case opt_isearch_and:
+        add_search_pattern_to_latest_group(&opt_state, opt_arg, TRUE, pool);
         break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away

Modified: 
subversion/trunk/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1383518&r1=1383517&r2=1383518&view=diff
==============================================================================
--- 
subversion/trunk/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
 (original)
+++ 
subversion/trunk/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
 Tue Sep 11 18:35:51 2012
@@ -38,7 +38,10 @@ usage: 1. log [PATH][@REV]
       *      matches a sequence of arbitrary characters
       [...]  matches any of the characters listed inside the brackets
   If multiple --search options are provided, a log message is shown if
-  it matches any of the provided search patterns.
+  it matches any of the provided search patterns. If the --search-and
+  option is used, that option's argument is combined with the pattern
+  from any previous --search or --search-and option, and a log message
+  is shown only if it matches any of the combined search patterns.
   If --limit is used in combination with --search, --limit restricts the
   number of log messages searched, rather than restricting the output
   to a particular number of matching log messages.
@@ -113,7 +116,11 @@ Valid options:
                                 -p (--show-c-function):
                                    Show C function name in diff output.
   --search ARG             : use ARG as search pattern (glob syntax)
+                             Multiple search patterns match independently.
+  --search-and ARG         : combine ARG with any previous search pattern
+                             Combined search patterns match unitedly.
   --isearch ARG            : like --search, but case-insensitive
+  --isearch-and ARG        : like --search-and, but case-insensitive
 
 Global options:
   --username ARG           : specify a username ARG

Modified: subversion/trunk/subversion/tests/cmdline/log_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/log_tests.py?rev=1383518&r1=1383517&r2=1383518&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/log_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/log_tests.py Tue Sep 11 18:35:51 
2012
@@ -2314,6 +2314,33 @@ def log_search(sbox):
   log_chain = parse_log_output(output)
   check_log_chain(log_chain, [7, 6, 3])
 
+  # combined pattern search
+  exit_code, output, err = svntest.actions.run_and_verify_svn(
+                             None, None, [], 'log', '--verbose',
+                             '--search', 'for revision 8',
+                             '--search-and', 'test the code',
+                             '--search', 'for revision 7',
+                             '--search-and', 'this won\'t match ',
+                             '--search', 'psi',
+                             '--search-and', 'multiple lines',
+                             '--search-and', 'revision 6') # don't match r4
+
+  log_chain = parse_log_output(output)
+  check_log_chain(log_chain, [8, 6])
+
+  exit_code, output, err = svntest.actions.run_and_verify_svn(
+                             None, None, [], 'log', '--verbose',
+                             '--search', 'for revision 8',
+                             '--search-and', 'this won\'t match ',
+                             '--search', 'for revision 7',
+                             '--search', 'psi',
+                             '--search-and', 'multiple lines',
+                             '--search-and', 'revision 4') # don't match r6
+
+  log_chain = parse_log_output(output)
+  check_log_chain(log_chain, [7, 4])
+
+
 @SkipUnless(server_has_mergeinfo)
 def merge_sensitive_log_with_search(sbox):
   "test 'svn log -g --search'"


Reply via email to