Index: subversion/include/svn_repos.h =================================================================== --- subversion/include/svn_repos.h (revision 25841) +++ subversion/include/svn_repos.h (working copy) @@ -1014,9 +1014,10 @@ /** * Call @a history_func (with @a history_baton) for each interesting * history location in the lifetime of @a path in @a fs, from the - * youngest of @a end and @a start to the oldest. Only cross - * filesystem copy history if @a cross_copies is @c TRUE. And do all - * of this in @a pool. + * youngest of @a end and @a start to the oldest. Stop processing if + * @a history_func returns @c SVN_ERR_CANCELLED (a la a @c + * svn_cancel_func_t). Only cross filesystem copy history if @a + * cross_copies is @c TRUE. And do all of this in @a pool. * * If @a authz_read_func is non-NULL, then use it (and @a * authz_read_baton) to verify that @a path in @a end is readable; if Index: subversion/svnlook/main.c =================================================================== --- subversion/svnlook/main.c (revision 25842) +++ subversion/svnlook/main.c (working copy) @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -102,6 +103,9 @@ {"help", 'h', 0, N_("show help on a subcommand")}, + {"limit", 'l', 1, + N_("maximum number of history entries")}, + {"no-diff-added", svnlook__no_diff_added, 0, N_("do not print differences for added files")}, @@ -179,7 +183,7 @@ N_("usage: svnlook history REPOS_PATH [PATH_IN_REPOS]\n\n" "Print information about the history of a path in the repository (or\n" "the root directory if no path is supplied).\n"), - {'r', svnlook__show_ids} }, + {'r', svnlook__show_ids, 'l'} }, {"info", subcommand_info, {0}, N_("usage: svnlook info REPOS_PATH\n\n" @@ -239,6 +243,7 @@ const char *txn; svn_boolean_t version; /* --version */ svn_boolean_t show_ids; /* --show-ids */ + apr_size_t limit; /* --limit */ svn_boolean_t help; /* --help */ svn_boolean_t no_diff_deleted; /* --no-diff-deleted */ svn_boolean_t no_diff_added; /* --no-diff-added */ @@ -257,6 +262,7 @@ svn_fs_t *fs; svn_boolean_t is_revision; svn_boolean_t show_ids; + apr_size_t limit; svn_boolean_t no_diff_deleted; svn_boolean_t no_diff_added; svn_boolean_t diff_copy_from; @@ -1327,7 +1333,9 @@ struct print_history_baton { svn_fs_t *fs; - svn_boolean_t show_ids; + svn_boolean_t show_ids; /* whether to show node IDs */ + apr_size_t limit; /* max number of history items */ + apr_size_t count; /* number of history items processed */ }; /* Implements svn_repos_history_func_t interface. Print the history @@ -1360,6 +1368,15 @@ SVN_ERR(svn_cmdline_printf(pool, "%8ld %s\n", revision, path)); } + if (phb->limit > 0) + { + phb->count++; + if (phb->count >= phb->limit) + /* Not L10N'd, since this error is supressed by the caller. */ + return svn_error_create(SVN_ERR_CANCELLED, NULL, + "History entry limit reached"); + } + return SVN_NO_ERROR; } @@ -1371,6 +1388,7 @@ do_history(svnlook_ctxt_t *c, const char *path, svn_boolean_t show_ids, + apr_size_t limit, apr_pool_t *pool) { struct print_history_baton args; @@ -1391,8 +1409,10 @@ copies. */ args.fs = c->fs; args.show_ids = show_ids; + args.limit = limit; + args.count = 0; SVN_ERR(svn_repos_history2(c->fs, path, print_history, &args, - NULL, NULL, 0, c->rev_id, 1, pool)); + NULL, NULL, 0, c->rev_id, TRUE, pool)); return SVN_NO_ERROR; } @@ -1713,7 +1733,7 @@ path = opt_state->arg1; SVN_ERR(get_ctxt_baton(&c, opt_state, pool)); - SVN_ERR(do_history(c, path, opt_state->show_ids, pool)); + SVN_ERR(do_history(c, path, opt_state->show_ids, opt_state->limit, pool)); return SVN_NO_ERROR; } @@ -2002,6 +2022,25 @@ opt_state.show_ids = TRUE; break; + case 'l': + { + char *end; + opt_state.limit = strtol(opt_arg, &end, 10); + if (end == opt_arg || *end != '\0') + { + err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, + _("Non-numeric limit argument given")); + return svn_cmdline_handle_exit_error(err, pool, "svnlook: "); + } + if (opt_state.limit <= 0) + { + err = svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL, + _("Argument to --limit must be positive")); + return svn_cmdline_handle_exit_error(err, pool, "svnlook: "); + } + } + break; + case svnlook__no_diff_deleted: opt_state.no_diff_deleted = TRUE; break; Index: subversion/libsvn_repos/rev_hunt.c =================================================================== --- subversion/libsvn_repos/rev_hunt.c (revision 25841) +++ subversion/libsvn_repos/rev_hunt.c (working copy) @@ -21,6 +21,7 @@ #include "svn_private_config.h" #include "svn_pools.h" #include "svn_error.h" +#include "svn_error_codes.h" #include "svn_fs.h" #include "svn_repos.h" #include "svn_string.h" @@ -251,6 +252,7 @@ get rid of the old history until we use it to get the new, so we alternate back and forth between our subpools. */ apr_pool_t *tmppool; + svn_error_t *err; SVN_ERR(svn_fs_history_prev(&history, history, cross_copies, newpool)); @@ -281,8 +283,19 @@ } /* Call the user-provided callback function. */ - SVN_ERR(history_func(history_baton, history_path, - history_rev, newpool)); + err = history_func(history_baton, history_path, history_rev, newpool); + if (err) + { + if (err->apr_err == SVN_ERR_CANCELLED) + { + svn_error_clear(err); + goto cleanup; + } + else + { + return err; + } + } /* We're done with the old history item, so we can clear its pool, and then toggle our notion of "the old pool". */ @@ -293,6 +306,7 @@ } while (history); /* shouldn't hit this */ + cleanup: svn_pool_destroy(oldpool); svn_pool_destroy(newpool); return SVN_NO_ERROR;