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

[PATCH] V2, diff preview without text deltas

From: Martin Hauner <martin.hauner_at_gmx.net>
Date: 2005-08-12 19:07:05 CEST

Hi,

attached is a second version of a patch for the diff preview api call
(which the gui clients like to have) that doesn't produce text deltas.

I have updated it based on Julians notes and changed and cleaned up
a few other things.

Since the first version is a couple of weeks old i repeat a few notes:

* this is an api only patch. For easier review i have created a small
   patch to run the preview from the command line.

* there is a lot of code duplication between the diff and the diff
   preview code that i want to address in another patch if the preview
   stuff makes it into the repository.

* the preview handles only the repository <-> repoditory case for now.
   the other combinations are another thing i would like to address in
   different patches.

Unsolved problem
----------------

The open_file slot in the diff editor is called for files that are
not changed (a diff shows no text differences). These files don't
show up in a normal diff.

It looks like this has something todo with merging.

After creating a branch from trunk and merging several files from
trunk to that branch (making the files on the branch and trunk equal
again (text content)) they appear in a diff preview between the
branch and trunk.

Is this supposed to happen (ie. open_file is called for such files)?
And if so how do i recognize this situation so i can filter those
files?

minor version compatibility:
----------------------------

The preview patch adds an optional boolean to do_diff.

To handle minor version compatibility i modified vparse_tuple to
handle optional bool values simply by not returning an error. This
requires to initialize the optional bool before calling vparse_tuple.

preview or summarize:
---------------------

How should it be named? preview or summarize?
I named it preview after the inital confusion with #issue 2015
(summarize) because my patch doesn't really solve that issue.
But i have to problem with changing it again to summarize.

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

Added new svn_client api calls svn_diff_preview & svn_diff_preview_peg.
A diff preview 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): hardcoded TRUE as value for the new 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_preview,svn_client_diff_preview_peg): new methods.
  (svn_diff_preview_func_t): new callback type used by
  svn_client_diff_preview and svn_client_diff_preview_peg.
  (svn_diff_preview_t): new struct used by svn_diff_preview_func_t.
  (svn_diff_preview_kind): new enum type used by svn_diff_preview_t.

* subversion/libsvn_client/client.h
  (svn_client__get_diff_preview_editor): new method, implemented in
  subversion/libsvn_client/repos_diff_preview.c.
  
* subversion/libsvn_client/repos_diff_preview.c
  new file, the implementation of the diff preview 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 methods used to
  remove most of the code duplication between diff and diff preview.
  (diff_preview_repos_repos): do diff preview between two repository
  paths.
  (do_diff_preview): new method, diff preview without peg revision.
  (do_diff_preview_peg): new method, diff preview with peg revision.
  (svn_client_diff_preview): new method, implemementation of public api
  diff preview function (without peg revision).
  (svn_client_diff_preview_peg): new method, implemementation of public
  api diff preview peg function.
  
* 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/marshal.c
  (vparse_tuple): handle optional bool value.

* 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 15693)
+++ subversion/libsvn_ra/wrapper_template.h (working copy)
@@ -287,8 +287,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 15693)
+++ subversion/libsvn_ra/ra_loader.c (working copy)
@@ -409,6 +409,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,
@@ -423,7 +442,8 @@
 {
   return session->vtable->do_diff (session, reporter, report_baton, revision,
                                    diff_target, recurse, ignore_ancestry,
- versus_url, diff_editor, diff_baton, pool);
+ 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 15693)
+++ 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 15693)
+++ subversion/include/svn_client.h (working copy)
@@ -500,6 +500,64 @@
 svn_client_commit_info2_t *
 svn_client_create_commit_info (apr_pool_t *pool);
 
