[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] V3, diff summarize (preview) without text deltas

From: Martin Hauner <martin.hauner_at_gmx.net>
Date: 2005-10-02 14:52:23 CEST

Hi,

attached is the third version of the diff summarize api call that doesn't
produce text deltas (which helps to build a nice diff interface in a gui
client or at least that's why i did write it :) This is also partially
issue #2015 (without -v).

I have fixed/updated it based on Peter Lundblads nice review and cleaned
up a few other things.

I have also fixed the code duplication with the normal diff code that I
had originally planned for another patch (that added another 25 KByte to
the patch ;)

Since the previous version of the patch is out of everyones mind remember
that

* this is an api only patch. For easier review I attached another small
   patch to run summarize from the command line, ie. svn diff -s.

* the summarize currently handles only the repository <-> repository case.

Happy reviewing :)

-- 
Martin
Subcommander, http://subcommander.tigris.org
a cross platform Win32/Unix/MacOSX subversion gui client & diff/merge tool.

Added new client api calls svn_diff_summarize/svn_diff_summarize_peg.
A diff summary lists the changed items without creating text deltas.

To achieve this the svn_ra__vtable_t do_diff function got a new boolean
parameter text_deltas that is finally passed to svn_repos_begin_report
to run the diff without creating text deltas.

* subversion/include/svn_ra.h
  (svn_ra_do_diff2): new method, similar to svn_ra_do_diff but with a
  new text_deltas boolean parameter.
  (svn_ra_do_diff): updated method description, deprecated.
  (svn_ra_plugin_t): added text_deltas parameter to do_diff function.

* subversion/libsvn_ra/ra_loader.h
  (svn_ra__vtable_t): added text_deltas parameter to do_diff function.

* subversion/libsvn_ra/ra_loader.c
  (svn_ra_do_diff2): new method.
  (svn_ra_do_diff): call svn_ra_do_diff2 with TRUE for the text_deltas
  parameter of do_diff.
  
* subversion/libsvn_ra/wrapper_template.h
  (compat_do_diff): added text_deltas parameter, pass new parameter to
  do_diff.

* subversion/include/svn_client.h
  (svn_client_diff_summarize,svn_client_diff_summarize_peg): new api
  methods.
  (svn_diff_summarize_func_t): new callback type used by
  svn_client_diff_summarize and svn_client_diff_summarize_peg.
  (svn_diff_summarize_t): new struct used by svn_diff_summarize_func_t.
  (svn_diff_summarize_kind_t): new enum type for svn_diff_summarize_t.

* subversion/libsvn_client/client.h
  (svn_client__get_diff_summary_editor): new method, implemented in
  subversion/libsvn_client/repos_diff_summarize.c.
  
* subversion/libsvn_client/repos_diff_summarize.c
  new file, the implementation of the diff summary svn_delta_editor_t.

* subversion/libsvn_client/diff.c
  (diff_parameters,diff_paths,diff_repos_repos): new helper structures
  used by the new helper functions.
  (check_paths,diff_prepare_repos_repos): new helper functions used to
  remove most of the code duplication between diff and diff summarize.
  (diff_summarize_repos_repos): do diff summarize between two repository
  paths.
  (do_diff_summarize): new function, do diff summarize without peg
  revision.
  (do_diff_summarize_peg): new function, do diff summarize with peg
  revision.
  (svn_client_diff_summarize): new function, implemementation of the
  public diff summarize api function without peg revision.
  (svn_client_diff_summarize_peg): new function, implemementation of
  the public diff summarize peg api function.
  (diff_repos_repos): replaced diff parameters with diff_parameters
  structure. Removed code duplication with diff_summarize_repos_repos
  by using the new helper functions.
  (do_diff,do_diff_peg): replaced diff parameters with diff_parameters
  structure. Removed code duplication with do_diff_summarize and
  do_diff_summarize_peg by using the new helper functions.
  (svn_client_diff3,svn_client_diff_peg3): updated to changed signature
  of do_diff.
  
* subversion/libsvn_ra_dav/ra_dav.h
  (svn_ra_dav__do_diff): added text_deltas boolean parameter.

* subversion/libsvn_ra_dav/fetch.c
  (svn_ra_dav__do_diff): added text_deltas boolean parameter. Passing
  new parameter to make_reporter.

* subversion/libsvn_ra_local/ra_plugin.c
  (svn_ra_local__do_diff): added text_deltas boolean parameter. Passing
  new parameter to make_reporter.

* subversion/libsvn_ra_svn/client.c
  (ra_svn_diff): added text_deltas boolean parameter. Added text_deltas
  to "diff" cmd.

* subversion/libsvn_ra_svn/protocol
  added text-deltas parameter to diff command description.
  
* subversion/svnserve/serve.c
  (diff): added parsing of the new text_deltas parameter. Passing new
  parameter to accept_report.

Index: subversion/libsvn_ra/wrapper_template.h
===================================================================
--- subversion/libsvn_ra/wrapper_template.h (revision 16385)
+++ subversion/libsvn_ra/wrapper_template.h (working copy)
@@ -312,8 +312,8 @@
   void *baton2;
   
   SVN_ERR (VTBL.do_diff (session_baton, &reporter2, &baton2, revision,
- diff_target, recurse, ignore_ancestry, versus_url,
- diff_editor, diff_baton, pool));
+ diff_target, recurse, ignore_ancestry, TRUE,
+ versus_url, diff_editor, diff_baton, pool));
 
   compat_wrap_reporter (reporter, report_baton, reporter2, baton2, pool);
 
Index: subversion/libsvn_ra/ra_loader.c
===================================================================
--- subversion/libsvn_ra/ra_loader.c (revision 16385)
+++ subversion/libsvn_ra/ra_loader.c (working copy)
@@ -449,6 +449,25 @@
                                      status_editor, status_baton, pool);
 }
 
+svn_error_t *svn_ra_do_diff2 (svn_ra_session_t *session,
+ const svn_ra_reporter2_t **reporter,
+ void **report_baton,
+ svn_revnum_t revision,
+ const char *diff_target,
+ svn_boolean_t recurse,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
+ const char *versus_url,
+ const svn_delta_editor_t *diff_editor,
+ void *diff_baton,
+ apr_pool_t *pool)
+{
+ return session->vtable->do_diff (session, reporter, report_baton, revision,
+ diff_target, recurse, ignore_ancestry,
+ text_deltas, versus_url, diff_editor,
+ diff_baton, pool);
+}
+
 svn_error_t *svn_ra_do_diff (svn_ra_session_t *session,
                              const svn_ra_reporter2_t **reporter,
                              void **report_baton,
@@ -461,9 +480,9 @@
                              void *diff_baton,
                              apr_pool_t *pool)
 {
- return session->vtable->do_diff (session, reporter, report_baton, revision,
- diff_target, recurse, ignore_ancestry,
- versus_url, diff_editor, diff_baton, pool);
+ return svn_ra_do_diff2 ( session, reporter, report_baton, revision,
+ diff_target, recurse, ignore_ancestry, TRUE,
+ versus_url, diff_editor, diff_baton, pool );
 }
 
 svn_error_t *svn_ra_get_log (svn_ra_session_t *session,
Index: subversion/libsvn_ra/ra_loader.h
===================================================================
--- subversion/libsvn_ra/ra_loader.h (revision 16385)
+++ subversion/libsvn_ra/ra_loader.h (working copy)
@@ -134,6 +134,7 @@
                            const char *diff_target,
                            svn_boolean_t recurse,
                            svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
                            const char *versus_url,
                            const svn_delta_editor_t *diff_editor,
                            void *diff_baton,
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 16385)
+++ subversion/include/svn_client.h (working copy)
@@ -449,6 +449,84 @@
                                 apr_pool_t *pool);
 
 
