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:31:45 UTC

svn commit: r1438264 - in /subversion/trunk/subversion: include/private/svn_diff_tree.h include/private/svn_wc_private.h libsvn_wc/diff_editor.c

Author: rhuijben
Date: Thu Jan 24 23:31:44 2013
New Revision: 1438264

URL: http://svn.apache.org/viewvc?rev=1438264&view=rev
Log:
Following up on r1438261, implement a diff tree processor that wraps the old
diff callback layer. This private api also includes an additional callback
for handling the state output arguments that are used only by libsvn_client's
internal code.

* subversion/include/private/svn_diff_tree.h
  (svn_diff_source_t): Uncomment optional components.

* subversion/include/private/svn_wc_private.h
  (includes): Add svn_diff_tree.h.
  (svn_wc__diff_state_handle_t,
   svn_wc__diff_state_close_t): New typedef.
  (svn_wc__wrap_diff_callbacks): New function.

* subversion/libsvn_wc/diff_editor.c
  (includes): Add svn_diff_tree.h.
  (wc_diff_wrap_baton_t): New struct.
  (wrap_*): New functions.
  (svn_wc__wrap_diff_callbacks): New function.

Modified:
    subversion/trunk/subversion/include/private/svn_diff_tree.h
    subversion/trunk/subversion/include/private/svn_wc_private.h
    subversion/trunk/subversion/libsvn_wc/diff_editor.c

Modified: 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=1438264&r1=1438263&r2=1438264&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_diff_tree.h (original)
+++ subversion/trunk/subversion/include/private/svn_diff_tree.h Thu Jan 24 23:31:44 2013
@@ -40,8 +40,8 @@ typedef struct svn_diff_source_t
   svn_revnum_t revision;
 
   /* Depending on the driver */