+
+/** the difference type in an svn_diff_preview_t structure.
+ *
+ * @since New in 1.3.
+ */
+typedef enum svn_diff_preview_kind
+{
+ /** an unchagned item */
+ svn_diff_preview_kind_unchanged,
+
+ /** an added item */
+ svn_diff_preview_kind_added,
+
+ /** a modified item */
+ svn_diff_preview_kind_modified,
+
+ /** a deleted item */
+ svn_diff_preview_kind_deleted
+
+} svn_diff_preview_kind_t;
+
+
+/** a struct that describes the diff of an item. Passed to
+ * svn_diff_preview_func_t.
+ *
+ * @since New in 1.3.
+ */
+typedef struct svn_diff_preview_t
+{
+ /** file or dir */
+ svn_node_kind_t node_kind;
+
+ /** item paths, relative to the old diff target and new diff target */
+ const char* path_old;
+ const char* path_new;
+
+ /** change kind: unchanged, added, modified or deleted */
+ svn_diff_preview_kind_t preview_kind;
+
+ /** properties changed? */
+ svn_boolean_t props_changed;
+
+} svn_diff_preview_t;
+
+
+/** A callback used in svn_client_diff_preview for reporting a @a diff
+ * preview.
+ *
+ * @a baton is a closure object; it should be provided by the
+ * implementation, and passed by the caller.
+ *
+ * @since New in 1.3.
+ */
+typedef svn_error_t *
+(*svn_diff_preview_func_t) (void *preview_baton,
+ svn_diff_preview_t *diff);
+
+
 /**
  * Checkout a working copy of @a URL at @a revision, looked up at @a
  * peg_revision, using @a path as the root directory of the newly
@@ -1246,6 +1304,57 @@
                                   svn_client_ctx_t *ctx,
                                   apr_pool_t *pool);
 
+/**
+ * Produce a diff preview 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.
+ *
+ * Calls @a preview_func with @a preview_baton for each difference with
+ * a @c svn_diff_preview_t * structure describing the difference.
+ *
+ * See svn_client_diff3 for a description of the other parameters.
+ *
+ * @since New in 1.3.
+ */
+svn_error_t *
+svn_client_diff_preview (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_boolean_t no_diff_deleted,
+ svn_diff_preview_func_t preview_func,
+ void *preview_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool);
+
+/**
+ * Produce a diff preview 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.
+ *
+ * Calls @a preview_func with @a preview_baton for each difference with
+ * a @c svn_diff_preview_t * structure describing the difference.
+ *
+ * See svn_client_diff_peg3 for a description of the other parameters.
+ *
+ * @since New in 1.3.
+ */
+svn_error_t *
+svn_client_diff_preview_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_boolean_t no_diff_deleted,
+ svn_diff_preview_func_t preview_func,
+ void *preview_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 15693)
+++ subversion/include/svn_ra.h (working copy)
@@ -761,10 +761,31 @@
  * 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.
+ *
  * Use @a pool for memory allocation.
  *
- * @since New in 1.2.
+ * @since New in 1.3.
  */
+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 15693)
+++ 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 15693)
+++ subversion/libsvn_client/client.h (working copy)
@@ -400,6 +400,37 @@
 
 /* ---------------------------------------------------------------- */
 
