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'"