+/** the difference type in an svn_diff_summarize_t structure.
+ *
+ * @since New in 1.4.
+ */
+typedef enum svn_diff_summarize_kind_t
+{
+ /** an unchagned item */
+ svn_diff_summarize_kind_unchanged,
+
+ /** an added item */
+ svn_diff_summarize_kind_added,
+
+ /** a modified item */
+ svn_diff_summarize_kind_modified,
+
+ /** a deleted item */
+ svn_diff_summarize_kind_deleted
+
+} svn_diff_summarize_kind_t;
+
+
+/** a struct that describes the diff of an item. Passed to
+ * svn_diff_summarize_func_t.
+ *
+ * @note Fields may be added to the end of this structure in future
+ * versions. Therefore, users shouldn't allocate structures of this
+ * type, to preserve binary compatibility.
+ *
+ * @since New in 1.4.
+ */
+typedef struct svn_diff_summarize_t
+{
+ /**
+ * path relative to the diff summarize target.
+ */
+ const char* path;
+
+ /**
+ * set if @a path was copied from @a path_copyfrom, else NULL.
+ */
+ const char* copyfrom_path;
+
+ /**
+ * valid if @a path_copyfrom is not NULL, else SVN_INVALID_REVNUM.
+ */
+ svn_revnum_t copyfrom_rev;
+
+ /** change kind: is @a path unchanged, added, modified or deleted */
+ svn_diff_summarize_kind_t summarize_kind;
+
+ /** file or dir */
+ svn_node_kind_t node_kind;
+
+ /** text content changed? */
+ svn_boolean_t text_changed;
+
+ /** properties changed? */
+ svn_boolean_t prop_changed;
+
+} svn_diff_summarize_t;
+
+
+/** A callback used in svn_client_diff_summarize/svn_client_diff_summarize_peg
+ * for reporting a @a diff summary.
+ *
+ * All allocations should be performed in @a pool.
+ *
+ * @a baton is a closure object; it should be provided by the implementation,
+ * and passed by the caller.
+ *
+ * @since New in 1.4.
+ */
+typedef svn_error_t *
+(*svn_diff_summarize_func_t) (void *summarize_baton,
+ svn_diff_summarize_t *diff,
+ apr_pool_t *pool);
+
+
 /** A client context structure, which holds client specific callbacks,
  * batons, serves as a cache for configuration options, and other various
  * and sundry things. In order to avoid backwards compatibility problems
@@ -1349,6 +1427,59 @@
                                   svn_client_ctx_t *ctx,
                                   apr_pool_t *pool);
 
+/**
+ * Produce a diff summary which lists the changed items between
+ * @a path1/@a revision1 and @a path2/@a revision2 without creating the
+ * delta. @a path1 and @a path2 can be either working-copy paths or URLs.
+ *
+ * The function may report false positives if @a ignore_ancestry is false.
+ *
+ * Calls @a summarize_func with @a summarize_baton for each difference
+ * with a @c svn_diff_summarize_t * structure describing the difference.
+ *
+ * See svn_client_diff3 for a description of the other parameters.
+ *
+ * @since New in 1.4.
+ */
+svn_error_t *
+svn_client_diff_summarize (const char *path1,
+ const svn_opt_revision_t *revision1,
+ const char *path2,
+ const svn_opt_revision_t *revision2,
+ svn_boolean_t recurse,
+ svn_boolean_t ignore_ancestry,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
+/**
+ * Produce a diff summary which lists the changed items between the
+ * filesystem object @a path in peg revision @a peg_revision, as it
+ * changed between @a start_revision and @a end_revision. @a path can
+ * be either a working-copy path or URL.
+ *
+ * The function may report false positives if @a ignore_ancestry is false.
+ *
+ * Calls @a summarize_func with @a preview_baton for each difference
+ * with a @c svn_diff_summarize_t * structure describing the difference.
+ *
+ * See svn_client_diff_peg3 for a description of the other parameters.
+ *
+ * @since New in 1.4.
+ */
+svn_error_t *
+svn_client_diff_summarize_peg (const char *path,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *start_revision,
+ const svn_opt_revision_t *end_revision,
+ svn_boolean_t recurse,
+ svn_boolean_t ignore_ancestry,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
 /** Merge changes from @a source1/@a revision1 to @a source2/@a revision2 into
  * the working-copy path @a target_wcpath.
  *
Index: subversion/include/svn_ra.h
===================================================================
--- subversion/include/svn_ra.h (revision 16385)
+++ subversion/include/svn_ra.h (working copy)
@@ -834,10 +834,33 @@
  * finishing the report, and may not perform any RA operations using
  * @a session from within the editing operations of @a diff_editor.
  *
+ * @a text_deltas instructs the driver of the @a diff_editor to enable
+ * the generation of text deltas. If @a text_deltas is FALSE the window
+ * handler returned by apply_textdelta will be called with an empty
+ * svn_txdelta_window_t.
+ *
  * Use @a pool for memory allocation.
  *
- * @since New in 1.2.
+ * @since New in 1.4.
  */
+svn_error_t *svn_ra_do_diff2 (svn_ra_session_t *session,
+ const svn_ra_reporter2_t **reporter,
+ void **report_baton,
+ svn_revnum_t revision,
+ const char *diff_target,
+ svn_boolean_t recurse,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
+ const char *versus_url,
+ const svn_delta_editor_t *diff_editor,
+ void *diff_baton,
+ apr_pool_t *pool);
+
+/**
+ * Similar to svn_ra_do_diff2(), but with @a text_deltas set to @c TRUE.
+ *
+ * @deprecated Provided for backward compatibility with the 1.2 API.
+ */
 svn_error_t *svn_ra_do_diff (svn_ra_session_t *session,
                              const svn_ra_reporter2_t **reporter,
                              void **report_baton,
Index: subversion/libsvn_ra_local/ra_plugin.c
===================================================================
--- subversion/libsvn_ra_local/ra_plugin.c (revision 16385)
+++ subversion/libsvn_ra_local/ra_plugin.c (working copy)
@@ -697,6 +697,7 @@
                        const char *update_target,
                        svn_boolean_t recurse,
                        svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
                        const char *switch_url,
                        const svn_delta_editor_t *update_editor,
                        void *update_baton,
@@ -708,7 +709,7 @@
                         update_revision,
                         update_target,
                         switch_url,
- TRUE,
+ text_deltas,
                         recurse,
                         ignore_ancestry,
                         update_editor,
Index: subversion/libsvn_client/client.h
===================================================================
--- subversion/libsvn_client/client.h (revision 16385)
+++ subversion/libsvn_client/client.h (working copy)
@@ -403,6 +403,32 @@
 
 /* ---------------------------------------------------------------- */
 
+/*** Editor for diff summary ***/
+
+/* Create an editor for a repository diff summary, i.e. comparing one
+ * repository version against the other and only providing information
+ * about the changed items without the text delta.
+ *
+ * @summarize_func is called with @a summarize_baton as parameter by the
+ * created svn_delta_editor_t for each changed item.
+ *
+ * See svn_client__get_diff_editor for a description of the other
+ * parameters.
+ */
+svn_error_t *
+svn_client__get_diff_summarize_editor(const char *target,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_ra_session_t *ra_session,
+ svn_revnum_t revision,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ const svn_delta_editor_t **editor,
+ void **edit_baton,
+ apr_pool_t *pool);
+
+/* ---------------------------------------------------------------- */
+
 /*** Commit Stuff ***/
 
 /* WARNING: This is all new, untested, un-peer-reviewed conceptual
Index: subversion/libsvn_client/diff.c
===================================================================
--- subversion/libsvn_client/diff.c (revision 16385)
+++ subversion/libsvn_client/diff.c (working copy)
@@ -1401,8 +1401,234 @@
   return SVN_NO_ERROR;
 }
 
+/** Helper structure: for passing around the diff parameters */
+struct diff_parameters
+{
+ /* additional parameters for diff tool */
+ const apr_array_header_t *options;
 
+ /* first input path */
+ const char *path1;
 
+ /* revision of first input path */
+ const svn_opt_revision_t *revision1;
+
+ /* second input path */
+ const char *path2;
+
+ /* revision of second input path */
+ const svn_opt_revision_t *revision2;
+
+ /* peg revision */
+ const svn_opt_revision_t *peg_revision;
+
+ /* recurse */
+ svn_boolean_t recurse;
+
+ /* ignore acestry */
+ svn_boolean_t ignore_ancestry;
+
+ /* ignore deleted */
+ svn_boolean_t no_diff_deleted;
+};
+
+/** Helper structure: filled by check_paths */
+struct diff_paths
+{
+ /* revision1 is a local revision */
+ svn_boolean_t is_local_rev1;
+
+ /* revision2 is a local revision */
+ svn_boolean_t is_local_rev2;
+
+ /* path1 is a repos url */
+ svn_boolean_t is_repos_path1;
+
+ /* path2 is a repos url, not used by check_paths when peg is true */
+ svn_boolean_t is_repos_path2;
+};
+
+
+/** check if paths are urls and if the revisions are local. Pass FALSE to
+ @a peg to run the check for a diff with two sources. Pass TRUE to @a peg
+ to run the check for a pegged diff. Fills the @a paths structure. */
+static svn_error_t *
+check_paths (const struct diff_parameters* params, struct diff_paths* paths,
+ svn_boolean_t peg )
+{
+ /* Figure out if the sources are URLs or working copy paths. */
+ paths->is_repos_path1 = svn_path_is_url (params->path1);
+
+ if (peg)
+ paths->is_repos_path2 = FALSE;
+ else
+ paths->is_repos_path2 = svn_path_is_url (params->path2);
+
+
+ /* Verify our revision arguments in light of the paths. */
+ if ((params->revision1->kind == svn_opt_revision_unspecified)
+ || (params->revision2->kind == svn_opt_revision_unspecified))
+ return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL,
+ _("Not all required revisions are specified"));
+
+ /* Revisions can be said to be local or remote. BASE and WORKING,
+ for example, are local. */
+ paths->is_local_rev1 =
+ ((params->revision1->kind == svn_opt_revision_base)
+ || (params->revision1->kind == svn_opt_revision_working));
+ paths->is_local_rev2 =
+ ((params->revision2->kind == svn_opt_revision_base)
+ || (params->revision2->kind == svn_opt_revision_working));
+
+ if (peg)
+ {
+ if (paths->is_local_rev1 && paths->is_local_rev2)
+ return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL,
+ _("At least one revision must be non-local "
+ "for a pegged diff"));
+ }
+ else
+ {
+ /* Working copy paths with non-local revisions get turned into
+ URLs. We don't do that here, though. We simply record that it
+ needs to be done, which is information that helps us choose our
+ diff helper function. */
+ if ((! paths->is_repos_path1) && (! paths->is_local_rev1))
+ paths->is_repos_path1 = TRUE;
+ if ((! paths->is_repos_path2) && (! paths->is_local_rev2))
+ paths->is_repos_path2 = TRUE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/** Helper structure filled by diff_prepare_repos_repos */
+struct diff_repos_repos
+{
+ /* url created from path1 */
+ const char *url1;
+
+ /* url created from path2 */
+ const char *url2;
+
+ /* the BASE_PATH for the diff */
+ const char *base_path;
+
+ /* url1 and url2 are the same */
+ svn_boolean_t same_urls;
+
+ /* revision of url1 */
+ svn_revnum_t rev1;
+
+ /* revision of url2 */
+ svn_revnum_t rev2;
+
+ /* anchor based on url1 */
+ const char *anchor1;
+
+ /* anchor based on url2 */
+ const char *anchor2;
+
+ /* target based on url1 */
+ const char *target1;
+
+ /* target based on url2 */
+ const char *target2;
+};
+
+/** Helper function: prepare a repos repos diff. Fills @a drr
+ * structure. */
+static svn_error_t *
+diff_prepare_repos_repos (const struct diff_parameters *params,
+ struct diff_repos_repos *drr,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ svn_ra_session_t *ra_session1, *ra_session2;
+ svn_node_kind_t kind1, kind2;
+
+ apr_pool_t *temppool = svn_pool_create (pool);
+
+ /* Figure out URL1 and URL2. */
+ SVN_ERR (convert_to_url (&drr->url1, params->path1, pool));
+ SVN_ERR (convert_to_url (&drr->url2, params->path2, pool));
+ drr->same_urls = (strcmp (drr->url1, drr->url2) == 0);
+
+ /* We need exactly one BASE_PATH, so we'll let the BASE_PATH
+ calculated for PATH2 override the one for PATH1 (since the diff
+ will be "applied" to URL2 anyway). */
+ drr->base_path = NULL;
+ if (drr->url1 != params->path1)
+ drr->base_path = params->path1;
+ if (drr->url2 != params->path2)
+ drr->base_path = params->path2;
+
+ /* If we are performing a pegged diff, we need to find out what our
+ actual URLs will be. */
+ if (params->peg_revision->kind != svn_opt_revision_unspecified)
+ {
+ svn_opt_revision_t *start_ignore, *end_ignore;
+
+ SVN_ERR (svn_client__repos_locations (&drr->url1, &start_ignore,
+ &drr->url2, &end_ignore,
+ params->path2,
+ params->peg_revision,
+ params->revision1,
+ params->revision2,
+ ctx, pool));
+ }
+
+
+ /* Open temporary RA sessions to each URL. */
+ SVN_ERR (svn_client__open_ra_session_internal (&ra_session1, drr->url1,
+ NULL, NULL, NULL, FALSE,
+ TRUE, ctx, temppool));
+ SVN_ERR (svn_client__open_ra_session_internal (&ra_session2, drr->url2,
+ NULL, NULL, NULL, FALSE,
+ TRUE, ctx, temppool));
+
+ /* Resolve named revisions to real numbers. */
+ SVN_ERR (svn_client__get_revision_number
+ (&drr->rev1, ra_session1, params->revision1,
+ (params->path1 == drr->url1) ? NULL : params->path1, pool));
+ SVN_ERR (svn_client__get_revision_number
+ (&drr->rev2, ra_session2, params->revision2,
+ (params->path2 == drr->url2) ? NULL : params->path2, pool));
+
+ /* Choose useful anchors and targets for our two URLs, and verify
+ that both sides of the diff exist. */
+ drr->anchor1 = drr->url1;
+ drr->anchor2 = drr->url2;
+ drr->target1 = "";
+ drr->target2 = "";
+ SVN_ERR (svn_ra_check_path (ra_session1, "", drr->rev1, &kind1, temppool));
+ SVN_ERR (svn_ra_check_path (ra_session2, "", drr->rev2, &kind2, temppool));
+ if (kind1 == svn_node_none)
+ return svn_error_createf
+ (SVN_ERR_FS_NOT_FOUND, NULL,
+ _("'%s' was not found in the repository at revision %ld"),
+ drr->url1, drr->rev1);
+ if (kind2 == svn_node_none)
+ return svn_error_createf
+ (SVN_ERR_FS_NOT_FOUND, NULL,
+ _("'%s' was not found in the repository at revision %ld"),
+ drr->url2, drr->rev2);
+ if ((kind1 == svn_node_file) || (kind2 == svn_node_file))
+ {
+ svn_path_split (drr->url1, &drr->anchor1, &drr->target1, pool);
+ drr->target1 = svn_path_uri_decode (drr->target1, pool);
+ svn_path_split (drr->url2, &drr->anchor2, &drr->target2, pool);
+ drr->target2 = svn_path_uri_decode (drr->target2, pool);
+ if (drr->base_path)
+ drr->base_path = svn_path_dirname (drr->base_path, pool);
+ }
+
+ /* Destroy the temporary pool, which closes our RA session. */
+ svn_pool_destroy (temppool);
+
+ return SVN_NO_ERROR;
+}
+
 /* URL1/PATH1, URL2/PATH2, and TARGET_WCPATH all better be
    directories. For the single file case, the caller does the merging
    manually. PATH1 and PATH2 can be NULL.
@@ -1779,158 +2005,69 @@
 
 /* Perform a diff between two repository paths.
    
- PATH1 and PATH2 may be either URLs or the working copy paths.
- REVISION1 and REVISION2 are their respective revisions. If
- PEG_REVISION is specified, PATH2 is the path at the peg revision,
- and the actual two paths compared are determined by following copy
- history from PATH2.
+ diff_param.path1 and diff_param.path2 may be either URLs or the working
+ copy paths. diff_param.revision1 and diff_param.revision2 are their
+ respective revisions. If diff_param.peg_revision is specified, path2 is
+ the path at the peg revision, and the actual two paths compared are
+ determined by following copy history from path2.
 
    All other options are the same as those passed to svn_client_diff3(). */
 static svn_error_t *
-diff_repos_repos (const apr_array_header_t *options,
- const char *path1,
- const svn_opt_revision_t *revision1,
- const char *path2,
- const svn_opt_revision_t *revision2,
- const svn_opt_revision_t *peg_revision,
- svn_boolean_t recurse,
- svn_boolean_t ignore_ancestry,
+diff_repos_repos (const struct diff_parameters* diff_param,
                   const svn_wc_diff_callbacks2_t *callbacks,
                   struct diff_cmd_baton *callback_baton,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
 {
- const char *url1, *url2;
- const char *anchor1, *target1, *anchor2, *target2, *base_path;
- svn_node_kind_t kind1, kind2;
- svn_revnum_t rev1, rev2;
   svn_ra_session_t *ra_session1, *ra_session2;
+
   const svn_ra_reporter2_t *reporter;
   void *report_baton;
+
   const svn_delta_editor_t *diff_editor;
   void *diff_edit_baton;
- apr_pool_t *temppool = svn_pool_create (pool);
- svn_boolean_t same_urls;
 
- /* Figure out URL1 and URL2. */
- SVN_ERR (convert_to_url (&url1, path1, pool));
- SVN_ERR (convert_to_url (&url2, path2, pool));
- same_urls = (strcmp (url1, url2) == 0);
+ struct diff_repos_repos drr;
 
- /* We need exactly one BASE_PATH, so we'll let the BASE_PATH
- calculated for PATH2 override the one for PATH1 (since the diff
- will be "applied" to URL2 anyway). */
- base_path = NULL;
- if (url1 != path1)
- base_path = path1;
- if (url2 != path2)
- base_path = path2;
+ /* prepare info for the repos repos diff */
+ SVN_ERR (diff_prepare_repos_repos (diff_param, &drr, ctx, pool ));
 
- /* If we are performing a pegged diff, we need to find out what our
- actual URLs will be. */
- if (peg_revision->kind != svn_opt_revision_unspecified)
- {
- svn_opt_revision_t *start_ignore, *end_ignore;
-
- SVN_ERR (svn_client__repos_locations (&url1, &start_ignore,
- &url2, &end_ignore,
- path2,
- peg_revision,
- revision1, revision2,
- ctx, pool));
+ /* get actual urls */
+ callback_baton->orig_path_1 = drr.url1;
+ callback_baton->orig_path_2 = drr.url2;
 
- callback_baton->orig_path_1 = url1;
- callback_baton->orig_path_2 = url2;
- }
-
- /* Open temporary RA sessions to each URL. */
- SVN_ERR (svn_client__open_ra_session_internal (&ra_session1, url1, NULL,
- NULL, NULL, FALSE, TRUE,
- ctx, temppool));
- SVN_ERR (svn_client__open_ra_session_internal (&ra_session2, url2, NULL,
- NULL, NULL, FALSE, TRUE,
- ctx, temppool));
+ /* get numeric revisions */
+ callback_baton->revnum1 = drr.rev1;
+ callback_baton->revnum2 = drr.rev2;
 
- /* Resolve named revisions to real numbers. */
- SVN_ERR (svn_client__get_revision_number
- (&rev1, ra_session1, revision1,
- (path1 == url1) ? NULL : path1, pool));
- callback_baton->revnum1 = rev1;
- SVN_ERR (svn_client__get_revision_number
- (&rev2, ra_session2, revision2,
- (path2 == url2) ? NULL : path2, pool));
- callback_baton->revnum2 = rev2;
-
- /* Choose useful anchors and targets for our two URLs, and verify
- that both sides of the diff exist. */
- anchor1 = url1;
- anchor2 = url2;
- target1 = "";
- target2 = "";
- SVN_ERR (svn_ra_check_path (ra_session1, "", rev1, &kind1, temppool));
- SVN_ERR (svn_ra_check_path (ra_session2, "", rev2, &kind2, temppool));
- if (kind1 == svn_node_none)
- return svn_error_createf
- (SVN_ERR_FS_NOT_FOUND, NULL,
- _("'%s' was not found in the repository at revision %ld"),
- url1, rev1);
- if (kind2 == svn_node_none)
- return svn_error_createf
- (SVN_ERR_FS_NOT_FOUND, NULL,
- _("'%s' was not found in the repository at revision %ld"),
- url2, rev2);
- if ((kind1 == svn_node_file) || (kind2 == svn_node_file))
- {
- svn_path_split (url1, &anchor1, &target1, pool);
- target1 = svn_path_uri_decode (target1, pool);
- svn_path_split (url2, &anchor2, &target2, pool);
- target2 = svn_path_uri_decode (target2, pool);
- if (base_path)
- base_path = svn_path_dirname (base_path, pool);
- }
-
- /* Destroy the temporary pool, which closes our RA session. */
- svn_pool_destroy (temppool);
-
   /* Now, we reopen two RA session to the correct anchor/target
      locations for our URLs. */
- SVN_ERR (svn_client__open_ra_session_internal (&ra_session1, anchor1,
- NULL, NULL, NULL, FALSE, TRUE,
- ctx, pool));
- SVN_ERR (svn_client__open_ra_session_internal (&ra_session2, anchor1,
- NULL, NULL, NULL, FALSE, TRUE,
- ctx, pool));
+ SVN_ERR (svn_client__open_ra_session_internal
+ (&ra_session1, drr.anchor1, NULL, NULL, NULL, FALSE, TRUE, ctx,
+ pool));
+ SVN_ERR (svn_client__open_ra_session_internal
+ (&ra_session2, drr.anchor1, NULL, NULL, NULL, FALSE, TRUE, ctx,
+ pool));
 
   /* Set up the repos_diff editor on BASE_PATH, if available.
      Otherwise, we just use "". */
- SVN_ERR (svn_client__get_diff_editor (base_path ? base_path : "",
- NULL,
- callbacks,
- callback_baton,
- recurse,
- FALSE, /* doesn't matter for diff */
- ra_session2,
- rev1,
- NULL, /* no notify_func */
- NULL, /* no notify_baton */
- ctx->cancel_func,
- ctx->cancel_baton,
- &diff_editor,
- &diff_edit_baton,
- pool));
+ SVN_ERR (svn_client__get_diff_editor
+ (drr.base_path ? drr.base_path : "",
+ NULL, callbacks, callback_baton, diff_param->recurse,
+ FALSE, /* doesn't matter for diff */ ra_session2, drr.rev1,
+ NULL, /* no notify_func */ NULL, /* no notify_baton */
+ ctx->cancel_func, ctx->cancel_baton,
+ &diff_editor, &diff_edit_baton, pool));
   
   /* We want to switch our txn into URL2 */
- SVN_ERR (svn_ra_do_diff (ra_session1,
- &reporter, &report_baton,
- rev2,
- target1,
- recurse,
- ignore_ancestry,
- url2,
- diff_editor, diff_edit_baton, pool));
+ SVN_ERR (svn_ra_do_diff2
+ (ra_session1, &reporter, &report_baton, drr.rev2, drr.target1,
+ diff_param->recurse, diff_param->ignore_ancestry, TRUE,
+ drr.url2, diff_editor, diff_edit_baton, pool));
 
   /* Drive the reporter; do the diff. */
- SVN_ERR (reporter->set_path (report_baton, "", rev1, FALSE, NULL, pool));
+ SVN_ERR (reporter->set_path (report_baton, "", drr.rev1, FALSE, NULL,
+ pool));
   SVN_ERR (reporter->finish_report (report_baton, pool));
 
   return SVN_NO_ERROR;
@@ -2061,83 +2198,55 @@
 
 /* This is basically just the guts of svn_client_diff3(). */
 static svn_error_t *
-do_diff (const apr_array_header_t *options,
- const char *path1,
- const svn_opt_revision_t *revision1,
- const char *path2,
- const svn_opt_revision_t *revision2,
- svn_boolean_t recurse,
- svn_boolean_t ignore_ancestry,
+do_diff (const struct diff_parameters* diff_param,
          const svn_wc_diff_callbacks2_t *callbacks,
          struct diff_cmd_baton *callback_baton,
          svn_client_ctx_t *ctx,
          apr_pool_t *pool)
 {
- svn_boolean_t is_local_rev1, is_local_rev2;
- svn_boolean_t is_repos_path1, is_repos_path2;
- svn_opt_revision_t peg_revision;
+ struct diff_paths diff_paths;
 
- /* We will never do a pegged diff from here. */
- peg_revision.kind = svn_opt_revision_unspecified;
+ /* Check if paths/revisions are urls/local. */
+ check_paths(diff_param, &diff_paths, FALSE);
 
- /* Either path could be a URL or a working copy path. Let's figure
- out what's what. */
- is_repos_path1 = svn_path_is_url (path1);
- is_repos_path2 = svn_path_is_url (path2);
-
- /* Verify our revision arguments in light of the paths. */
- if ((revision1->kind == svn_opt_revision_unspecified)
- || (revision2->kind == svn_opt_revision_unspecified))
- return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL,
- _("Not all required revisions are specified"));
-
- /* Revisions can be said to be local or remote. BASE and WORKING,
- for example, are local. */
- is_local_rev1 = ((revision1->kind == svn_opt_revision_base)
- || (revision1->kind == svn_opt_revision_working));
- is_local_rev2 = ((revision2->kind == svn_opt_revision_base)
- || (revision2->kind == svn_opt_revision_working));
-
- /* Working copy paths with non-local revisions get turned into
- URLs. We don't do that here, though. We simply record that it
- needs to be done, which is information that helps us choose our
- diff helper function. */
- if ((! is_repos_path1) && (! is_local_rev1))
- is_repos_path1 = TRUE;
- if ((! is_repos_path2) && (! is_local_rev2))
- is_repos_path2 = TRUE;
-
- if (is_repos_path1) /* path1 is (effectively) a URL */
+ if (diff_paths.is_repos_path1) /* path1 is (effectively) a URL */
     {
- if (is_repos_path2) /* path2 is (effectively) a URL */
+ if (diff_paths.is_repos_path2) /* path2 is (effectively) a URL */
         {
- SVN_ERR (diff_repos_repos (options, path1, revision1, path2,
- revision2, &peg_revision, recurse,
- ignore_ancestry, callbacks,
- callback_baton, ctx, pool));
+ SVN_ERR (diff_repos_repos (diff_param, callbacks, callback_baton,
+ ctx, pool));
         }
       else /* path2 is a working copy path */
         {
- SVN_ERR (diff_repos_wc (options, path1, revision1, &peg_revision,
- path2, revision2, FALSE, recurse,
- ignore_ancestry, callbacks,
- callback_baton, ctx, pool));
+ SVN_ERR (diff_repos_wc (diff_param->options,
+ diff_param->path1, diff_param->revision1,
+ diff_param->peg_revision,
+ diff_param->path2, diff_param->revision2,
+ FALSE, diff_param->recurse,
+ diff_param->ignore_ancestry,
+ callbacks, callback_baton, ctx, pool));
         }
     }
   else /* path1 is a working copy path */
     {
- if (is_repos_path2) /* path2 is (effectively) a URL */
+ if (diff_paths.is_repos_path2) /* path2 is (effectively) a URL */
         {
- SVN_ERR (diff_repos_wc (options, path2, revision2, &peg_revision,
- path1, revision1, TRUE, recurse,
- ignore_ancestry, callbacks,
- callback_baton, ctx, pool));
+ SVN_ERR (diff_repos_wc (diff_param->options,
+ diff_param->path2, diff_param->revision2,
+ diff_param->peg_revision,
+ diff_param->path1, diff_param->revision1,
+ TRUE, diff_param->recurse,
+ diff_param->ignore_ancestry,
+ callbacks, callback_baton, ctx, pool));
         }
       else /* path2 is a working copy path */
         {
- SVN_ERR (diff_wc_wc (options, path1, revision1, path2, revision2,
- recurse, ignore_ancestry, callbacks,
- callback_baton, ctx, pool));
+ SVN_ERR (diff_wc_wc (diff_param->options,
+ diff_param->path1, diff_param->revision1,
+ diff_param->path2, diff_param->revision2,
+ diff_param->recurse,
+ diff_param->ignore_ancestry,
+ callbacks, callback_baton, ctx, pool));
         }
     }
 
@@ -2146,80 +2255,199 @@
 
 /* This is basically just the guts of svn_client_diff_peg3(). */
 static svn_error_t *
-do_diff_peg (const apr_array_header_t *options,
- const char *path,
- const svn_opt_revision_t *peg_revision,
- const svn_opt_revision_t *revision1,
- const svn_opt_revision_t *revision2,
- svn_boolean_t recurse,
- svn_boolean_t ignore_ancestry,
+do_diff_peg (const struct diff_parameters* diff_param,
              const svn_wc_diff_callbacks2_t *callbacks,
              struct diff_cmd_baton *callback_baton,
              svn_client_ctx_t *ctx,
              apr_pool_t *pool)
 {
- svn_boolean_t is_local_rev1, is_local_rev2;
- svn_boolean_t is_repos_path;
+ struct diff_paths diff_paths;
 
- /* Either path could be a URL or a working copy path. Let's figure
- out what's what. */
- is_repos_path = svn_path_is_url (path);
+ /* Check if paths/revisions are urls/local. */
+ check_paths(diff_param, &diff_paths, TRUE);
 
- /* Verify our revision arguments in light of the paths. */
- if ((revision1->kind == svn_opt_revision_unspecified)
- || (revision2->kind == svn_opt_revision_unspecified))
- return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL,
- _("Not all required revisions are specified"));
+ if (! diff_paths.is_local_rev1) /* path1 is (effectively) a URL */
+ {
+ if (! diff_paths.is_local_rev2) /* path2 is (effectively) a URL */
+ {
+ SVN_ERR (diff_repos_repos (diff_param, callbacks,
+ callback_baton, ctx, pool));
+ }
+ else /* path2 is a working copy path */
+ {
+ SVN_ERR (diff_repos_wc (diff_param->options,
+ diff_param->path1, diff_param->revision1,
+ diff_param->peg_revision,
+ diff_param->path1, diff_param->revision2,
+ FALSE, diff_param->recurse,
+ diff_param->ignore_ancestry,
+ callbacks, callback_baton, ctx, pool));
+ }
+ }
+ else /* path1 is a working copy path */
+ {
+ if (! diff_paths.is_local_rev2) /* path2 is (effectively) a URL */
+ {
+ SVN_ERR (diff_repos_wc (diff_param->options,
+ diff_param->path1, diff_param->revision2,
+ diff_param->peg_revision,
+ diff_param->path1, diff_param->revision1,
+ TRUE, diff_param->recurse,
+ diff_param->ignore_ancestry,
+ callbacks, callback_baton, ctx, pool));
+ }
+ else
+ {
+ SVN_ERR (diff_wc_wc (diff_param->options,
+ diff_param->path1, diff_param->revision1,
+ diff_param->path1, diff_param->revision2,
+ diff_param->recurse,
+ diff_param->ignore_ancestry,
+ callbacks, callback_baton, ctx, pool));
+ }
+ }
 
- /* Revisions can be said to be local or remote. BASE and WORKING,
- for example, are local. */
- is_local_rev1 = ((revision1->kind == svn_opt_revision_base)
- || (revision1->kind == svn_opt_revision_working));
- is_local_rev2 = ((revision2->kind == svn_opt_revision_base)
- || (revision2->kind == svn_opt_revision_working));
+ return SVN_NO_ERROR;
+}
 
- if (is_local_rev1 && is_local_rev2)
- return svn_error_create (SVN_ERR_CLIENT_BAD_REVISION, NULL,
- _("At least one revision must be non-local for "
- "a pegged diff"));
+/* Perform a diff preview between two repository paths. */
+static svn_error_t *
+diff_summarize_repos_repos (const struct diff_parameters* diff_param,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ svn_ra_session_t *ra_session1, *ra_session2;
 
- if (! is_local_rev1) /* path1 is (effectively) a URL */
+ const svn_ra_reporter2_t *reporter;
+ void *report_baton;
+
+ const svn_delta_editor_t *diff_editor;
+ void *diff_edit_baton;
+
+ struct diff_repos_repos drr;
+
+ /* prepare info for the repos repos diff */
+ SVN_ERR (diff_prepare_repos_repos (diff_param, &drr, ctx, pool ));
+
+ /* Now, we reopen two RA session to the correct anchor/target
+ locations for our URLs. */
+ SVN_ERR (svn_client__open_ra_session_internal
+ (&ra_session1, drr.anchor1, NULL, NULL, NULL, FALSE, TRUE,
+ ctx, pool));
+ SVN_ERR (svn_client__open_ra_session_internal
+ (&ra_session2, drr.anchor1, NULL, NULL, NULL, FALSE, TRUE,
+ ctx, pool));
+
+ /* Set up the repos_diff editor on BASE_PATH, if available.
+ Otherwise, we just use "". */
+ SVN_ERR (svn_client__get_diff_summarize_editor
+ (drr.base_path ? drr.base_path : "", summarize_func,
+ summarize_baton, ra_session2, drr.rev1, ctx->cancel_func,
+ ctx->cancel_baton, &diff_editor, &diff_edit_baton, pool));
+
+ /* We want to switch our txn into URL2 */
+ SVN_ERR (svn_ra_do_diff2
+ (ra_session1, &reporter, &report_baton, drr.rev2, drr.target1,
+ diff_param->recurse, diff_param->ignore_ancestry,
+ FALSE /* do not create text delta */, drr.url2, diff_editor,
+ diff_edit_baton, pool));
+
+ /* Drive the reporter; do the diff. */
+ SVN_ERR (reporter->set_path (report_baton, "", drr.rev1, FALSE, NULL,
+ pool));
+ SVN_ERR (reporter->finish_report (report_baton, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* This is basically just the guts of svn_client_diff_summarize(). */
+static svn_error_t *
+do_diff_summarize (const struct diff_parameters* diff_param,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct diff_paths diff_paths;
+
+ /* Check if paths/revisions are urls/local. */
+ check_paths(diff_param, &diff_paths, FALSE);
+
+ if (diff_paths.is_repos_path1) /* path1 is (effectively) a URL */
     {
- if (! is_local_rev2) /* path2 is (effectively) a URL */
+ if (diff_paths.is_repos_path2) /* path2 is (effectively) a URL */
         {
- SVN_ERR (diff_repos_repos (options, path, revision1, path,
- revision2, peg_revision, recurse,
- ignore_ancestry, callbacks,
- callback_baton, ctx, pool));
+ SVN_ERR (diff_summarize_repos_repos (diff_param, summarize_func,
+ summarize_baton, ctx, pool));
         }
       else /* path2 is a working copy path */
         {
- SVN_ERR (diff_repos_wc (options, path, revision1, peg_revision, path,
- revision2, FALSE, recurse, ignore_ancestry,
- callbacks, callback_baton, ctx, pool));
+ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE,
+ NULL, NULL);
         }
     }
   else /* path1 is a working copy path */
     {
- if (! is_local_rev2) /* path2 is (effectively) a URL */
+ if (diff_paths.is_repos_path2) /* path2 is (effectively) a URL */
         {
- SVN_ERR (diff_repos_wc (options, path, revision2, peg_revision,
- path, revision1, TRUE, recurse,
- ignore_ancestry, callbacks,
- callback_baton, ctx, pool));
+ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE,
+ NULL, NULL);
         }
+ else /* path2 is a working copy path */
+ {
+ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE,
+ NULL, NULL);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* This is basically just the guts of svn_client_diff_summarize_peg(). */
+static svn_error_t *
+do_diff_summarize_peg (const struct diff_parameters* diff_param,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct diff_paths diff_paths;
+
+ /* Check if paths/revisions are urls/local. */
+ check_paths(diff_param, &diff_paths, TRUE);
+
+ if (! diff_paths.is_local_rev1) /* path1 is (effectively) a URL */
+ {
+ if (! diff_paths.is_local_rev2) /* path2 is (effectively) a URL */
+ {
+ SVN_ERR (diff_summarize_repos_repos (diff_param, summarize_func,
+ summarize_baton, ctx, pool));
+ }
+ else /* path2 is a working copy path */
+ {
+ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE,
+ NULL, NULL);
+ }
+ }
+ else /* path1 is a working copy path */
+ {
+ if (! diff_paths.is_local_rev2) /* path2 is (effectively) a URL */
+ {
+ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE,
+ NULL, NULL);
+ }
       else
         {
- SVN_ERR (diff_wc_wc (options, path, revision1, path, revision2,
- recurse, ignore_ancestry, callbacks,
- callback_baton, ctx, pool));
+ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE,
+ NULL, NULL);
         }
     }
 
   return SVN_NO_ERROR;
 }
 
-
 /*----------------------------------------------------------------------- */
 
 /*** Public Interfaces. ***/
@@ -2281,9 +2509,27 @@
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
 {
+ struct diff_parameters diff_params;
+
   struct diff_cmd_baton diff_cmd_baton;
   svn_wc_diff_callbacks2_t diff_callbacks;
 
+ /* We will never do a pegged diff from here. */
+ svn_opt_revision_t peg_revision;
+ peg_revision.kind = svn_opt_revision_unspecified;
+
+ /* fill diff_param */
+ diff_params.options = options;
+ diff_params.path1 = path1;
+ diff_params.revision1 = revision1;
+ diff_params.path2 = path2;
+ diff_params.revision2 = revision2;
+ diff_params.peg_revision = &peg_revision;
+ diff_params.recurse = recurse;
+ diff_params.ignore_ancestry = ignore_ancestry;
+ diff_params.no_diff_deleted = no_diff_deleted;
+
+ /* setup callback and baton */
   diff_callbacks.file_changed = diff_file_changed;
   diff_callbacks.file_added = diff_file_added;
   diff_callbacks.file_deleted = no_diff_deleted ? diff_file_deleted_no_diff :
@@ -2307,14 +2553,7 @@
   diff_cmd_baton.force_empty = FALSE;
   diff_cmd_baton.force_binary = ignore_content_type;
 
- return do_diff (options,
- path1, revision1,
- path2, revision2,
- recurse,
- ignore_ancestry,
- &diff_callbacks, &diff_cmd_baton,
- ctx,
- pool);
+ return do_diff (&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
 }
 
 svn_error_t *
@@ -2373,9 +2612,23 @@
                       svn_client_ctx_t *ctx,
                       apr_pool_t *pool)
 {
+ struct diff_parameters diff_params;
+
   struct diff_cmd_baton diff_cmd_baton;
   svn_wc_diff_callbacks2_t diff_callbacks;
 
+ /* fill diff_param */
+ diff_params.options = options;
+ diff_params.path1 = path;
+ diff_params.revision1 = start_revision;
+ diff_params.path2 = path;
+ diff_params.revision2 = end_revision;
+ diff_params.peg_revision = peg_revision;
+ diff_params.recurse = recurse;
+ diff_params.ignore_ancestry = ignore_ancestry;
+ diff_params.no_diff_deleted = no_diff_deleted;
+
+ /* setup callback and baton */
   diff_callbacks.file_changed = diff_file_changed;
   diff_callbacks.file_added = diff_file_added;
   diff_callbacks.file_deleted = no_diff_deleted ? diff_file_deleted_no_diff :
@@ -2399,14 +2652,7 @@
   diff_cmd_baton.force_empty = FALSE;
   diff_cmd_baton.force_binary = ignore_content_type;
 
- return do_diff_peg (options,
- path, peg_revision,
- start_revision, end_revision,
- recurse,
- ignore_ancestry,
- &diff_callbacks, &diff_cmd_baton,
- ctx,
- pool);
+ return do_diff_peg (&diff_params, &diff_callbacks, &diff_cmd_baton, ctx, pool);
 }
 
 svn_error_t *
@@ -2452,6 +2698,68 @@
 }
 
 svn_error_t *
+svn_client_diff_summarize (const char *path1,
+ const svn_opt_revision_t *revision1,
+ const char *path2,
+ const svn_opt_revision_t *revision2,
+ svn_boolean_t recurse,
+ svn_boolean_t ignore_ancestry,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct diff_parameters diff_params;
+
+ /* We will never do a pegged diff from here. */
+ svn_opt_revision_t peg_revision;
+ peg_revision.kind = svn_opt_revision_unspecified;
+
+ /* fill diff_param */
+ diff_params.options = NULL;
+ diff_params.path1 = path1;
+ diff_params.revision1 = revision1;
+ diff_params.path2 = path2;
+ diff_params.revision2 = revision2;
+ diff_params.peg_revision = &peg_revision;
+ diff_params.recurse = recurse;
+ diff_params.ignore_ancestry = ignore_ancestry;
+ diff_params.no_diff_deleted = FALSE;
+
+ return do_diff_summarize (&diff_params, summarize_func, summarize_baton,
+ ctx, pool);
+}
+
+svn_error_t *
+svn_client_diff_summarize_peg (const char *path,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *start_revision,
+ const svn_opt_revision_t *end_revision,
+ svn_boolean_t recurse,
+ svn_boolean_t ignore_ancestry,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct diff_parameters diff_params;
+
+ /* fill diff_param */
+ diff_params.options = NULL;
+ diff_params.path1 = path;
+ diff_params.revision1 = start_revision;
+ diff_params.path2 = path;
+ diff_params.revision2 = end_revision;
+ diff_params.peg_revision = peg_revision;
+ diff_params.recurse = recurse;
+ diff_params.ignore_ancestry = ignore_ancestry;
+ diff_params.no_diff_deleted = FALSE;
+
+ return do_diff_summarize_peg (&diff_params, summarize_func, summarize_baton,
+ ctx, pool);
+}
+
+svn_error_t *
 svn_client_merge (const char *source1,
                   const svn_opt_revision_t *revision1,
                   const char *source2,
Index: subversion/libsvn_client/repos_diff_summarize.c
===================================================================
--- subversion/libsvn_client/repos_diff_summarize.c (revision 0)
+++ subversion/libsvn_client/repos_diff_summarize.c (revision 0)
@@ -0,0 +1,355 @@
+/*
+ * repos_diff_summarize.c -- The diff summarize editor for summarizing
+ * the differences of two repository versions
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2004 CollabNet. All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+#include "svn_wc.h"
+#include "svn_props.h"
+#include "svn_pools.h"
+
+#include "client.h"
+
+
+/* Overall crawler editor baton. */
+struct summarize_edit_baton {
+
+ /* The summarize callback passed down from the api */
+ svn_diff_summarize_func_t summarize_func;
+
+ /* The summarize callback baton */
+ void *summarize_func_baton;
+
+ /* the open session for thes requests */
+ svn_ra_session_t *ra_session;
+
+ /* The rev1 from the '-r Rev1:Rev2' command line option */
+ svn_revnum_t revision;
+};
+
+
+/* item baton.
+ */
+struct summarize_baton {
+
+ /* the overall crawler editor baton */
+ struct summarize_edit_baton *edit_baton;
+
+ /* the summarize filled by the editor calls */
+ svn_diff_summarize_t *summarize;
+
+ /* The path of the file or directory within the repository */
+ const char *path;
+};
+
+
+/* create a summarize baton
+*/
+struct summarize_baton* create_baton (struct summarize_edit_baton *edit_baton,
+ svn_diff_summarize_t *summarize,
+ const char *path,
+ apr_pool_t *pool)
+{
+ struct summarize_baton *b = apr_palloc (pool, sizeof (*b));
+
+ b->edit_baton = edit_baton;
+ b->summarize = summarize;
+ b->path = apr_pstrdup (pool, path);
+
+ return b;
+}
+
+/* create a svn_diff_summarize_t struct
+*/
+svn_diff_summarize_t* create_summarize (svn_node_kind_t node_kind,
+ svn_diff_summarize_kind_t sum_kind,
+ const char* path,
+ const char* copyfrom_path,
+ svn_revnum_t copyfrom_rev,
+ svn_boolean_t text_changed,
+ svn_boolean_t prop_changed,
+ apr_pool_t* pool )
+{
+ svn_diff_summarize_t *sum = apr_palloc (pool, sizeof (*sum));
+
+ sum->node_kind = node_kind;
+ sum->summarize_kind = sum_kind;
+ sum->path = apr_pstrdup (pool, path);
+ sum->copyfrom_path = apr_pstrdup (pool, copyfrom_path);
+ sum->copyfrom_rev = copyfrom_rev;
+ sum->text_changed = text_changed;
+ sum->prop_changed = prop_changed;
+
+ return sum;
+}
+
+
+/* An editor function. The root of the comparison hierarchy */
+static svn_error_t *
+open_root (void *edit_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **root_baton)
+{
+ struct summarize_baton *sb;
+ svn_diff_summarize_t *sum;
+
+ sum = create_summarize (svn_node_dir, svn_diff_summarize_kind_unchanged,
+ "", NULL, SVN_INVALID_REVNUM,
+ FALSE, FALSE, pool);
+
+ sb = create_baton (edit_baton, sum, "", pool);
+
+ *root_baton = sb;
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+delete_entry (const char *path,
+ svn_revnum_t base_revision,
+ void *parent_baton,
+ apr_pool_t *pool)
+{
+ struct summarize_baton *sb = parent_baton;
+ struct summarize_edit_baton *seb = sb->edit_baton;
+ svn_diff_summarize_t *sum;
+ svn_node_kind_t kind;
+
+ /* We need to know if this is a directory or a file */
+ SVN_ERR (svn_ra_check_path (seb->ra_session,
+ path,
+ seb->revision,
+ &kind,
+ pool));
+
+ sum = create_summarize (kind, svn_diff_summarize_kind_deleted,
+ path, NULL, SVN_INVALID_REVNUM,
+ FALSE, FALSE, pool);
+
+ SVN_ERR (seb->summarize_func (seb->summarize_func_baton, sum, pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+add_directory (const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ apr_pool_t *pool,
+ void **child_baton)
+{
+ struct summarize_baton *pb = parent_baton;
+ struct summarize_baton *sb;
+ svn_diff_summarize_t *sum;
+
+ sum = create_summarize (svn_node_dir, svn_diff_summarize_kind_added,
+ path, copyfrom_path, copyfrom_revision,
+ FALSE, FALSE, pool);
+
+ sb = create_baton (pb->edit_baton, sum, path, pool);
+
+ *child_baton = sb;
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+open_directory (const char *path,
+ void *parent_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **child_baton)
+{
+ struct summarize_baton *pb = parent_baton;
+ struct summarize_baton *sb;
+ svn_diff_summarize_t *sum;
+
+ sum = create_summarize (svn_node_dir, svn_diff_summarize_kind_modified,
+ path, NULL, SVN_INVALID_REVNUM,
+ FALSE, FALSE, pool);
+
+ sb = create_baton (pb->edit_baton, sum, path, pool);
+
+ *child_baton = sb;
+ return SVN_NO_ERROR;
+}
+
+
+/* An editor function. */
+static svn_error_t *
+close_directory (void *dir_baton,
+ apr_pool_t *pool)
+{
+ struct summarize_baton *sb = dir_baton;
+ struct summarize_edit_baton *eb = sb->edit_baton;
+ svn_diff_summarize_t *sum = sb->summarize;
+
+ if (sum->summarize_kind != svn_diff_summarize_kind_unchanged)
+ {
+ SVN_ERR (eb->summarize_func (eb->summarize_func_baton, sum, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* An editor function. */
+static svn_error_t *
+add_file (const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ apr_pool_t *pool,
+ void **file_baton)
+{
+ struct summarize_baton *pb = parent_baton;
+ struct summarize_baton *sb;
+ svn_diff_summarize_t *sum;
+
+ sum = create_summarize (svn_node_file, svn_diff_summarize_kind_added,
+ path, copyfrom_path, copyfrom_revision,
+ FALSE, FALSE, pool);
+
+ sb = create_baton (pb->edit_baton, sum, path, pool);
+
+ *file_baton = sb;
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+open_file (const char *path,
+ void *parent_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **file_baton)
+{
+ struct summarize_baton *pb = parent_baton;
+ struct summarize_baton *sb;
+ svn_diff_summarize_t *sum;
+
+ sum = create_summarize (svn_node_file, svn_diff_summarize_kind_unchanged,
+ path, NULL, SVN_INVALID_REVNUM,
+ FALSE, FALSE, pool);
+
+ sb = create_baton (pb->edit_baton, sum, path, pool);
+
+ *file_baton = sb;
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+apply_textdelta (void *file_baton,
+ const char *base_checksum,
+ apr_pool_t *pool,
+ svn_txdelta_window_handler_t *handler,
+ void **handler_baton)
+{
+ struct summarize_baton *sb = file_baton;
+
+ sb->summarize->summarize_kind = svn_diff_summarize_kind_modified;
+ sb->summarize->text_changed = TRUE;
+
+ *handler = svn_delta_noop_window_handler;
+ *handler_baton = NULL;
+
+ return SVN_NO_ERROR;
+}
+
+
+/* An editor function. */
+static svn_error_t *
+close_file (void *file_baton,
+ const char *text_checksum,
+ apr_pool_t *pool)
+{
+ struct summarize_baton *sb = file_baton;
+ struct summarize_edit_baton *eb = sb->edit_baton;
+ svn_diff_summarize_t *sum = sb->summarize;
+
+ if (sum->summarize_kind != svn_diff_summarize_kind_unchanged)
+ {
+ SVN_ERR (eb->summarize_func (eb->summarize_func_baton, sum, pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* An editor function. */
+static svn_error_t *
+change_prop (void *entry_baton,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ struct summarize_baton *sb = entry_baton;
+
+ if (svn_property_kind (NULL,name) == svn_prop_regular_kind)
+ {
+ sb->summarize->summarize_kind = svn_diff_summarize_kind_modified;
+ sb->summarize->prop_changed = TRUE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Create a repository diff summarize editor and baton. */
+svn_error_t *
+svn_client__get_diff_summarize_editor (const char *target,
+ svn_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ svn_ra_session_t *ra_session,
+ svn_revnum_t revision,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ const svn_delta_editor_t **editor,
+ void **edit_baton,
+ apr_pool_t *pool)
+{
+ svn_delta_editor_t *tree_editor = svn_delta_default_editor (pool);
+ struct summarize_edit_baton *eb = apr_palloc (pool, sizeof (*eb));
+
+ eb->summarize_func = summarize_func;
+ eb->summarize_func_baton = summarize_baton;
+ eb->ra_session = ra_session;
+ eb->revision = revision;
+
+ tree_editor->open_root = open_root;
+
+ tree_editor->delete_entry = delete_entry;
+ tree_editor->add_directory = add_directory;
+ tree_editor->open_directory = open_directory;
+ tree_editor->change_dir_prop = change_prop;
+ tree_editor->close_directory = close_directory;
+
+ tree_editor->add_file = add_file;
+ tree_editor->open_file = open_file;
+ tree_editor->apply_textdelta = apply_textdelta;
+ tree_editor->change_file_prop = change_prop;
+ tree_editor->close_file = close_file;
+
+ SVN_ERR (svn_delta_get_cancellation_editor
+ (cancel_func, cancel_baton, tree_editor, eb, editor, edit_baton,
+ pool));
+
+ return SVN_NO_ERROR;
+}
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c (revision 16385)
+++ subversion/libsvn_ra_svn/client.c (working copy)
@@ -1070,6 +1070,7 @@
                                 svn_revnum_t rev, const char *target,
                                 svn_boolean_t recurse,
                                 svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
                                 const char *versus_url,
                                 const svn_delta_editor_t *diff_editor,
                                 void *diff_baton, apr_pool_t *pool)
@@ -1078,8 +1079,9 @@
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   /* Tell the server we want to start a diff. */
- SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "diff", "(?r)cbbc", rev, target,
- recurse, ignore_ancestry, versus_url));
+ SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "diff", "(?r)cbbcb", rev,
+ target, recurse, ignore_ancestry,
+ versus_url, text_deltas));
   SVN_ERR(handle_auth_request(sess_baton, pool));
 
   /* Fetch a reporter for the caller to drive. The reporter will drive
Index: subversion/libsvn_ra_svn/protocol
===================================================================
--- subversion/libsvn_ra_svn/protocol (revision 16385)
+++ subversion/libsvn_ra_svn/protocol (working copy)
@@ -293,7 +293,7 @@
 
   diff
     params: ( [ rev:number ] target:string recurse:bool ignore-ancestry:bool
- url:string )
+ url:string ? text-deltas:bool )
     Client switches to report command set.
     Upon finish-report, server sends auth-request.
     After auth exchange completes, server switches to editor command set.
Index: subversion/libsvn_ra_dav/ra_dav.h
===================================================================
--- subversion/libsvn_ra_dav/ra_dav.h (revision 16385)
+++ subversion/libsvn_ra_dav/ra_dav.h (working copy)
@@ -291,6 +291,7 @@
   const char *diff_target,
   svn_boolean_t recurse,
   svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
   const char *versus_url,
   const svn_delta_editor_t *wc_diff,
   void *wc_diff_baton,
Index: subversion/libsvn_ra_dav/fetch.c
===================================================================
--- subversion/libsvn_ra_dav/fetch.c (revision 16385)
+++ subversion/libsvn_ra_dav/fetch.c (working copy)
@@ -3196,6 +3196,7 @@
                                   const char *diff_target,
                                   svn_boolean_t recurse,
                                   svn_boolean_t ignore_ancestry,
+ svn_boolean_t text_deltas,
                                   const char *versus_url,
                                   const svn_delta_editor_t *wc_diff,
                                   void *wc_diff_baton,
@@ -3212,7 +3213,7 @@
                         FALSE,
                         wc_diff,
                         wc_diff_baton,
- TRUE, /* fetch_content */
+ text_deltas, /* fetch_content */
                         FALSE, /* send_all */
                         TRUE, /* spool_response */
                         pool);
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c (revision 16385)
+++ subversion/svnserve/serve.c (working copy)
@@ -1207,10 +1207,22 @@
   svn_revnum_t rev;
   const char *target, *versus_url, *versus_path;
   svn_boolean_t recurse, ignore_ancestry;
+ svn_boolean_t text_deltas;
 
   /* Parse the arguments. */
- SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "(?r)cbbc", &rev, &target,
- &recurse, &ignore_ancestry, &versus_url));
+ if (params->nelts == 5)
+ {
+ /* Clients before 1.4 don't send the text_deltas boolean. */
+ SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "(?r)cbbc", &rev, &target,
+ &recurse, &ignore_ancestry, &versus_url));
+ text_deltas = TRUE;
+ }
+ else
+ {
+ SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "(?r)cbbc?b", &rev, &target,
+ &recurse, &ignore_ancestry, &versus_url,
+ &text_deltas));
+ }
   target = svn_path_canonicalize(target, pool);
   versus_url = svn_path_canonicalize(versus_url, pool);
   SVN_ERR(trivial_auth_request(conn, pool, b));
@@ -1220,8 +1232,8 @@
                           svn_path_uri_decode(versus_url, pool),
                           &versus_path, pool));
 
- return accept_report(conn, pool, b, rev, target, versus_path, TRUE, recurse,
- ignore_ancestry);
+ return accept_report(conn, pool, b, rev, target, versus_path,
+ text_deltas, recurse, ignore_ancestry);
 }
 
 /* Send a log entry to the client. */

This is a small patch that adds a 's' option to svn diff to run the diff
summarize from the command line.

this patch is only intended for reviewing the diff summarize patch and
not for committing it to the repository.

* subversion/clients/cmdline/cl.h
  (svn_cl__opt_state_t): added summarize member.

* subversion/clients/cmdline/diff-cmd.c
  (generate_summarize_code,summarize_func): new functions.
  (svn_cl__diff): run diff summary if the summarize option is set.

* subversion/clients/cmdline/main.c
  (svn_cl__options): added summarize option.
  (main): added check if the summarize option is given as a parameter.

Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h (revision 16385)
+++ subversion/clients/cmdline/cl.h (working copy)
@@ -141,6 +141,7 @@
   svn_boolean_t autoprops; /* enable automatic properties */
   svn_boolean_t no_autoprops; /* disable automatic properties */
   const char *native_eol; /* override system standard eol marker */
+ svn_boolean_t summarize; /* diff summary */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/diff-cmd.c
===================================================================
--- subversion/clients/cmdline/diff-cmd.c (revision 16385)
+++ subversion/clients/cmdline/diff-cmd.c (working copy)
@@ -36,6 +36,32 @@
 
 /*** Code. ***/
 
+static char
+generate_summarize_code (enum svn_diff_summarize_kind kind)
+{
+ switch (kind)
+ {
+ case svn_diff_summarize_kind_added: return 'A';
+ //case svn_diff_summarize_kind_modified: return 'M';
+ case svn_diff_summarize_kind_deleted: return 'D';
+ default: return '?';
+ }
+}
+
+svn_error_t* summarize_func( void *summarize_baton,
+ svn_diff_summarize_t *diff,
+ apr_pool_t *pool)
+{
+ SVN_ERR (svn_cmdline_printf (pool, "%c%c%c %s\n",
+ diff->text_changed ? 'M' :
+ generate_summarize_code(diff->summarize_kind),
+ diff->prop_changed ? 'M' : ' ',
+ diff->node_kind == svn_node_dir ? 'F' : ' ',
+ diff->path));
+
+ return SVN_NO_ERROR;
+}
+
 /* An svn_opt_subcommand_t to handle the 'diff' command.
    This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
@@ -184,20 +210,36 @@
           target1 = svn_path_join (old_target, path, subpool);
           target2 = svn_path_join (new_target, path, subpool);
           
- SVN_ERR (svn_client_diff3 (options,
- target1,
- &(opt_state->start_revision),
- target2,
- &(opt_state->end_revision),
- opt_state->nonrecursive ? FALSE : TRUE,
- opt_state->notice_ancestry ? FALSE : TRUE,
- opt_state->no_diff_deleted,
- opt_state->force,
- svn_cmdline_output_encoding (pool),
- outfile,
- errfile,
- ((svn_cl__cmd_baton_t *)baton)->ctx,
- pool));
+ if (! opt_state->summarize)
+ {
+ SVN_ERR (svn_client_diff3 (options,
+ target1,
+ &(opt_state->start_revision),
+ target2,
+ &(opt_state->end_revision),
+ opt_state->nonrecursive ? FALSE : TRUE,
+ opt_state->notice_ancestry ? FALSE : TRUE,
+ opt_state->no_diff_deleted,
+ opt_state->force,
+ svn_cmdline_output_encoding (pool),
+ outfile,
+ errfile,
+ ((svn_cl__cmd_baton_t *)baton)->ctx,
+ pool));
+ }
+ else
+ {
+ SVN_ERR (svn_client_diff_summarize
+ (target1,
+ &(opt_state->start_revision),
+ target2,
+ &(opt_state->end_revision),
+ opt_state->nonrecursive ? FALSE : TRUE,
+ opt_state->notice_ancestry ? FALSE : TRUE,
+ summarize_func, pool,
+ ((svn_cl__cmd_baton_t *)baton)->ctx,
+ pool));
+ }
         }
       else
         {
@@ -212,22 +254,40 @@
             peg_revision.kind = svn_path_is_url (path)
               ? svn_opt_revision_head : svn_opt_revision_working;
 
- SVN_ERR (svn_client_diff_peg3 (options,
- truepath,
- &peg_revision,
- &opt_state->start_revision,
- &opt_state->end_revision,
- opt_state->nonrecursive
- ? FALSE : TRUE,
- opt_state->notice_ancestry
- ? FALSE : TRUE,
- opt_state->no_diff_deleted,
- opt_state->force,
- svn_cmdline_output_encoding(pool),
- outfile,
- errfile,
- ((svn_cl__cmd_baton_t *)baton)->ctx,
- pool));
+ if (! opt_state->summarize)
+ {
+ SVN_ERR (svn_client_diff_peg3 (options,
+ truepath,
+ &peg_revision,
+ &opt_state->start_revision,
+ &opt_state->end_revision,
+ opt_state->nonrecursive
+ ? FALSE : TRUE,
+ opt_state->notice_ancestry
+ ? FALSE : TRUE,
+ opt_state->no_diff_deleted,
+ opt_state->force,
+ svn_cmdline_output_encoding(pool),
+ outfile,
+ errfile,
+ ((svn_cl__cmd_baton_t *)baton)->ctx,
+ pool));
+ }
+ else
+ {
+ SVN_ERR (svn_client_diff_summarize_peg
+ (truepath,
+ &peg_revision,
+ &opt_state->start_revision,
+ &opt_state->end_revision,
+ opt_state->nonrecursive
+ ? FALSE : TRUE,
+ opt_state->notice_ancestry
+ ? FALSE : TRUE,
+ summarize_func, pool,
+ ((svn_cl__cmd_baton_t *)baton)->ctx,
+ pool));
+ }
         }
     }
   svn_pool_destroy (subpool);
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c (revision 16385)
+++ subversion/clients/cmdline/main.c (working copy)
@@ -151,6 +151,8 @@
                       N_("maximum number of log entries")},
     {"no-unlock", svn_cl__no_unlock_opt, 0,
                       N_("don't unlock the targets")},
+ {"summarize", 's', 0,
+ N_("diff summary")},
     {0, 0, 0, 0}
   };
 
@@ -312,7 +314,7 @@
     {'r', svn_cl__old_cmd_opt, svn_cl__new_cmd_opt, 'N',
      svn_cl__diff_cmd_opt, 'x', svn_cl__no_diff_deleted,
      svn_cl__notice_ancestry_opt, svn_cl__force_opt, SVN_CL__AUTH_OPTIONS,
- svn_cl__config_dir_opt} },
+ svn_cl__config_dir_opt, 'p'} },
 
   { "export", svn_cl__export, {0},
     N_("Create an unversioned copy of a tree.\n"
@@ -1116,6 +1118,8 @@
       case svn_cl__no_unlock_opt:
         opt_state.no_unlock = TRUE;
         break;
+ case 'p':
+ opt_state.summarize = TRUE;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sun Oct 2 14:59:24 2005

This is an archived mail posted to the Subversion Dev mailing list.