You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2011/09/07 21:36:01 UTC

svn commit: r1166332 - in /subversion/trunk/subversion: libsvn_delta/compat.c tests/libsvn_delta/editor-test.c

Author: hwright
Date: Wed Sep  7 19:36:01 2011
New Revision: 1166332

URL: http://svn.apache.org/viewvc?rev=1166332&view=rev
Log:
A checkpoint commit of work on the Ev2 compat code.  This extends the tests and
compat code a bit.

* subversion/tests/libsvn_delta/editor-test.c
  (SET_STR): New.
  (editor_from_delta_editor_test): Extend this test with some prop editing.
 
* subversion/libsvn_delta/compat.c
  (edit_baton, file_baton): Add a few members.
  (action, path_action, prop_args): New.
  (add_action): New.
  (ev2_add_directory, ev2_add_file, ev2_open_file, ev2_change_file_prop):
    Queue up a few actions for processing.
  (ev2_close_edit): Implement post-pass processing.
  (svn_delta_from_editor): Populate a few baton members.

Modified:
    subversion/trunk/subversion/libsvn_delta/compat.c
    subversion/trunk/subversion/tests/libsvn_delta/editor-test.c

Modified: subversion/trunk/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/compat.c?rev=1166332&r1=1166331&r2=1166332&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/compat.c (original)
+++ subversion/trunk/subversion/libsvn_delta/compat.c Wed Sep  7 19:36:01 2011
@@ -21,11 +21,11 @@
  * ====================================================================
  */
 
