subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1173112 - /subversion/trunk/subversion/libsvn_delta/compat.c
Date Tue, 20 Sep 2011 12:28:04 GMT
Author: hwright
Date: Tue Sep 20 12:28:04 2011
New Revision: 1173112

URL: http://svn.apache.org/viewvc?rev=1173112&view=rev
Log:
Lift in-memory delta tree construction code from svnmucc and drop it into the 
Delta Editor -> Ev2 compat shim.

This is something of a checkpoint commit.  The code compiles, but doesn't do
much more than that (it isin't even invoked).  This code is still very 
ra session-centric, but will be generalized in a subsequent commit.

* subversion/libsvn_delta/compat.c
  (action_code_t, operation): New types.
  (get_operation, subtract_anchor, build): New.

Modified:
    subversion/trunk/subversion/libsvn_delta/compat.c

Modified: subversion/trunk/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/compat.c?rev=1173112&r1=1173111&r2=1173112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/compat.c (original)
+++ subversion/trunk/subversion/libsvn_delta/compat.c Tue Sep 20 12:28:04 2011
@@ -25,6 +25,8 @@
 #include "svn_error.h"
 #include "svn_delta.h"
 #include "svn_sorts.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
 #include "svn_pools.h"
 
 
@@ -531,6 +533,293 @@ struct editor_baton
   apr_pool_t *edit_pool;
 };
 
