Author: stsp Date: Tue Sep 11 16:58:40 2012 New Revision: 1383480 URL: http://svn.apache.org/viewvc?rev=1383480&view=rev Log: Allow mulitple --search options with 'svn log'. Log messages are shown if they match any of the provided search patterns (i.e. logical OR).
This will be extended later with a new --search-and option to allow for AND/OR combining of search terms (idea from philip). * subversion/svn/cl.h (svn_cl__search_pattern_t): New data type. (svn_cl__opt_state_t): Replace search_pattern and case_insensitive_search with an array of svn_cl__search_pattern_t objects. * subversion/svn/log-cmd.c (log_receiver_baton): As above, search_pattern and case_insensitive_search become an array of search patterns. (match_search_patterns): New helper to match multiple patterns. (log_entry_receiver, log_entry_receiver_xml): Call the new helper. (svn_cl__log): Track changes made to log_receiver_baton. * subversion/svn/main.c (svn_cl__cmd_table): Document the effect of multiple --search options in the output of 'svn help log'. (add_search_pattern): New helper to create an array of search patterns from option arguments. (sub_main): Use new helper for processing --search and --isearch options. * subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout: Adjust to new output of 'svn help log'. * subversion/tests/cmdline/log_tests.py (log_search): Add a simple test case for multiple --search options. Modified: subversion/trunk/subversion/svn/cl.h 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/cl.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1383480&r1=1383479&r2=1383480&view=diff ============================================================================== --- subversion/trunk/subversion/svn/cl.h (original) +++ subversion/trunk/subversion/svn/cl.h Tue Sep 11 16:58:40 2012 @@ -108,6 +108,12 @@ typedef enum svn_cl__accept_t svn_cl__accept_t svn_cl__accept_from_word(const char *word); +/* --search and --isearch option values */ +typedef struct svn_cl__search_pattern_t { + const char *pattern; /* glob syntax */ + svn_boolean_t case_insensitive; +} svn_cl__search_pattern_t; + /*** Mergeinfo flavors. ***/ @@ -236,8 +242,7 @@ typedef struct svn_cl__opt_state_t svn_boolean_t show_diff; /* produce diff output (maps to --diff) */ svn_boolean_t allow_mixed_rev; /* Allow operation on mixed-revision WC */ svn_boolean_t include_externals; /* Recurses (in)to file & dir externals */ - const char *search_pattern; /* pattern argument for --search */ - svn_boolean_t case_insensitive_search; /* perform case-insensitive search */ + apr_array_header_t* search_patterns; /* pattern arguments for --search */ svn_wc_conflict_resolver_func2_t conflict_func; void *conflict_baton; Modified: subversion/trunk/subversion/svn/log-cmd.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/log-cmd.c?rev=1383480&r1=1383479&r2=1383480&view=diff ============================================================================== --- subversion/trunk/subversion/svn/log-cmd.c (original) +++ subversion/trunk/subversion/svn/log-cmd.c Tue Sep 11 16:58:40 2012 @@ -71,10 +71,9 @@ struct log_receiver_baton /* Stack which keeps track of merge revision nesting, using svn_revnum_t's */ apr_array_header_t *merge_stack; - /* Log message search pattern. Log entries will only be shown if the author, - * the log message, or a changed path matches this pattern. */ - const char *search_pattern; - svn_boolean_t case_insensitive_search; + /* Log message search patterns. Log entries will only be shown if the author, + * the log message, or a changed path matches one of these patterns. */ + apr_array_header_t *search_patterns; /* Pool for persistent allocations. */ apr_pool_t *pool; @@ -203,6 +202,38 @@ match_search_pattern(const char *search_ return FALSE; } +/* Match all search patterns in SEARCH_PATTERNS against AUTHOR, DATE, MESSAGE, + * and CHANGED_PATHS. Return TRUE if any pattern matches, else FALSE. + * SCRACH_POOL is used for temporary allocations. */ +static svn_boolean_t +match_search_patterns(apr_array_header_t *search_patterns, + const char *author, + const char *date, + const char *message, + apr_hash_t *changed_paths, + apr_pool_t *scratch_pool) +{ + int i; + svn_boolean_t match = FALSE; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + for (i = 0; i < search_patterns->nelts; i++) + { + svn_cl__search_pattern_t p; + + 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); + if (match) + break; + } + svn_pool_destroy(iterpool); + + return match; +} /* Implement `svn_log_entry_receiver_t', printing the logs in * a human-readable and machine-parseable format. @@ -320,10 +351,9 @@ log_entry_receiver(void *baton, if (! lb->omit_log_message && message == NULL) message = ""; - if (lb->search_pattern && - ! match_search_pattern(lb->search_pattern, author, date, message, - log_entry->changed_paths2, - lb->case_insensitive_search, pool)) + if (lb->search_patterns && + ! match_search_patterns(lb->search_patterns, author, date, message, + log_entry->changed_paths2, pool)) { if (log_entry->has_children) APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision; @@ -505,10 +535,9 @@ log_entry_receiver_xml(void *baton, } /* Match search pattern before XML-escaping. */ - if (lb->search_pattern && - ! match_search_pattern(lb->search_pattern, author, date, message, - log_entry->changed_paths2, - lb->case_insensitive_search, pool)) + if (lb->search_patterns && + ! match_search_patterns(lb->search_patterns, author, date, message, + log_entry->changed_paths2, pool)) { if (log_entry->has_children) APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision; @@ -740,8 +769,7 @@ svn_cl__log(apr_getopt_t *os, : opt_state->depth; lb.diff_extensions = opt_state->extensions; lb.merge_stack = apr_array_make(pool, 0, sizeof(svn_revnum_t)); - lb.search_pattern = opt_state->search_pattern; - lb.case_insensitive_search = opt_state->case_insensitive_search; + lb.search_patterns = opt_state->search_patterns; lb.pool = pool; if (opt_state->xml) Modified: subversion/trunk/subversion/svn/main.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/main.c?rev=1383480&r1=1383479&r2=1383480&view=diff ============================================================================== --- subversion/trunk/subversion/svn/main.c (original) +++ subversion/trunk/subversion/svn/main.c Tue Sep 11 16:58:40 2012 @@ -690,6 +690,8 @@ const svn_opt_subcommand_desc2_t svn_cl_ " ? matches any single character\n" " * 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" " 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" @@ -1579,6 +1581,23 @@ svn_cl__check_cancel(void *baton) return SVN_NO_ERROR; } +/* Add a --search or --isearch argument to OPT_STATE. */ +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) +{ + svn_cl__search_pattern_t p; + + if (opt_state->search_patterns == NULL) + opt_state->search_patterns = apr_array_make( + result_pool, 1, + sizeof(svn_cl__search_pattern_t)); + p.pattern = pattern; + p.case_insensitive = case_insensitive; + APR_ARRAY_PUSH(opt_state->search_patterns, svn_cl__search_pattern_t) = p; +} /*** Main. ***/ @@ -2130,11 +2149,10 @@ sub_main(int argc, const char *argv[], a opt_state.diff.properties_only = TRUE; break; case opt_search: - opt_state.search_pattern = opt_arg; + add_search_pattern(&opt_state, opt_arg, FALSE, pool); break; case opt_isearch: - opt_state.search_pattern = opt_arg; - opt_state.case_insensitive_search = TRUE; + add_search_pattern(&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=1383480&r1=1383479&r2=1383480&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 16:58:40 2012 @@ -37,6 +37,8 @@ usage: 1. log [PATH][@REV] ? matches any single character * 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. 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. Modified: subversion/trunk/subversion/tests/cmdline/log_tests.py URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/log_tests.py?rev=1383480&r1=1383479&r2=1383480&view=diff ============================================================================== --- subversion/trunk/subversion/tests/cmdline/log_tests.py (original) +++ subversion/trunk/subversion/tests/cmdline/log_tests.py Tue Sep 11 16:58:40 2012 @@ -2304,6 +2304,16 @@ def log_search(sbox): log_chain = parse_log_output(output) check_log_chain(log_chain, [7, 6, 3]) + # multi-pattern search + exit_code, output, err = svntest.actions.run_and_verify_svn( + None, None, [], 'log', + '--search', 'for revision 3', + '--search', 'for revision 6', + '--search', 'for revision 7') + + log_chain = parse_log_output(output) + check_log_chain(log_chain, [7, 6, 3]) + @SkipUnless(server_has_mergeinfo) def merge_sensitive_log_with_search(sbox): "test 'svn log -g --search'"