+/*** Editor for diff preview ***/
+
+/* Create an editor for a repository diff preview, i.e. comparing one
+ * repository version against the other and only providing information
+ * about the changed items without the text delta.
+ *
+ * @preview_func is called with @a preview_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_preview_editor (const char *target,
+ svn_wc_adm_access_t *adm_access,
+ svn_diff_preview_func_t preview_func,
+ void *preview_baton,
+ svn_boolean_t recurse,
+ svn_boolean_t dry_run,
+ svn_ra_session_t *ra_session,
+ svn_revnum_t revision,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ 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 15693)
+++ subversion/libsvn_client/diff.c (working copy)
@@ -1397,8 +1397,243 @@
   return SVN_NO_ERROR;
 }
 
+/** Helper structure: for passing around the diff parameters */
+struct diff_parameters
+{
+ /* 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));
+
+ /* @todo copy info when called from diff_repos_repos */
+ /* 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,
+ 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));
+ /* @todo copy info when called from diff_repos_repos */
+ /* callback_baton->revnum1 = rev1; */
+ SVN_ERR (svn_client__get_revision_number
+ (&drr->rev2, ra_session2, params->revision2,
+ (params->path2 == drr->url2) ? NULL : params->path2, pool));
+ /* @todo copy info when called from diff_repos_repos */
+ /* callback_baton->revnum2 = rev2; */
+
+ /* 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.
@@ -2215,7 +2450,147 @@
   return SVN_NO_ERROR;
 }
 
+/* Perform a diff preview between two repository paths. */
+static svn_error_t *
+diff_preview_repos_repos (const struct diff_parameters* diff_param,
+ svn_diff_preview_func_t preview_func,
+ void *preview_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ 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;
+
+ 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_preview_editor
+ (drr.base_path ? drr.base_path : "", NULL, preview_func,
+ preview_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_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_preview(). */
+static svn_error_t *
+do_diff_preview (const struct diff_parameters* diff_param,
+ svn_diff_preview_func_t preview_func,
+ void *preview_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 (diff_paths.is_repos_path2) /* path2 is (effectively) a URL */
+ {
+ SVN_ERR (diff_preview_repos_repos (diff_param, preview_func,
+ preview_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_repos_path2) /* path2 is (effectively) a URL */
+ {
+ 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_preview_peg(). */
+static svn_error_t *
+do_diff_preview_peg (const struct diff_parameters* diff_param,
+ svn_diff_preview_func_t preview_func,
+ void *preview_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_preview_repos_repos (diff_param, preview_func,
+ preview_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
+ {
+ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE,
+ NULL, NULL);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
 /*----------------------------------------------------------------------- */
 
 /*** Public Interfaces. ***/
@@ -2448,6 +2823,68 @@
 }
 
 svn_error_t *
+svn_client_diff_preview (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_boolean_t no_diff_deleted,
+ svn_diff_preview_func_t preview_func,
+ void *preview_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.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;
+
+ return do_diff_preview (&diff_params, preview_func, preview_baton,
+ ctx, pool);
+}
+
+svn_error_t *
+svn_client_diff_preview_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_boolean_t no_diff_deleted,
+ svn_diff_preview_func_t preview_func,
+ void *preview_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct diff_parameters diff_params;
+
+ /* fill diff_param */
+ 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;
+
+ return do_diff_preview_peg (&diff_params, preview_func, preview_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_preview.c
===================================================================
--- subversion/libsvn_client/repos_diff_preview.c (revision 0)
+++ subversion/libsvn_client/repos_diff_preview.c (revision 0)
@@ -0,0 +1,398 @@
+/*
+ * repos_diff_preview.c -- The diff preview editor for previewing 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 preview_edit_baton {
+
+ /* The preview callback passed down from the api */
+ svn_diff_preview_func_t preview_func;
+
+ /* The preview callback baton */
+ void *preview_func_baton;
+};
+
+
+/* item baton.
+ */
+struct preview_baton {
+
+ /* the overall crawler editor baton */
+ struct preview_edit_baton *edit_baton;
+
+ /* the preview filled by the editor calls */
+ svn_diff_preview_t *preview;
+
+ /* The path of the file or directory within the repository */
+ const char *path;
+};
+
+/* An editor function. The root of the comparison hierarchy */
+static svn_error_t *
+set_target_revision (void *edit_baton,
+ svn_revnum_t target_revision,
+ apr_pool_t *pool)
+{
+ return SVN_NO_ERROR;
+}
+
+/* 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 preview_baton *nb = apr_palloc (pool, sizeof (*nb));
+ svn_diff_preview_t *diff = apr_palloc (pool, sizeof (*diff));
+
+ diff->node_kind = svn_node_dir;
+ diff->preview_kind = svn_diff_preview_kind_unchanged;
+ diff->path_old = NULL;
+ diff->path_new = NULL;
+ diff->props_changed = FALSE;
+
+ nb->edit_baton = edit_baton;
+ nb->preview = diff;
+ nb->path = NULL;
+
+ *root_baton = nb;
+ 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 preview_baton *pb = parent_baton;
+ svn_diff_preview_t *diff = apr_palloc (pool, sizeof (*diff));
+ struct preview_edit_baton *eb = pb->edit_baton;
+
+ diff->node_kind = svn_node_file;
+ diff->preview_kind = svn_diff_preview_kind_deleted;
+ diff->path_old = apr_pstrdup (pool, path);
+ diff->path_new = NULL;
+ diff->props_changed = FALSE;
+
+ SVN_ERR (eb->preview_func (eb->preview_func_baton,diff));
+
+ 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 preview_baton *pb = parent_baton;
+ struct preview_baton *nb = apr_palloc (pool, sizeof (*nb));
+ svn_diff_preview_t *diff = apr_palloc (pool, sizeof (*diff));
+
+ nb->edit_baton = pb->edit_baton;
+ nb->preview = diff;
+ nb->path = apr_pstrdup (pool, path);
+
+ diff->node_kind = svn_node_dir;
+ diff->preview_kind = svn_diff_preview_kind_added;
+ diff->path_old = apr_pstrdup (pool, copyfrom_path);
+ diff->path_new = apr_pstrdup (pool, path);
+ diff->props_changed = FALSE;
+
+ *child_baton = nb;
+ 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 preview_baton *pb = parent_baton;
+ struct preview_baton *nb = apr_palloc (pool, sizeof (*nb));
+ svn_diff_preview_t *diff = apr_palloc (pool, sizeof (*diff));
+
+ nb->edit_baton = pb->edit_baton;
+ nb->preview = diff;
+ nb->path = apr_pstrdup (pool, path);
+
+ diff->node_kind = svn_node_dir;
+ diff->preview_kind = svn_diff_preview_kind_modified;
+ diff->path_old = NULL;
+ diff->path_new = apr_pstrdup (pool, path);
+ diff->props_changed = FALSE;
+
+ *child_baton = nb;
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+change_dir_prop (void *dir_baton,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ struct preview_baton *pb = dir_baton;
+
+ if ( svn_property_kind (NULL,name) == svn_prop_regular_kind )
+ {
+ pb->preview->props_changed = TRUE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+close_directory (void *dir_baton,
+ apr_pool_t *pool)
+{
+ struct preview_baton *pb = dir_baton;
+ svn_diff_preview_t *diff = pb->preview;
+ struct preview_edit_baton *eb = pb->edit_baton;
+
+ if (!diff->path_old) /* ignore empty root */
+ return SVN_NO_ERROR;
+
+ if (diff->preview_kind != svn_diff_preview_kind_unchanged
+ || diff->props_changed)
+ {
+ SVN_ERR (eb->preview_func (eb->preview_func_baton,diff));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+absent_directory (const char *path,
+ void *parent_baton,
+ apr_pool_t *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 preview_baton *pb = parent_baton;
+ struct preview_baton *nb = apr_pcalloc (pool, sizeof (*nb));
+ svn_diff_preview_t *diff = apr_pcalloc (pool, sizeof (*diff));
+
+ nb->edit_baton = pb->edit_baton;
+ nb->preview = diff;
+ nb->path = apr_pstrdup (pool, path);
+
+ diff->node_kind = svn_node_file;
+ diff->preview_kind = svn_diff_preview_kind_added;
+ diff->path_old = apr_pstrdup (pool, copyfrom_path);
+ diff->path_new = apr_pstrdup (pool, path);
+ diff->props_changed = FALSE;
+
+ *file_baton = nb;
+ 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)
+{
+ /*
+ This code is also called for files that are not changed.
+
+ It looks like this has something todo with merging.
+
+ After creating a branch from trunk and merging several files
+ from trunk to that branch (making the files on the branch and
+ trunk equal again) they appear in a diff preview between the
+ branch and trunk.
+
+ Is this supposed to happen? And if so how do i recognize
+ this situation so i can filter those files?
+ */
+ struct preview_baton *pb = parent_baton;
+ struct preview_baton *nb = apr_palloc (pool, sizeof (*nb));
+ svn_diff_preview_t *diff = apr_palloc (pool, sizeof (*diff));
+
+ nb->edit_baton = pb->edit_baton;
+ nb->preview = diff;
+ nb->path = apr_pstrdup (pool, path);
+
+ diff->node_kind = svn_node_file;
+ diff->preview_kind = svn_diff_preview_kind_modified;
+ diff->path_old = NULL;
+ diff->path_new = apr_pstrdup (pool, path);
+ diff->props_changed = FALSE;
+
+ *file_baton = nb;
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. Do the work of applying the text delta. */
+static svn_error_t *
+window_handler (svn_txdelta_window_t *window,
+ void *window_baton)
+{
+ 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)
+{
+ *handler = svn_delta_noop_window_handler;
+ *handler_baton = NULL;
+
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+change_file_prop (void *file_baton,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ struct preview_baton *pb = file_baton;
+
+ if ( svn_property_kind (NULL,name) == svn_prop_regular_kind )
+ {
+ pb->preview->props_changed = TRUE;
+ }
+
+ 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 preview_baton *pb = file_baton;
+ struct preview_edit_baton *eb = pb->edit_baton;
+
+ SVN_ERR (eb->preview_func (eb->preview_func_baton,pb->preview));
+
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+absent_file (const char *path,
+ void *parent_baton,
+ apr_pool_t *pool)
+{
+ struct preview_dir_baton *pb = parent_baton;
+
+ return SVN_NO_ERROR;
+}
+
+/* An editor function. */
+static svn_error_t *
+close_edit (void *edit_baton,
+ apr_pool_t *pool)
+{
+ return SVN_NO_ERROR;
+}
+
+
+
+/* Create a repository diff preview editor and baton. */
+svn_error_t *
+svn_client__get_diff_preview_editor (const char *target,
+ svn_wc_adm_access_t *adm_access,
+ svn_diff_preview_func_t preview_func,
+ void *preview_baton,
+ svn_boolean_t recurse,
+ svn_boolean_t dry_run,
+ svn_ra_session_t *ra_session,
+ svn_revnum_t revision,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ const svn_delta_editor_t **editor,
+ void **edit_baton,
+ apr_pool_t *pool)
+{
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ svn_delta_editor_t *tree_editor = svn_delta_default_editor (subpool);
+ struct preview_edit_baton *eb = apr_palloc (subpool, sizeof (*eb));
+
+ eb->preview_func = preview_func;
+ eb->preview_func_baton = preview_baton;
+
+ tree_editor->set_target_revision = set_target_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_dir_prop;
+ tree_editor->close_directory = close_directory;
+ tree_editor->absent_directory = absent_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_file_prop;
+ tree_editor->close_file = close_file;
+ tree_editor->absent_file = absent_file;
+
+ tree_editor->close_edit = close_edit;
+
+ 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 15693)
+++ subversion/libsvn_ra_svn/client.c (working copy)
@@ -1050,6 +1050,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)
@@ -1058,8 +1059,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 15693)
+++ subversion/libsvn_ra_svn/protocol (working copy)
@@ -292,7 +292,8 @@
     response: ( )
 
   diff
- params: ( [ rev:number ] target:string recurse:bool url:string )
+ params: ( [ rev:number ] target:string recurse:bool ignore-ancestry:bool
+ 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_svn/marshal.c
===================================================================
--- subversion/libsvn_ra_svn/marshal.c (revision 15693)
+++ subversion/libsvn_ra_svn/marshal.c (working copy)
@@ -691,6 +691,10 @@
             case 'n':
               *va_arg(*ap, apr_uint64_t *) = SVN_RA_SVN_UNSPECIFIED_NUMBER;
               break;
+ case 'b':
+ /* an optional bool value is supposed to have a default value
+ already set, so simply skip over it. */
+ break;
             case '(':
               list_level++;
               break;
Index: subversion/libsvn_ra_dav/ra_dav.h
===================================================================
--- subversion/libsvn_ra_dav/ra_dav.h (revision 15693)
+++ subversion/libsvn_ra_dav/ra_dav.h (working copy)
@@ -290,6 +290,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 15693)
+++ subversion/libsvn_ra_dav/fetch.c (working copy)
@@ -3197,6 +3197,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,
@@ -3213,7 +3214,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 15693)
+++ subversion/svnserve/serve.c (working copy)
@@ -1035,10 +1035,12 @@
   svn_revnum_t rev;
   const char *target, *versus_url, *versus_path;
   svn_boolean_t recurse, ignore_ancestry;
+ svn_boolean_t text_deltas = TRUE; /* set default for optional bool */
 
   /* Parse the arguments. */
- SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "(?r)cbbc", &rev, &target,
- &recurse, &ignore_ancestry, &versus_url));
+ 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));
@@ -1048,8 +1050,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 'p' option to svn diff to run the diff
preview from the command line.

this patch is only intended for reviewing the diff preview patch and not
for commit to the repository.

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

* subversion/clients/cmdline/diff-cmd.c
  (generate_preview_code,preview_func): new methods.
  (svn_cl__diff): run diff preview if the preview option is set.

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

Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h (revision 15693)
+++ 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 preview; /* diff preview */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/diff-cmd.c
===================================================================
--- subversion/clients/cmdline/diff-cmd.c (revision 15693)
+++ subversion/clients/cmdline/diff-cmd.c (working copy)
@@ -36,6 +36,41 @@
 
 /*** Code. ***/
 
+static char
+generate_preview_code (enum svn_diff_preview_kind kind)
+{
+ switch (kind)
+ {
+ case svn_diff_preview_kind_added: return 'A';
+ case svn_diff_preview_kind_modified: return 'M';
+ case svn_diff_preview_kind_deleted: return 'D';
+ default: return '?';
+ }
+}
+
+svn_error_t* preview_func( void *preview_baton, svn_diff_preview_t *diff )
+{
+ apr_pool_t* pool = preview_baton;
+ const char *path;
+
+ if( diff->preview_kind == svn_diff_preview_kind_deleted )
+ {
+ path = diff->path_old;
+ }
+ else
+ {
+ path = diff->path_new;
+ }
+
+ SVN_ERR (svn_cmdline_printf (pool, "%c%c%c %s\n",
+ generate_preview_code(diff->preview_kind),
+ diff->props_changed ? 'M' : ' ',
+ diff->node_kind == svn_node_dir ? 'F' : ' ',
+ 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 +219,37 @@
           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->preview)
+ {
+ 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_preview
+ (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,
+ preview_func, pool,
+ ((svn_cl__cmd_baton_t *)baton)->ctx,
+ pool));
+ }
         }
       else
         {
@@ -212,22 +264,41 @@
             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->preview)
+ {
+ 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_preview_peg
+ (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,
+ preview_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 15693)
+++ 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")},
+ {"preview", 'p', 0,
+ N_("diff preview")},
     {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"
@@ -1105,6 +1107,8 @@
       case svn_cl__no_unlock_opt:
         opt_state.no_unlock = TRUE;
         break;
+ case 'p':
+ opt_state.preview = 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 Fri Aug 12 21:05:50 2005

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

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.