-#include <apr_pools.h>
-
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_delta.h"
+#include "svn_sorts.h"
+#include "svn_pools.h"
 
 
 struct file_rev_handler_wrapper_baton {
@@ -92,6 +92,8 @@ svn_compat_wrap_file_rev_handler(svn_fil
 struct ev2_edit_baton
 {
   svn_editor_t *editor;
+  apr_hash_t *paths;
+  apr_pool_t *edit_pool;
 };
 
 struct ev2_dir_baton
@@ -102,9 +104,56 @@ struct ev2_dir_baton
 struct ev2_file_baton
 {
   struct ev2_edit_baton *eb;
+  const char *path;
+};
+
+enum action
+{
+  add,
+  delete,
+  set_prop
+};
+
+struct path_action
+{
+  enum action action;
+  void *args;
+};
+
+struct prop_args
+{
+  const char *name;
+  const svn_string_t *value;
 };
 
 static svn_error_t *
+add_action(struct ev2_edit_baton *eb,
+           const char *path,
+           enum action action,
+           void *args)
+{
+  struct path_action *p_action;
+  apr_array_header_t *action_list = apr_hash_get(eb->paths, path,
+                                                 APR_HASH_KEY_STRING);
+
+  p_action = apr_palloc(eb->edit_pool, sizeof(*p_action));
+  p_action->action = action;
+  p_action->args = args;
+
+  if (action_list == NULL)
+    {
+      action_list = apr_array_make(eb->edit_pool, 1,
+                                   sizeof(struct path_action *));
+      apr_hash_set(eb->paths, apr_pstrdup(eb->edit_pool, path),
+                   APR_HASH_KEY_STRING, action_list);
+    }
+
+  APR_ARRAY_PUSH(action_list, struct path_action *) = p_action;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 ev2_set_target_revision(void *edit_baton,
                         svn_revnum_t target_revision,
                         apr_pool_t *scratch_pool)
@@ -148,6 +197,11 @@ ev2_add_directory(const char *path,
                   void **child_baton)
 {
   struct ev2_dir_baton *pb = parent_baton;
+  svn_node_kind_t *kind;
+
+  kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+  *kind = svn_node_dir;
+  SVN_ERR(add_action(pb->eb, path, add, kind));
 
   return SVN_NO_ERROR;
 }
@@ -183,6 +237,7 @@ ev2_close_directory(void *dir_baton,
                     apr_pool_t *scratch_pool)
 {
   struct ev2_dir_baton *db = dir_baton;
+
   return SVN_NO_ERROR;
 }
 
@@ -205,10 +260,16 @@ ev2_add_file(const char *path,
 {
   struct ev2_file_baton *fb = apr_palloc(result_pool, sizeof(*fb));
   struct ev2_dir_baton *pb = parent_baton;
+  svn_node_kind_t *kind;
 
   fb->eb = pb->eb;
-
+  fb->path = apr_pstrdup(result_pool, path);
   *file_baton = fb;
+
+  kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+  *kind = svn_node_file;
+  SVN_ERR(add_action(pb->eb, path, add, kind));
+
   return SVN_NO_ERROR;
 }
 
@@ -223,6 +284,7 @@ ev2_open_file(const char *path,
   struct ev2_dir_baton *pb = parent_baton;
 
   fb->eb = pb->eb;
+  fb->path = apr_pstrdup(result_pool, path);
 
   *file_baton = fb;
   return SVN_NO_ERROR;
@@ -250,6 +312,13 @@ ev2_change_file_prop(void *file_baton,
                      apr_pool_t *scratch_pool)
 {
   struct ev2_file_baton *fb = file_baton;
+  struct prop_args *p_args = apr_palloc(fb->eb->edit_pool, sizeof(*p_args));
+
+  p_args->name = apr_pstrdup(fb->eb->edit_pool, name);
+  p_args->value = svn_string_dup(value, fb->eb->edit_pool);
+
+  SVN_ERR(add_action(fb->eb, fb->path, set_prop, p_args));
+
   return SVN_NO_ERROR;
 }
 
@@ -276,6 +345,60 @@ ev2_close_edit(void *edit_baton,
                apr_pool_t *scratch_pool)
 {
   struct ev2_edit_baton *eb = edit_baton;
+  apr_array_header_t *sorted_hash;
+  apr_pool_t *iterpool;
+  int i;
+
+  /* Sort the paths touched by this edit.
+   * Ev2 doesn't really have any particular need for depth-first-ness, but
+   * we want to ensure all parent directories are handled before children in
+   * the case of adds (which does introduce an element of depth-first-ness). */
+  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
+                               scratch_pool);
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < sorted_hash->nelts; i++)
+    {
+      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
+      apr_array_header_t *actions = item->value;
+      const char *path = item->key;
+      apr_hash_t *props;
+      int j;
+
+      svn_pool_clear(iterpool);
+
+      props = apr_hash_make(iterpool);
+
+      /* Go through all of our actions, populating various datastructures
+       * dependent on them. */
+      for (j = 0; j < actions->nelts; j++)
+        {
+          struct path_action *action = APR_ARRAY_IDX(actions, j,
+                                                     struct path_action *);
+
+          switch (action->action)
+            {
+              case set_prop:
+                {
+                  struct prop_args *p_args = action->args;
+
+                  apr_hash_set(props, p_args->name, APR_HASH_KEY_STRING,
+                               p_args->value);
+                  break;
+                }
+
+              default:
+                break;
+            }
+        }
+
+      /* We've now got a wholistic view of what has happened to this node,
+       * so we can call our own editor APIs on it. */
+      if (apr_hash_count(props) > 0)
+        SVN_ERR(svn_editor_set_props(eb->editor, path, SVN_INVALID_REVNUM,
+                                     props, TRUE));
+    }
+  svn_pool_destroy(iterpool);
 
   return svn_error_trace(svn_editor_complete(eb->editor));
 }
@@ -317,6 +440,8 @@ svn_delta_from_editor(svn_delta_editor_t
   struct ev2_edit_baton *eb = apr_palloc(pool, sizeof(*eb));
 
   eb->editor = editor;
+  eb->paths = apr_hash_make(pool);
+  eb->edit_pool = pool;
 
   *dedit_baton = eb;
   *deditor = &delta_editor;

Modified: subversion/trunk/subversion/tests/libsvn_delta/editor-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_delta/editor-test.c?rev=1166332&r1=1166331&r2=1166332&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_delta/editor-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_delta/editor-test.c Wed Sep  7 19:36:01 2011
@@ -27,10 +27,13 @@
 
 #include "svn_types.h"
 #include "svn_error.h"
+#include "svn_pools.h"
 #include "svn_editor.h"
 
 #include "../svn_test_fs.h"
 
+#define SET_STR(ps, s) ((ps)->data = (s), (ps)->len = strlen(s))
+
 /* We use svn_repos APIs in some of these tests simply for convenience. */
 
 /* This implements svn_editor_cb_add_directory_t */
@@ -201,38 +204,78 @@ editor_from_delta_editor_test(const svn_
   svn_repos_t *repos;
   svn_fs_t *fs;
   svn_fs_txn_t *txn;
-  svn_fs_root_t *revision_root, *txn_root, *base_root;
+  svn_fs_root_t *txn_root;
   svn_revnum_t youngest_rev;
-  void *dedit_baton;
-  svn_delta_editor_t *deditor;
-  svn_editor_t *editor;
+  apr_pool_t *iterpool;
+  svn_string_t s1;
+  int i;
 
   /* Create a filesystem and repository. */
   SVN_ERR(svn_test__create_repos(&repos, "ev2-from-delta-editor-test",
                                  opts, pool));
   fs = svn_repos_fs(repos);
 
-  /* Prepare a txn to receive the greek tree. */
-  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
-  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
-  /* Create and commit the greek tree. */
-  SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
-  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
-  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
-
-  SVN_ERR(svn_fs_revision_root(&revision_root, fs, youngest_rev, pool));
-  SVN_ERR(svn_fs_revision_root(&base_root, fs, 0, pool));
-
-  /* Construct our editor, and from it a delta editor. */
-  SVN_ERR(get_noop_editor(&editor, NULL, NULL, NULL, pool, pool));
-  SVN_ERR(svn_delta_from_editor(&deditor, &dedit_baton, editor, pool));
-
-  SVN_ERR(svn_repos_replay2(revision_root, "", SVN_INVALID_REVNUM, TRUE,
-                            deditor, dedit_baton, NULL, NULL, pool));
+  {
+    /* Prepare a txn to receive the greek tree. */
+    SVN_ERR(svn_fs_begin_txn2(&txn, fs, 0, 0, pool));
+    SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+
+    /* Create and commit the greek tree. */
+    SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
+    SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+    SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
+  }
 
-  /* Close the edit. */
-  SVN_ERR(deditor->close_edit(dedit_baton, pool));
+  {
+    /* Now chuck in some prop changes. */
+    const char *props[4][2] = {
+        { "If you change to meet a frown,", "Do not let it stay." },
+        { "Quickly turn it upside down,", "And smile that frown away." },
+        { "No one likes a frowny face,", "Change it for a smile," },
+        { "Make the world a better place,", "By smiling all the while!" }
+      };
+
+    SVN_ERR(svn_fs_begin_txn2(&txn, fs, 1, 0, pool));
+    SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+
+    for (i = 0; i < 4; i++)
+      {
+        SET_STR(&s1, props[i][1]);
+        SVN_ERR(svn_fs_change_node_prop(txn_root, "iota",
+                                        props[i][0], &s1, pool));
+      }
+
+    SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+    SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
+  }
+
+  /* Now, let's look at each revision. */
+  iterpool = svn_pool_create(pool);
+  for (i = 0; i < youngest_rev; i++)
+    {
+      svn_fs_root_t *revision_root;
+      void *dedit_baton;
+      svn_delta_editor_t *deditor;
+      svn_editor_t *editor;
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(svn_fs_revision_root(&revision_root, fs, i, iterpool));
+
+      /* Construct our editor, and from it a delta editor. */
+      SVN_ERR(get_noop_editor(&editor, NULL, NULL, NULL, iterpool, iterpool));
+      SVN_ERR(svn_delta_from_editor(&deditor, &dedit_baton, editor, iterpool));
+
+      SVN_ERR(svn_repos_replay2(revision_root, "", SVN_INVALID_REVNUM, TRUE,
+                                deditor, dedit_baton, NULL, NULL, iterpool));
+
+      /* Close the edit. */
+      SVN_ERR(deditor->close_edit(dedit_baton, iterpool));
+
+      /* ### This is the point at which we should probably verify something,
+       * ### but right now, we're just pleased if the tests don't crash. */
+    }
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }



Re: svn commit: r1166332 - in /subversion/trunk/subversion: libsvn_delta/compat.c tests/libsvn_delta/editor-test.c

Posted by Hyrum K Wright <hy...@wandisco.com>.
On Wed, Sep 7, 2011 at 10:52 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> hwright@apache.org wrote on Wed, Sep 07, 2011 at 19:36:01 -0000:
>> @@ -276,6 +345,60 @@ ev2_close_edit(void *edit_baton,
>>                 apr_pool_t *scratch_pool)
>>  {
>>    struct ev2_edit_baton *eb = edit_baton;
>> +  apr_array_header_t *sorted_hash;
>> +  apr_pool_t *iterpool;
>> +  int i;
>> +
>> +  /* Sort the paths touched by this edit.
>> +   * Ev2 doesn't really have any particular need for depth-first-ness, but
>> +   * we want to ensure all parent directories are handled before children in
>> +   * the case of adds (which does introduce an element of depth-first-ness). */
>> +  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
>> +                               scratch_pool);
>> +
>> +  iterpool = svn_pool_create(scratch_pool);
>> +  for (i = 0; i < sorted_hash->nelts; i++)
>> +    {
>> +      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
>> +      apr_array_header_t *actions = item->value;
>> +      const char *path = item->key;
>> +      apr_hash_t *props;
>> +      int j;
>> +
>> +      svn_pool_clear(iterpool);
>> +
>> +      props = apr_hash_make(iterpool);
>> +
>> +      /* Go through all of our actions, populating various datastructures
>> +       * dependent on them. */
>> +      for (j = 0; j < actions->nelts; j++)
>> +        {
>> +          struct path_action *action = APR_ARRAY_IDX(actions, j,
>> +                                                     struct path_action *);
>> +
>> +          switch (action->action)
>> +            {
>> +              case set_prop:
>> +                {
>> +                  struct prop_args *p_args = action->args;
>> +
>> +                  apr_hash_set(props, p_args->name, APR_HASH_KEY_STRING,
>> +                               p_args->value);
>> +                  break;
>> +                }
>> +
>> +              default:
>> +                break;
>> +            }
>> +        }
>> +
>> +      /* We've now got a wholistic view of what has happened to this node,
>> +       * so we can call our own editor APIs on it. */
>> +      if (apr_hash_count(props) > 0)
>
> What if ACTIONS contains only property deletions?

I *think* I addressed this in subsequent commits, but it did raise a
question which I added to svn_editor.h.

-Hyrum

>> +        SVN_ERR(svn_editor_set_props(eb->editor, path, SVN_INVALID_REVNUM,
>> +                                     props, TRUE));
>> +    }
>> +  svn_pool_destroy(iterpool);
>>
>>    return svn_error_trace(svn_editor_complete(eb->editor));
>>  }
>



-- 

uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/

Re: svn commit: r1166332 - in /subversion/trunk/subversion: libsvn_delta/compat.c tests/libsvn_delta/editor-test.c

Posted by Hyrum K Wright <hy...@wandisco.com>.
On Wed, Sep 7, 2011 at 10:52 PM, Daniel Shahaf <d....@daniel.shahaf.name> wrote:
> hwright@apache.org wrote on Wed, Sep 07, 2011 at 19:36:01 -0000:
>> @@ -276,6 +345,60 @@ ev2_close_edit(void *edit_baton,
>>                 apr_pool_t *scratch_pool)
>>  {
>>    struct ev2_edit_baton *eb = edit_baton;
>> +  apr_array_header_t *sorted_hash;
>> +  apr_pool_t *iterpool;
>> +  int i;
>> +
>> +  /* Sort the paths touched by this edit.
>> +   * Ev2 doesn't really have any particular need for depth-first-ness, but
>> +   * we want to ensure all parent directories are handled before children in
>> +   * the case of adds (which does introduce an element of depth-first-ness). */
>> +  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
>> +                               scratch_pool);
>> +
>> +  iterpool = svn_pool_create(scratch_pool);
>> +  for (i = 0; i < sorted_hash->nelts; i++)
>> +    {
>> +      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
>> +      apr_array_header_t *actions = item->value;
>> +      const char *path = item->key;
>> +      apr_hash_t *props;
>> +      int j;
>> +
>> +      svn_pool_clear(iterpool);
>> +
>> +      props = apr_hash_make(iterpool);
>> +
>> +      /* Go through all of our actions, populating various datastructures
>> +       * dependent on them. */
>> +      for (j = 0; j < actions->nelts; j++)
>> +        {
>> +          struct path_action *action = APR_ARRAY_IDX(actions, j,
>> +                                                     struct path_action *);
>> +
>> +          switch (action->action)
>> +            {
>> +              case set_prop:
>> +                {
>> +                  struct prop_args *p_args = action->args;
>> +
>> +                  apr_hash_set(props, p_args->name, APR_HASH_KEY_STRING,
>> +                               p_args->value);
>> +                  break;
>> +                }
>> +
>> +              default:
>> +                break;
>> +            }
>> +        }
>> +
>> +      /* We've now got a wholistic view of what has happened to this node,
>> +       * so we can call our own editor APIs on it. */
>> +      if (apr_hash_count(props) > 0)
>
> What if ACTIONS contains only property deletions?

I *think* I addressed this in subsequent commits, but it did raise a
question which I added to svn_editor.h.

-Hyrum

>> +        SVN_ERR(svn_editor_set_props(eb->editor, path, SVN_INVALID_REVNUM,
>> +                                     props, TRUE));
>> +    }
>> +  svn_pool_destroy(iterpool);
>>
>>    return svn_error_trace(svn_editor_complete(eb->editor));
>>  }
>



-- 

uberSVN: Apache Subversion Made Easy
http://www.uberSVN.com/

Re: svn commit: r1166332 - in /subversion/trunk/subversion: libsvn_delta/compat.c tests/libsvn_delta/editor-test.c

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
hwright@apache.org wrote on Wed, Sep 07, 2011 at 19:36:01 -0000:
> @@ -276,6 +345,60 @@ ev2_close_edit(void *edit_baton,
>                 apr_pool_t *scratch_pool)
>  {
>    struct ev2_edit_baton *eb = edit_baton;
> +  apr_array_header_t *sorted_hash;
> +  apr_pool_t *iterpool;
> +  int i;
> +
> +  /* Sort the paths touched by this edit.
> +   * Ev2 doesn't really have any particular need for depth-first-ness, but
> +   * we want to ensure all parent directories are handled before children in
> +   * the case of adds (which does introduce an element of depth-first-ness). */
> +  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
> +                               scratch_pool);
> +
> +  iterpool = svn_pool_create(scratch_pool);
> +  for (i = 0; i < sorted_hash->nelts; i++)
> +    {
> +      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
> +      apr_array_header_t *actions = item->value;
> +      const char *path = item->key;
> +      apr_hash_t *props;
> +      int j;
> +
> +      svn_pool_clear(iterpool);
> +
> +      props = apr_hash_make(iterpool);
> +
> +      /* Go through all of our actions, populating various datastructures
> +       * dependent on them. */
> +      for (j = 0; j < actions->nelts; j++)
> +        {
> +          struct path_action *action = APR_ARRAY_IDX(actions, j,
> +                                                     struct path_action *);
> +
> +          switch (action->action)
> +            {
> +              case set_prop:
> +                {
> +                  struct prop_args *p_args = action->args;
> +
> +                  apr_hash_set(props, p_args->name, APR_HASH_KEY_STRING,
> +                               p_args->value);
> +                  break;
> +                }
> +
> +              default:
> +                break;
> +            }
> +        }
> +
> +      /* We've now got a wholistic view of what has happened to this node,
> +       * so we can call our own editor APIs on it. */
> +      if (apr_hash_count(props) > 0)

What if ACTIONS contains only property deletions?

> +        SVN_ERR(svn_editor_set_props(eb->editor, path, SVN_INVALID_REVNUM,
> +                                     props, TRUE));
> +    }
> +  svn_pool_destroy(iterpool);
>  
>    return svn_error_trace(svn_editor_complete(eb->editor));
>  }

Re: svn commit: r1166332 - in /subversion/trunk/subversion: libsvn_delta/compat.c tests/libsvn_delta/editor-test.c

Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
hwright@apache.org wrote on Wed, Sep 07, 2011 at 19:36:01 -0000:
> @@ -276,6 +345,60 @@ ev2_close_edit(void *edit_baton,
>                 apr_pool_t *scratch_pool)
>  {
>    struct ev2_edit_baton *eb = edit_baton;
> +  apr_array_header_t *sorted_hash;
> +  apr_pool_t *iterpool;
> +  int i;
> +
> +  /* Sort the paths touched by this edit.
> +   * Ev2 doesn't really have any particular need for depth-first-ness, but
> +   * we want to ensure all parent directories are handled before children in
> +   * the case of adds (which does introduce an element of depth-first-ness). */
> +  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
> +                               scratch_pool);
> +
> +  iterpool = svn_pool_create(scratch_pool);
> +  for (i = 0; i < sorted_hash->nelts; i++)
> +    {
> +      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
> +      apr_array_header_t *actions = item->value;
> +      const char *path = item->key;
> +      apr_hash_t *props;
> +      int j;
> +
> +      svn_pool_clear(iterpool);
> +
> +      props = apr_hash_make(iterpool);
> +
> +      /* Go through all of our actions, populating various datastructures
> +       * dependent on them. */
> +      for (j = 0; j < actions->nelts; j++)
> +        {
> +          struct path_action *action = APR_ARRAY_IDX(actions, j,
> +                                                     struct path_action *);
> +
> +          switch (action->action)
> +            {
> +              case set_prop:
> +                {
> +                  struct prop_args *p_args = action->args;
> +
> +                  apr_hash_set(props, p_args->name, APR_HASH_KEY_STRING,
> +                               p_args->value);
> +                  break;
> +                }
> +
> +              default:
> +                break;
> +            }
> +        }
> +
> +      /* We've now got a wholistic view of what has happened to this node,
> +       * so we can call our own editor APIs on it. */
> +      if (apr_hash_count(props) > 0)

What if ACTIONS contains only property deletions?

> +        SVN_ERR(svn_editor_set_props(eb->editor, path, SVN_INVALID_REVNUM,
> +                                     props, TRUE));
> +    }
> +  svn_pool_destroy(iterpool);
>  
>    return svn_error_trace(svn_editor_complete(eb->editor));
>  }