You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2013/01/25 00:25:35 UTC

svn commit: r1438261 - in /subversion/trunk: build.conf subversion/include/private/svn_diff_tree.h subversion/libsvn_diff/diff_tree.c

Author: rhuijben
Date: Thu Jan 24 23:25:34 2013
New Revision: 1438261

URL: http://svn.apache.org/viewvc?rev=1438261&view=rev
Log:
To allow resolving serveral open issues in the repository diff support (missing
information) and merge handling (tree conflicts involving deletes), add an
improved diff callback infrastructure.

To avoid having to rev the entire api again in the next version, I pass the
structure itself to all functions. This allows future implementations to
call older functions without breaking backwards compatibility.

This commits add the processing infrastructure, including a processor that
reverses all operations. Future separate commits will include a wrapper to
the old diff api and an update to the repository diff editor to use this
new infrastructure while staying compatible via the wrapper.

* build.conf
  (libsvn_diff): Add header to exports.

* subversion/include/private/svn_diff_tree.h
  New file.
  (svn_diff_source_t): New struct.
  (svn_diff_tree_processor_t): New struct.

  (svn_diff__tree_processor_create): New function.
  (svn_diff__tree_processor_reverse_create): New function.
  (svn_diff__source_create): New function.

* subversion/include/private/svn_diff_tree.h
  New file.
  (svn_diff__tree_processor_create,
  (svn_diff__tree_processor_reverse_create,
  (svn_diff__source_create): Implement these functions using a large number of
    static helper functions.

Added:
    subversion/trunk/subversion/include/private/svn_diff_tree.h   (with props)
    subversion/trunk/subversion/libsvn_diff/diff_tree.c   (with props)
Modified:
    subversion/trunk/build.conf

Modified: subversion/trunk/build.conf
URL: http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1438261&r1=1438260&r2=1438261&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Thu Jan 24 23:25:34 2013
@@ -230,7 +230,7 @@ type = lib
 path = subversion/libsvn_diff
 libs = libsvn_subr apriconv apr zlib
 install = lib
-msvc-export = svn_diff.h private\svn_diff_private.h
+msvc-export = svn_diff.h private/svn_diff_private.h private/svn_diff_tree.h
 
 # The repository filesystem library
 [libsvn_fs]

Added: subversion/trunk/subversion/include/private/svn_diff_tree.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_diff_tree.h?rev=1438261&view=auto
==============================================================================
--- subversion/trunk/subversion/include/private/svn_diff_tree.h (added)
+++ subversion/trunk/subversion/include/private/svn_diff_tree.h Thu Jan 24 23:25:34 2013
@@ -0,0 +1,234 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file svn_wc.h
+ * @brief Generic diff handler. Replacing the old svn_wc_diff_callbacks4_t
+ * infrastructure
+ */
+
+#ifndef SVN_DIFF_PROCESSOR_H
+#define SVN_DIFF_PROCESSOR_H
+
+#include "svn_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct svn_diff_source_t
+{
+  /* Always available */
+  svn_revnum_t revision;
+
+  /* Depending on the driver */
+  /*const char *repos_relpath;
+  const char *local_abspath;*/
+} svn_diff_source_t;
+
+/**
+ * A callback vtable invoked by our diff-editors, as they receive diffs
+ * from the server. 'svn diff' and 'svn merge' implement their own versions
+ * of this vtable.
+ *
+ * All callbacks receive the processor and at least a parent baton. Forwarding
+ * the processor allows future extensions to call into the old functions without
+ * revving the entire API.
+ *
+ * Users must call svn_diff__tree_processor_create() to allow adding new
+ * callbacks later. (E.g. when we decide how to add move support) These
+ * extensions can then just call into other callbacks.
+ *
+ * @since New in 1.8.
+ */
+typedef struct svn_diff_tree_processor_t
+{
+  /** The value passed to svn_diff__tree_processor_create() as BATON.
+   */
+  void *baton; /* To avoid an additional in some places */
+
+  /* Called before a directories children are processed.
+   *
+   * Set *SKIP_CHILDREN to TRUE, to skip calling callbacks for all
+   * children.
+   *
+   * Set *SKIP to TRUE to skip calling the added, deleted, changed
+   * or closed callback for this node only.
+   */
+  svn_error_t *
+  (*dir_opened)(void **new_dir_baton,
+                svn_boolean_t *skip,
+                svn_boolean_t *skip_children,
+                const char *relpath,
+                const svn_diff_source_t *left_source,
+                const svn_diff_source_t *right_source,
+                const svn_diff_source_t *copyfrom_source,
+                void *parent_dir_baton,
+                const struct svn_diff_tree_processor_t *processor,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool);
+
+  /* Called after a directory and all its children are added
+   */
+  svn_error_t *
+  (*dir_added)(const char *relpath,
+               const svn_diff_source_t *copyfrom_source,
+               const svn_diff_source_t *right_source,
+               /*const*/ apr_hash_t *copyfrom_props,
+               /*const*/ apr_hash_t *right_props,
+               void *dir_baton,
+               const struct svn_diff_tree_processor_t *processor,
+               apr_pool_t *scratch_pool);
+
+  /* Called after all children of this node are reported as deleted.
+   *
+   * The default implementation calls dir_closed().
+   */
+  svn_error_t *
+  (*dir_deleted)(const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 /*const*/ apr_hash_t *left_props,
+                 void *dir_baton,
+                 const struct svn_diff_tree_processor_t *processor,
+                 apr_pool_t *scratch_pool);
+
+  /* Called instead of dir_closed() if the properties on the directory
+   *  were modified.
+   *
+   * The default implementation calls dir_closed().
+   */
+  svn_error_t *
+  (*dir_changed)(const char *relpath,
+                const svn_diff_source_t *left_source,
+                const svn_diff_source_t *right_source,
+                /*const*/ apr_hash_t *left_props,
+                /*const*/ apr_hash_t *right_props,
+                const apr_array_header_t *prop_changes,
+                void *dir_baton,
+                const struct svn_diff_tree_processor_t *processor,
+                apr_pool_t *scratch_pool);
+
+  /* Called when a directory is closed without applying changes to
+   * the directory itself.
+   *
+   * When dir_changed or dir_deleted are handled by the default implementation
+   * they call dir_closed()
+   */
+  svn_error_t *
+  (*dir_closed)(const char *relpath,
+                const svn_diff_source_t *left_source,
+                const svn_diff_source_t *right_source,
+                void *dir_baton,
+                const struct svn_diff_tree_processor_t *processor,
+                apr_pool_t *scratch_pool);
+
+  /* Called before file_added(), file_deleted(), file_changed() and
+     file_closed()
+   */
+  svn_error_t *
+  (*file_opened)(void **new_file_baton,
+                 svn_boolean_t *skip,
+                 const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 const svn_diff_source_t *right_source,
+                 const svn_diff_source_t *copyfrom_source,
+                 void *dir_baton,
+                 const struct svn_diff_tree_processor_t *processor,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool);
+
+  svn_error_t *
+  (*file_added)(const char *relpath,
+                const svn_diff_source_t *copyfrom_source,
+                const svn_diff_source_t *right_source,
+                const char *copyfrom_file,
+                const char *right_file,
+                /*const*/ apr_hash_t *copyfrom_props,
+                /*const*/ apr_hash_t *right_props,
+                void *file_baton,
+                const struct svn_diff_tree_processor_t *processor,
+                apr_pool_t *scratch_pool);
+
+  svn_error_t *
+  (*file_deleted)(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const char *left_file,
+                  /*const*/ apr_hash_t *left_props,
+                  void *file_baton,
+                  const struct svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool);
+
+  svn_error_t *
+  (*file_changed)(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const svn_diff_source_t *right_source,
+                  const char *left_file,
+                  const char *right_file,
+                  /*const*/ apr_hash_t *left_props,
+                  /*const*/ apr_hash_t *right_props,
+                  svn_boolean_t file_modified,
+                  const apr_array_header_t *prop_changes,
+                  void *file_baton,
+                  const struct svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool);
+
+  svn_error_t *
+  (*file_closed)(const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 const svn_diff_source_t *right_source,
+                 void *file_baton,
+                 const struct svn_diff_tree_processor_t *processor,
+                 apr_pool_t *scratch_pool);
+} svn_diff_tree_processor_t;
+
+/**
+ * Create a new svn_diff_tree_processor_t instance with all functions
+ * set to a callback doing nothing but copying the parent baton to
+ * the new baton.
+ *
+ * @since New in 1.8.
+ */
+svn_diff_tree_processor_t *
+svn_diff__tree_processor_create(void *baton,
+                                apr_pool_t *result_pool);
+
+/**
+ * Create a new svn_diff_tree_processor_t instance with all functions setup
+ * to call into another svn_diff_tree_processor_t processor, but with all
+ * adds and deletes inverted.
+ *
+ * @since New in 1.8.
+ */ /* Used by libsvn clients repository diff */
+const svn_diff_tree_processor_t *
+svn_diff__tree_processor_reverse_create(svn_diff_tree_processor_t * processor,
+                                        const char *prefix_relpath,
+                                        apr_pool_t *result_pool);
+
+svn_diff_source_t *
+svn_diff__source_create(svn_revnum_t revision,
+                        apr_pool_t *result_pool);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* SVN_DIFF_PROCESSOR_H */
+

Propchange: subversion/trunk/subversion/include/private/svn_diff_tree.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/trunk/subversion/libsvn_diff/diff_tree.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/diff_tree.c?rev=1438261&view=auto
==============================================================================
--- subversion/trunk/subversion/libsvn_diff/diff_tree.c (added)
+++ subversion/trunk/subversion/libsvn_diff/diff_tree.c Thu Jan 24 23:25:34 2013
@@ -0,0 +1,555 @@
+/*
+ * diff_tree.c :  default diff tree processor
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include <apr.h>
+#include <apr_pools.h>
+#include <apr_general.h>
+
+#include "svn_dirent_uri.h"
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "svn_props.h"
+#include "svn_types.h"
+
+#include "private/svn_diff_tree.h"
+#include "svn_private_config.h"
+
+typedef struct tree_processor_t
+{
+  svn_diff_tree_processor_t tp;
+
+  /* void *future_extension */
+} tree_processor_t;
+
+
+static svn_error_t *
+default_dir_opened(void **new_dir_baton,
+                   svn_boolean_t *skip,
+                   svn_boolean_t *skip_children,
+                   const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   const svn_diff_source_t *right_source,
+                   const svn_diff_source_t *copyfrom_source,
+                   void *parent_dir_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  *new_dir_baton = NULL;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_dir_added(const char *relpath,
+                  const svn_diff_source_t *copyfrom_source,
+                  const svn_diff_source_t *right_source,
+                  /*const*/ apr_hash_t *copyfrom_props,
+                  /*const*/ apr_hash_t *right_props,
+                  void *dir_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR(processor->dir_closed(relpath, NULL, right_source,
+                                dir_baton, processor,
+                                scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_dir_deleted(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    /*const*/ apr_hash_t *left_props,
+                    void *dir_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  SVN_ERR(processor->dir_closed(relpath, left_source, NULL,
+                                dir_baton, processor,
+                                scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_dir_changed(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const svn_diff_source_t *right_source,
+                    /*const*/ apr_hash_t *left_props,
+                    /*const*/ apr_hash_t *right_props,
+                    const apr_array_header_t *prop_changes,
+                    void *dir_baton,
+                    const struct svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  SVN_ERR(processor->dir_closed(relpath,
+                                left_source, right_source,
+                                dir_baton,
+                                processor, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_dir_closed(const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   const svn_diff_source_t *right_source,
+                   void *dir_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_file_opened(void **new_file_baton,
+                    svn_boolean_t *skip,
+                    const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const svn_diff_source_t *right_source,
+                    const svn_diff_source_t *copyfrom_source,
+                    void *dir_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  *new_file_baton = dir_baton;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_file_added(const char *relpath,
+                   const svn_diff_source_t *copyfrom_source,
+                   const svn_diff_source_t *right_source,
+                   const char *copyfrom_file,
+                   const char *right_file,
+                   /*const*/ apr_hash_t *copyfrom_props,
+                   /*const*/ apr_hash_t *right_props,
+                   void *file_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  SVN_ERR(processor->file_closed(relpath,
+                                 NULL, right_source,
+                                 file_baton, processor, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_file_deleted(const char *relpath,
+                     const svn_diff_source_t *left_source,
+                     const char *left_file,
+                     /*const*/ apr_hash_t *left_props,
+                     void *file_baton,
+                     const svn_diff_tree_processor_t *processor,
+                     apr_pool_t *scratch_pool)
+{
+  SVN_ERR(processor->file_closed(relpath,
+                                 left_source, NULL,
+                                 file_baton, processor, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_file_changed(const char *relpath,
+                     const svn_diff_source_t *left_source,
+                     const svn_diff_source_t *right_source,
+                     const char *left_file,
+                     const char *right_file,
+                     /*const*/ apr_hash_t *left_props,
+                     /*const*/ apr_hash_t *right_props,
+                     svn_boolean_t file_modified,
+                     const apr_array_header_t *prop_changes,
+                     void *file_baton,
+                     const svn_diff_tree_processor_t *processor,
+                     apr_pool_t *scratch_pool)
+{
+  SVN_ERR(processor->file_closed(relpath,
+                                 left_source, right_source,
+                                 file_baton, processor, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+default_file_closed(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const svn_diff_source_t *right_source,
+                    void *file_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
+
+svn_diff_tree_processor_t *
+svn_diff__tree_processor_create(void *baton,
+                                apr_pool_t *result_pool)
+{
+  tree_processor_t *wrapper;
+  wrapper = apr_pcalloc(result_pool, sizeof(*wrapper));
+
+  wrapper->tp.baton        = baton;
+
+  wrapper->tp.dir_opened   = default_dir_opened;
+  wrapper->tp.dir_added    = default_dir_added;
+  wrapper->tp.dir_deleted  = default_dir_deleted;
+  wrapper->tp.dir_changed  = default_dir_changed;
+  wrapper->tp.dir_closed   = default_dir_closed;
+
+  wrapper->tp.file_opened   = default_file_opened;
+  wrapper->tp.file_added    = default_file_added;
+  wrapper->tp.file_deleted  = default_file_deleted;
+  wrapper->tp.file_changed  = default_file_changed;
+  wrapper->tp.file_closed   = default_file_closed;
+
+  return &wrapper->tp;
+}
+
+//////////////
+
+struct reverse_tree_baton_t
+{
+  svn_diff_tree_processor_t *processor;
+  const char *prefix_relpath;
+};
+
+static svn_error_t *
+reverse_dir_opened(void **new_dir_baton,
+                   svn_boolean_t *skip,
+                   svn_boolean_t *skip_children,
+                   const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   const svn_diff_source_t *right_source,
+                   const svn_diff_source_t *copyfrom_source,
+                   void *parent_dir_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->dir_opened(new_dir_baton, skip, skip_children,
+                                    relpath,
+                                    right_source, left_source,
+                                    NULL /* copyfrom */,
+                                    parent_dir_baton,
+                                    rb->processor,
+                                    result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_dir_added(const char *relpath,
+                  const svn_diff_source_t *copyfrom_source,
+                  const svn_diff_source_t *right_source,
+                  /*const*/ apr_hash_t *copyfrom_props,
+                  /*const*/ apr_hash_t *right_props,
+                  void *dir_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->dir_deleted(relpath,
+                                     right_source,
+                                     right_props,
+                                     dir_baton,
+                                     rb->processor,
+                                     scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_dir_deleted(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    /*const*/ apr_hash_t *left_props,
+                    void *dir_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->dir_added(relpath,
+                                   NULL,
+                                   left_source,
+                                   NULL,
+                                   left_props,
+                                   dir_baton,
+                                   rb->processor,
+                                   scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_dir_changed(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const svn_diff_source_t *right_source,
+                    /*const*/ apr_hash_t *left_props,
+                    /*const*/ apr_hash_t *right_props,
+                    const apr_array_header_t *prop_changes,
+                    void *dir_baton,
+                    const struct svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+  apr_array_header_t *reversed_prop_changes = NULL;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  if (prop_changes)
+    {
+      SVN_ERR_ASSERT(left_props != NULL && right_props != NULL);
+      SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props,
+                             scratch_pool));
+    }
+
+  SVN_ERR(rb->processor->dir_changed(relpath,
+                                     right_source,
+                                     left_source,
+                                     right_props,
+                                     left_props,
+                                     reversed_prop_changes,
+                                     dir_baton,
+                                     rb->processor,
+                                     scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_dir_closed(const char *relpath,
+                   const svn_diff_source_t *left_source,
+                   const svn_diff_source_t *right_source,
+                   void *dir_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->dir_closed(relpath,
+                                    right_source,
+                                    left_source,
+                                    dir_baton,
+                                    rb->processor,
+                                    scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_file_opened(void **new_file_baton,
+                    svn_boolean_t *skip,
+                    const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const svn_diff_source_t *right_source,
+                    const svn_diff_source_t *copyfrom_source,
+                    void *dir_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->file_opened(new_file_baton,
+                                     skip,
+                                     relpath,
+                                     right_source,
+                                     left_source,
+                                     NULL /* copy_from */,
+                                     dir_baton,
+                                     rb->processor,
+                                     result_pool,
+                                     scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_file_added(const char *relpath,
+                   const svn_diff_source_t *copyfrom_source,
+                   const svn_diff_source_t *right_source,
+                   const char *copyfrom_file,
+                   const char *right_file,
+                   /*const*/ apr_hash_t *copyfrom_props,
+                   /*const*/ apr_hash_t *right_props,
+                   void *file_baton,
+                   const svn_diff_tree_processor_t *processor,
+                   apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->file_deleted(relpath,
+                                      right_source,
+                                      right_file,
+                                      right_props,
+                                      file_baton,
+                                      rb->processor,
+                                      scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_file_deleted(const char *relpath,
+                     const svn_diff_source_t *left_source,
+                     const char *left_file,
+                     /*const*/ apr_hash_t *left_props,
+                     void *file_baton,
+                     const svn_diff_tree_processor_t *processor,
+                     apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->file_added(relpath,
+                                    NULL /* copyfrom src */,
+                                    left_source,
+                                    NULL /* copyfrom file */,
+                                    left_file,
+                                    NULL /* copyfrom props */,
+                                    left_props,
+                                    file_baton,
+                                    rb->processor,
+                                    scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_file_changed(const char *relpath,
+                     const svn_diff_source_t *left_source,
+                     const svn_diff_source_t *right_source,
+                     const char *left_file,
+                     const char *right_file,
+                     /*const*/ apr_hash_t *left_props,
+                     /*const*/ apr_hash_t *right_props,
+                     svn_boolean_t file_modified,
+                     const apr_array_header_t *prop_changes,
+                     void *file_baton,
+                     const svn_diff_tree_processor_t *processor,
+                     apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+  apr_array_header_t *reversed_prop_changes = NULL;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  if (prop_changes)
+    {
+      SVN_ERR_ASSERT(left_props != NULL && right_props != NULL);
+      SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props,
+                             scratch_pool));
+    }
+
+  SVN_ERR(rb->processor->file_changed(relpath,
+                                      right_source,
+                                      left_source,
+                                      right_file,
+                                      left_file,
+                                      right_props,
+                                      left_props,
+                                      file_modified,
+                                      reversed_prop_changes,
+                                      file_baton,
+                                      rb->processor,
+                                      scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reverse_file_closed(const char *relpath,
+                    const svn_diff_source_t *left_source,
+                    const svn_diff_source_t *right_source,
+                    void *file_baton,
+                    const svn_diff_tree_processor_t *processor,
+                    apr_pool_t *scratch_pool)
+{
+  struct reverse_tree_baton_t *rb = processor->baton;
+
+  if (rb->prefix_relpath)
+    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
+
+  SVN_ERR(rb->processor->file_closed(relpath,
+                                     right_source,
+                                     left_source,
+                                     file_baton,
+                                     rb->processor,
+                                     scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+const svn_diff_tree_processor_t *
+svn_diff__tree_processor_reverse_create(svn_diff_tree_processor_t * processor,
+                                        const char *prefix_relpath,
+                                        apr_pool_t *result_pool)
+{
+  struct reverse_tree_baton_t *rb;
+  svn_diff_tree_processor_t *reverse;
+
+  rb = apr_pcalloc(result_pool, sizeof(*rb));
+  rb->processor = processor;
+  if (prefix_relpath)
+    rb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath);
+
+  reverse = svn_diff__tree_processor_create(rb, result_pool);
+
+  reverse->dir_opened   = reverse_dir_opened;
+  reverse->dir_added    = reverse_dir_added;
+  reverse->dir_deleted  = reverse_dir_deleted;
+  reverse->dir_changed  = reverse_dir_changed;
+  reverse->dir_closed   = reverse_dir_closed;
+  reverse->file_opened   = reverse_file_opened;
+  reverse->file_added    = reverse_file_added;
+  reverse->file_deleted  = reverse_file_deleted;
+  reverse->file_changed  = reverse_file_changed;
+  reverse->file_closed   = reverse_file_closed;
+
+  return reverse;
+}
+
+svn_diff_source_t *
+svn_diff__source_create(svn_revnum_t revision,
+                        apr_pool_t *result_pool)
+{
+  svn_diff_source_t *src = apr_pcalloc(result_pool, sizeof(*src));
+
+  src->revision = revision;
+  return src;
+}

Propchange: subversion/trunk/subversion/libsvn_diff/diff_tree.c
------------------------------------------------------------------------------
    svn:eol-style = native