-  /*const char *repos_relpath;
-  const char *local_abspath;*/
+  const char *repos_relpath;
+  const char *local_abspath;
 } svn_diff_source_t;
 
 /**

Modified: subversion/trunk/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_wc_private.h?rev=1438264&r1=1438263&r2=1438264&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_wc_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_wc_private.h Thu Jan 24 23:31:44 2013
@@ -39,6 +39,7 @@
 
 #include "svn_types.h"
 #include "svn_wc.h"
+#include "private/svn_diff_tree.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -1672,6 +1673,50 @@ svn_wc__get_diff_editor(const svn_delta_
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);
 
+/** Callback for the svn_diff_tree_processor_t wrapper, to allow handling
+ *  notifications like how the repos diff in libsvn_client does.
+ *
+ * Probably only necessary while transitioning to svn_diff_tree_processor_t
+ */
+typedef svn_error_t *
+        (*svn_wc__diff_state_handle_t)(svn_boolean_t tree_conflicted,
+                                       svn_wc_notify_state_t *state,
+                                       svn_wc_notify_state_t *prop_state,
+                                       const char *relpath,
+                                       svn_kind_t kind,
+                                       svn_boolean_t before_op,
+                                       svn_boolean_t for_add,
+                                       svn_boolean_t for_delete,
+                                       void *state_baton,
+                                       apr_pool_t *scratch_pool);
+
+/** Callback for the svn_diff_tree_processor_t wrapper, to allow handling
+ *  notifications like how the repos diff in libsvn_client does.
+ *
+ * Probably only necessary while transitioning to svn_diff_tree_processor_t
+ */
+typedef svn_error_t *
+        (*svn_wc__diff_state_close_t)(const char *relpath,
+                                      svn_kind_t kind,
+                                      void *state_baton,
+                                      apr_pool_t *scratch_pool);
+
+
+/** Obtains a diff processor that will drive the diff callbacks when it
+ * is invoked. The state arguments will be handled by the state processor
+ * or ignored if STATE_HANDLER is NULL
+ */
+svn_error_t *
+svn_wc__wrap_diff_callbacks(svn_diff_tree_processor_t **diff_processor,
+                            const svn_wc_diff_callbacks4_t *callbacks,
+                            void *callback_baton,
+                            svn_wc__diff_state_handle_t state_handle,
+                            svn_wc__diff_state_close_t state_close,
+                            void *state_baton,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
+
+
 /**
  * Assuming @a local_abspath itself or any of its children are under version
  * control or a tree conflict victim and in a state of conflict, take these

Modified: subversion/trunk/subversion/libsvn_wc/diff_editor.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/diff_editor.c?rev=1438264&r1=1438263&r2=1438264&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/diff_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/diff_editor.c Thu Jan 24 23:31:44 2013
@@ -63,6 +63,7 @@
 
 #include "private/svn_subr_private.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_diff_tree.h"
 #include "private/svn_editor.h"
 
 #include "wc.h"
@@ -1958,3 +1959,477 @@ svn_wc__get_diff_editor(const svn_delta_
 
   return SVN_NO_ERROR;
 }
+
+/* Wrapping svn_wc_diff_callbacks4_t as svn_diff_tree_processor_t */
+
+/* baton for the svn_diff_tree_processor_t wrapper */
+typedef struct wc_diff_wrap_baton_t
+{
+  const svn_wc_diff_callbacks4_t *callbacks;
+  void *callback_baton;
+  svn_wc__diff_state_handle_t state_handle;
+  svn_wc__diff_state_close_t state_close;
+  void *state_baton;
+
+  apr_pool_t *result_pool;
+  const char *empty_file;
+
+} wc_diff_wrap_baton_t;
+
+static svn_error_t *
+wrap_ensure_empty_file(wc_diff_wrap_baton_t *wb,
+                       apr_pool_t *scratch_pool)
+{
+  if (wb->empty_file)
+    return SVN_NO_ERROR;
+
+  /* Create a unique file in the tempdir */
+  SVN_ERR(svn_io_open_uniquely_named(NULL, &wb->empty_file, NULL, NULL, NULL,
+                                     svn_io_file_del_on_pool_cleanup,
+                                     wb->result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+
+  /* Maybe store state and tree_conflicted in baton? */
+  if (left_source != NULL)
+    {
+      /* Open for change or delete */
+      SVN_ERR(wb->callbacks->dir_opened(&tree_conflicted, skip, skip_children,
+                                        relpath,
+                                        right_source
+                                            ? right_source->revision
+                                            : (left_source
+                                                    ? left_source->revision
+                                                    : SVN_INVALID_REVNUM),
+                                        wb->callback_baton,
+                                        scratch_pool));
+
+      if (wb->state_handle)
+        SVN_ERR(wb->state_handle(tree_conflicted, NULL, NULL,
+                                 relpath, svn_kind_dir,
+                                 TRUE /* before operation */,
+                                 FALSE /* for_add */,
+                                 (right_source == NULL) /* for_delete */,
+                                 wb->state_baton,
+                                 scratch_pool));
+    }
+  else /* left_source == NULL -> Add */
+    {
+      svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+      SVN_ERR(wb->callbacks->dir_added(&state, &tree_conflicted,
+                                       skip, skip_children,
+                                       relpath,
+                                       right_source->revision,
+                                       copyfrom_source
+                                            ? copyfrom_source->repos_relpath
+                                            : NULL,
+                                       copyfrom_source
+                                            ? copyfrom_source->revision
+                                            : SVN_INVALID_REVNUM,
+                                       wb->callback_baton,
+                                       scratch_pool));
+
+      if (wb->state_handle)
+        SVN_ERR(wb->state_handle(tree_conflicted, &state, NULL,
+                                 relpath, svn_kind_dir,
+                                 TRUE, TRUE, FALSE,
+                                 wb->state_baton,
+                                 scratch_pool));
+    }
+
+  *new_dir_baton = NULL;
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_dir_added(const char *relpath,
+               const svn_diff_source_t *right_source,
+               const svn_diff_source_t *copyfrom_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_unknown;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown;
+  apr_hash_t *pristine_props = copyfrom_props;
+  apr_array_header_t *prop_changes = NULL;
+
+  if (right_props && apr_hash_count(right_props))
+    {
+      if (!pristine_props)
+        pristine_props = apr_hash_make(scratch_pool);
+
+      SVN_ERR(svn_prop_diffs(&prop_changes, right_props, pristine_props,
+                             scratch_pool));
+
+      SVN_ERR(wb->callbacks->dir_props_changed(&prop_state,
+                                               &tree_conflicted,
+                                               relpath,
+                                               TRUE /* dir_was_added */,
+                                               prop_changes, pristine_props,
+                                               wb->callback_baton,
+                                               scratch_pool));
+    }
+
+  SVN_ERR(wb->callbacks->dir_closed(&state, &prop_state,
+                                   &tree_conflicted,
+                                   relpath,
+                                   TRUE /* dir_was_added */,
+                                   wb->callback_baton,
+                                   scratch_pool));
+
+  if (wb->state_handle)
+    SVN_ERR(wb->state_handle(tree_conflicted, &state, &prop_state,
+                             relpath, svn_kind_dir,
+                             FALSE /* before operation */,
+                             TRUE /* for_add */, FALSE /* for_delete */,
+                             wb->state_baton,
+                             scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+
+  if (wb->state_close)
+    SVN_ERR(wb->state_close(relpath, svn_kind_dir,
+                            wb->state_baton,
+                            scratch_pool));
+
+  SVN_ERR(wb->callbacks->dir_deleted(&state, &tree_conflicted,
+                                     relpath,
+                                     wb->callback_baton,
+                                     scratch_pool));
+
+  if (wb->state_handle)
+    SVN_ERR(wb->state_handle(tree_conflicted, &state, NULL,
+                             relpath, svn_kind_dir,
+                             FALSE /* before operation */,
+                             FALSE /* for_add */, TRUE /* for_delete */,
+                             wb->state_baton,
+                             scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+
+  if (wb->state_close)
+    SVN_ERR(wb->state_close(relpath, svn_kind_dir,
+                            wb->state_baton, scratch_pool));
+
+  /* No previous implementations provided these arguments, so we
+     are not doing with them either */
+  SVN_ERR(wb->callbacks->dir_closed(NULL, NULL, NULL,
+                                    relpath,
+                                    (left_source == NULL) /* added */,
+                                    wb->callback_baton,
+                                    scratch_pool));
+
+return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_inapplicable;
+
+  SVN_ERR(wb->callbacks->dir_props_changed(&prop_state, &tree_conflicted,
+                                           relpath,
+                                           (left_source == NULL) /* added */,
+                                           prop_changes,
+                                           left_props,
+                                           wb->callback_baton,
+                                           scratch_pool));
+
+  if (wb->state_handle)
+    SVN_ERR(wb->state_handle(tree_conflicted, NULL, &prop_state,
+                             relpath, svn_kind_dir,
+                             FALSE /* before operation */,
+                             FALSE /* for_add */, FALSE /* for_delete */,
+                             wb->state_baton,
+                             scratch_pool));
+
+
+  /* And call dir_closed, etc */
+  SVN_ERR(wrap_dir_closed(relpath, left_source, right_source,
+                          dir_baton, processor,
+                          scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+
+  if (left_source) /* If ! added */
+    SVN_ERR(wb->callbacks->file_opened(&tree_conflicted, skip, relpath,
+                                       right_source
+                                            ? right_source->revision
+                                            : (left_source
+                                                    ? left_source->revision
+                                                    : SVN_INVALID_REVNUM),
+                                       wb->callback_baton, scratch_pool));
+
+  /* No old implementation used the output arguments for notify */
+
+  *new_file_baton = NULL;
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_inapplicable;
+  apr_array_header_t *prop_changes;
+
+  if (! copyfrom_props)
+    copyfrom_props = apr_hash_make(scratch_pool);
+
+  SVN_ERR(svn_prop_diffs(&prop_changes, right_props, copyfrom_props,
+                         scratch_pool));
+
+  if (! copyfrom_source)
+    SVN_ERR(wrap_ensure_empty_file(wb, scratch_pool));
+
+  SVN_ERR(wb->callbacks->file_added(&state, &prop_state, &tree_conflicted,
+                                    relpath,
+                                    copyfrom_source
+                                        ? copyfrom_file
+                                        : wb->empty_file,
+                                    right_file,
+                                    copyfrom_source
+                                       ? copyfrom_source->revision
+                                       : 0 /* For legacy reasons */,
+                                    right_source->revision,
+                                    copyfrom_props
+                                     ? svn_prop_get_value(copyfrom_props,
+                                                          SVN_PROP_MIME_TYPE)
+                                     : NULL,
+                                    right_props
+                                     ? svn_prop_get_value(right_props,
+                                                          SVN_PROP_MIME_TYPE)
+                                     : NULL,
+                                    NULL, SVN_INVALID_REVNUM,
+                                    prop_changes, copyfrom_props,
+                                    wb->callback_baton,
+                                    scratch_pool));
+
+  if (wb->state_handle)
+    SVN_ERR(wb->state_handle(tree_conflicted, &state, &prop_state,
+                             relpath, svn_kind_file,
+                             FALSE /* before operation */,
+                             TRUE, FALSE,
+                             wb->state_baton,
+                             scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+wrap_file_deleted(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const char *left_file,
+                  apr_hash_t *left_props,
+                  void *file_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+
+  SVN_ERR(wrap_ensure_empty_file(wb, scratch_pool));
+
+  SVN_ERR(wb->callbacks->file_deleted(&state, &tree_conflicted,
+                                      relpath,
+                                      left_file, wb->empty_file,
+                                      left_props
+                                       ? svn_prop_get_value(left_props,
+                                                            SVN_PROP_MIME_TYPE)
+                                       : NULL,
+                                      NULL,
+                                      left_props,
+                                      wb->callback_baton,
+                                      scratch_pool));
+
+  if (wb->state_handle)
+    SVN_ERR(wb->state_handle(tree_conflicted, &state, NULL,
+                             relpath, svn_kind_file,
+                             FALSE /* before operation */,
+                             FALSE, TRUE,
+                             wb->state_baton,
+                             scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_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)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_inapplicable;
+
+  SVN_ERR(wrap_ensure_empty_file(wb, scratch_pool));
+
+  SVN_ERR(wb->callbacks->file_changed(&state, &prop_state, &tree_conflicted,
+                                      relpath,
+                                      left_file, right_file,
+                                      left_source->revision,
+                                      right_source->revision,
+                                      left_props
+                                       ? svn_prop_get_value(left_props,
+                                                            SVN_PROP_MIME_TYPE)
+                                       : NULL,
+                                      right_props
+                                       ? svn_prop_get_value(right_props,
+                                                            SVN_PROP_MIME_TYPE)
+                                       : NULL,
+                                       prop_changes,
+                                      left_props,
+                                      wb->callback_baton,
+                                      scratch_pool));
+
+  if (wb->state_handle)
+    SVN_ERR(wb->state_handle(tree_conflicted, &state, &prop_state,
+                             relpath, svn_kind_file,
+                             FALSE /* before operation */,
+                             FALSE, FALSE,
+                             wb->state_baton,
+                             scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__wrap_diff_callbacks(svn_diff_tree_processor_t **diff_processor,
+                            const svn_wc_diff_callbacks4_t *callbacks,
+                            void *callback_baton,
+                            svn_wc__diff_state_handle_t state_handler,
+                            svn_wc__diff_state_close_t state_close,
+                            void *state_baton,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wrap_baton;
+  svn_diff_tree_processor_t *processor;
+
+  wrap_baton = apr_pcalloc(result_pool, sizeof(*wrap_baton));
+
+  wrap_baton->result_pool = result_pool;
+  wrap_baton->callbacks = callbacks;
+  wrap_baton->callback_baton = callback_baton;
+  wrap_baton->state_handle = state_handler;
+  wrap_baton->state_close = state_close;
+  wrap_baton->state_baton = state_baton;
+  wrap_baton->empty_file = NULL;
+
+  processor = svn_diff__tree_processor_create(wrap_baton, result_pool);
+
+  processor->dir_opened   = wrap_dir_opened;
+  processor->dir_added    = wrap_dir_added;
+  processor->dir_deleted  = wrap_dir_deleted;
+  processor->dir_changed  = wrap_dir_changed;
+  processor->dir_closed   = wrap_dir_closed;
+
+  processor->file_opened   = wrap_file_opened;
+  processor->file_added    = wrap_file_added;
+  processor->file_deleted  = wrap_file_deleted;
+  processor->file_changed  = wrap_file_changed;
+  /*processor->file_closed   = wrap_file_closed*/; /* Not needed */
+
+  *diff_processor = processor;
+  return SVN_NO_ERROR;
+}