+
+typedef enum action_code_t {
+  ACTION_MV,
+  ACTION_MKDIR,
+  ACTION_CP,
+  ACTION_PROPSET,
+  ACTION_PROPSETF,
+  ACTION_PROPDEL,
+  ACTION_PUT,
+  ACTION_RM
+} action_code_t;
+
+struct operation {
+  enum {
+    OP_OPEN,
+    OP_DELETE,
+    OP_ADD,
+    OP_REPLACE,
+    OP_PROPSET           /* only for files for which no other operation is
+                            occuring; directories are OP_OPEN with non-empty
+                            props */
+  } operation;
+  svn_node_kind_t kind;  /* to copy, mkdir, put or set revprops */
+  svn_revnum_t rev;      /* to copy, valid for add and replace */
+  const char *url;       /* to copy, valid for add and replace */
+  const char *src_file;  /* for put, the source file for contents */
+  apr_hash_t *children;  /* const char *path -> struct operation * */
+  apr_hash_t *prop_mods; /* const char *prop_name ->
+                            const svn_string_t *prop_value */
+  apr_array_header_t *prop_dels; /* const char *prop_name deletions */
+  void *baton;           /* as returned by the commit editor */
+};
+
+
+/* Find the operation associated with PATH, which is a single-path
+   component representing a child of the path represented by
+   OPERATION.  If no such child operation exists, create a new one of
+   type OP_OPEN. */
+static struct operation *
+get_operation(const char *path,
+              struct operation *operation,
+              apr_pool_t *pool)
+{
+  struct operation *child = apr_hash_get(operation->children, path,
+                                         APR_HASH_KEY_STRING);
+  if (! child)
+    {
+      child = apr_pcalloc(pool, sizeof(*child));
+      child->children = apr_hash_make(pool);
+      child->operation = OP_OPEN;
+      child->rev = SVN_INVALID_REVNUM;
+      child->kind = svn_node_dir;
+      child->prop_mods = apr_hash_make(pool);
+      child->prop_dels = apr_array_make(pool, 1, sizeof(const char *));
+      apr_hash_set(operation->children, path, APR_HASH_KEY_STRING, child);
+    }
+  return child;
+}
+
+/* Return the portion of URL that is relative to ANCHOR (URI-decoded). */
+static const char *
+subtract_anchor(const char *anchor, const char *url, apr_pool_t *pool)
+{
+  return svn_uri_skip_ancestor(anchor, url, pool);
+}
+
+/* Add PATH to the operations tree rooted at OPERATION, creating any
+   intermediate nodes that are required.  Here's what's expected for
+   each action type:
+
+      ACTION          URL    REV      SRC-FILE  PROPNAME
+      ------------    -----  -------  --------  --------
+      ACTION_MKDIR    NULL   invalid  NULL      NULL
+      ACTION_CP       valid  valid    NULL      NULL
+      ACTION_PUT      NULL   invalid  valid     NULL
+      ACTION_RM       NULL   invalid  NULL      NULL
+      ACTION_PROPSET  valid  invalid  NULL      valid
+      ACTION_PROPDEL  valid  invalid  NULL      valid
+
+   Node type information is obtained for any copy source (to determine
+   whether to create a file or directory) and for any deleted path (to
+   ensure it exists since svn_delta_editor_t->delete_entry doesn't
+   return an error on non-existent nodes). */
+static svn_error_t *
+build(action_code_t action,
+      const char *path,
+      const char *url,
+      svn_revnum_t rev,
+      const char *prop_name,
+      const svn_string_t *prop_value,
+      const char *src_file,
+      svn_revnum_t head,
+      const char *anchor,
+      struct operation *operation,
+      apr_pool_t *pool)
+{
+  apr_array_header_t *path_bits = svn_path_decompose(path, pool);
+  const char *path_so_far = "";
+  const char *copy_src = NULL;
+  svn_revnum_t copy_rev = SVN_INVALID_REVNUM;
+  int i;
+
+  /* Look for any previous operations we've recognized for PATH.  If
+     any of PATH's ancestors have not yet been traversed, we'll be
+     creating OP_OPEN operations for them as we walk down PATH's path
+     components. */
+  for (i = 0; i < path_bits->nelts; ++i)
+    {
+      const char *path_bit = APR_ARRAY_IDX(path_bits, i, const char *);
+      path_so_far = svn_relpath_join(path_so_far, path_bit, pool);
+      operation = get_operation(path_so_far, operation, pool);
+
+      /* If we cross a replace- or add-with-history, remember the
+      source of those things in case we need to lookup the node kind
+      of one of their children.  And if this isn't such a copy,
+      but we've already seen one in of our parent paths, we just need
+      to extend that copy source path by our current path
+      component. */
+      if (operation->url
+          && SVN_IS_VALID_REVNUM(operation->rev)
+          && (operation->operation == OP_REPLACE
+              || operation->operation == OP_ADD))
+        {
+          copy_src = subtract_anchor(anchor, operation->url, pool);
+          copy_rev = operation->rev;
+        }
+      else if (copy_src)
+        {
+          copy_src = svn_relpath_join(copy_src, path_bit, pool);
+        }
+    }
+
+  /* Handle property changes. */
+  if (prop_name)
+    {
+      if (operation->operation == OP_DELETE)
+        return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                 "cannot set properties on a location being"
+                                 " deleted ('%s')", path);
+      /* If we're not adding this thing ourselves, check for existence.  */
+      if (! ((operation->operation == OP_ADD) ||
+             (operation->operation == OP_REPLACE)))
+        {
+          /* ### HKW:
+          SVN_ERR(svn_ra_check_path(session,
+                                    copy_src ? copy_src : path,
+                                    copy_src ? copy_rev : head,
+                                    &operation->kind, pool));*/
+          if (operation->kind == svn_node_none)
+            return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                     "propset: '%s' not found", path);
+          else if ((operation->kind == svn_node_file)
+                   && (operation->operation == OP_OPEN))
+            operation->operation = OP_PROPSET;
+        }
+      if (! prop_value)
+        APR_ARRAY_PUSH(operation->prop_dels, const char *) = prop_name;
+      else
+        apr_hash_set(operation->prop_mods, prop_name,
+                     APR_HASH_KEY_STRING, prop_value);
+      if (!operation->rev)
+        operation->rev = rev;
+      return SVN_NO_ERROR;
+    }
+
+  /* We won't fuss about multiple operations on the same path in the
+     following cases:
+
+       - the prior operation was, in fact, a no-op (open)
+       - the prior operation was a propset placeholder
+       - the prior operation was a deletion
+
+     Note: while the operation structure certainly supports the
+     ability to do a copy of a file followed by a put of new contents
+     for the file, we don't let that happen (yet).
+  */
+  if (operation->operation != OP_OPEN
+      && operation->operation != OP_PROPSET
+      && operation->operation != OP_DELETE)
+    return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                             "unsupported multiple operations on '%s'", path);
+
+  /* For deletions, we validate that there's actually something to
+     delete.  If this is a deletion of the child of a copied
+     directory, we need to remember to look in the copy source tree to
+     verify that this thing actually exists. */
+  if (action == ACTION_RM)
+    {
+      operation->operation = OP_DELETE;
+      /* ### HKW
+      SVN_ERR(svn_ra_check_path(session,
+                                copy_src ? copy_src : path,
+                                copy_src ? copy_rev : head,
+                                &operation->kind, pool));*/
+      if (operation->kind == svn_node_none)
+        {
+          if (copy_src && strcmp(path, copy_src))
+            return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                     "'%s' (from '%s:%ld') not found",
+                                     path, copy_src, copy_rev);
+          else
+            return svn_error_createf(SVN_ERR_BAD_URL, NULL, "'%s' not found",
+                                     path);
+        }
+    }
+  /* Handle copy operations (which can be adds or replacements). */
+  else if (action == ACTION_CP)
+    {
+      if (rev > head)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                "Copy source revision cannot be younger "
+                                "than base revision");
+      operation->operation =
+        operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
+      if (operation->operation == OP_ADD)
+        {
+          /* There is a bug in the current version of mod_dav_svn
+             which incorrectly replaces existing directories.
+             Therefore we need to check if the target exists
+             and raise an error here. */
+          /* ### HKW:
+          SVN_ERR(svn_ra_check_path(session,
+                                    copy_src ? copy_src : path,
+                                    copy_src ? copy_rev : head,
+                                    &operation->kind, pool));*/
+          if (operation->kind != svn_node_none)
+            {
+              if (copy_src && strcmp(path, copy_src))
+                return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                         "'%s' (from '%s:%ld') already exists",
+                                         path, copy_src, copy_rev);
+              else
+                return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                         "'%s' already exists", path);
+            }
+        }
+      /* ### HKW:
+      SVN_ERR(svn_ra_check_path(session, subtract_anchor(anchor, url, pool),
+                                rev, &operation->kind, pool));*/
+      if (operation->kind == svn_node_none)
+        return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                 "'%s' not found",
+                                  subtract_anchor(anchor, url, pool));
+      operation->url = url;
+      operation->rev = rev;
+    }
+  /* Handle mkdir operations (which can be adds or replacements). */
+  else if (action == ACTION_MKDIR)
+    {
+      operation->operation =
+        operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
+      operation->kind = svn_node_dir;
+    }
+  /* Handle put operations (which can be adds, replacements, or opens). */
+  else if (action == ACTION_PUT)
+    {
+      if (operation->operation == OP_DELETE)
+        {
+          operation->operation = OP_REPLACE;
+        }
+      else
+        {
+          /* ### HKW:
+          SVN_ERR(svn_ra_check_path(session,
+                                    copy_src ? copy_src : path,
+                                    copy_src ? copy_rev : head,
+                                    &operation->kind, pool));*/
+          if (operation->kind == svn_node_file)
+            operation->operation = OP_OPEN;
+          else if (operation->kind == svn_node_none)
+            operation->operation = OP_ADD;
+          else
+            return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                     "'%s' is not a file", path);
+        }
+      operation->kind = svn_node_file;
+      operation->src_file = src_file;
+    }
+  else
+    {
+      /* We shouldn't get here. */
+      SVN_ERR_MALFUNCTION();
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* This implements svn_editor_cb_add_directory_t */
 static svn_error_t *
 add_directory_cb(void *baton,



Mime
View raw message