subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhuij...@apache.org
Subject svn commit: r1550967 - in /subversion/trunk/subversion: libsvn_client/mtcc.c libsvn_client/mtcc.h tests/libsvn_client/mtcc-test.c
Date Sat, 14 Dec 2013 20:35:09 GMT
Author: rhuijben
Date: Sat Dec 14 20:35:08 2013
New Revision: 1550967

URL: http://svn.apache.org/r1550967
Log:
Properly handle tree replacements in the existance checking of the 'mtcc' api.

* subversion/libsvn_client/mtcc.c
  (SVN_PATH_IS_EMPTY): New define. Copied from path.c.
  (mtcc_op_find): Search children backwards to find adds before deletes.
    Properly bail on non directories.
  (get_origin): Return doesn't exist information for new nodes.
  (svn_client_mtcc_get_origin): Rename to...
  (mtcc_get_origin): ... this. Add boolean to define no origin handling.

  (svn_client_mtcc_create): Obtain and store head revision. Verify base
    revision using head revision.
  (mtcc_verify_create): Use standard error messages to ease translation.
  (svn_client_mtcc_add_add_file): Use check in standard form.
  (svn_client_mtcc_add_copy): Verify copy revision using head revision.
  (svn_client_mtcc_add_delete): Use check in standard form, fixing bug.
  (svn_client_mtcc_add_mkdir): Use check in standard form.
  (svn_client_mtcc_add_move): Update caller, asking for error message.
  (svn_client_mtcc_add_propset): Use check in standard form.
  (svn_client_mtcc_check_path): Use check in standard form. Properly
    check for replacements, etc.

* subversion/libsvn_client/mtcc.h
  (MTCC_UNMODIFIED): Handle unmodified file open as unmodified.
  (svn_client_mtcc_t): Add boolean.

* subversion/tests/libsvn_client/mtcc-test.c
  (test_replace_tree): New test.
  (test_funcs): Add test.

Modified:
    subversion/trunk/subversion/libsvn_client/mtcc.c
    subversion/trunk/subversion/libsvn_client/mtcc.h
    subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c

Modified: subversion/trunk/subversion/libsvn_client/mtcc.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/mtcc.c?rev=1550967&r1=1550966&r2=1550967&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/mtcc.c (original)
+++ subversion/trunk/subversion/libsvn_client/mtcc.c Sat Dec 14 20:35:08 2013
@@ -36,6 +36,8 @@
 
 #include <assert.h>
 
+#define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0')
+
 static svn_client_mtcc_op_t *
 mtcc_op_create(const char *name,
                svn_boolean_t add,
@@ -78,7 +80,7 @@ mtcc_op_find(svn_client_mtcc_op_t **op,
   if (created)
     *created = FALSE;
 
-  if (!*relpath)
+  if (SVN_PATH_IS_EMPTY(relpath))
     {
       if (find_existing)
         *op = base_op;
@@ -98,13 +100,21 @@ mtcc_op_find(svn_client_mtcc_op_t **op,
   else
     name = relpath;
 
-  if (child && !base_op->children)
-    return svn_error_createf(SVN_ERR_FS_NOT_DIRECTORY, NULL,
-                             _("Can't operate on '%s' because '%s' is not a "
-                               "directory"),
-                             child, base_op->name);
+  if (!base_op->children)
+    {
+      if (!created)
+        {
+          *op = NULL;
+           return SVN_NO_ERROR;
+        }
+      else
+        return svn_error_createf(SVN_ERR_FS_NOT_DIRECTORY, NULL,
+                                 _("Can't operate on '%s' because '%s' is not a "
+                                   "directory"),
+                                 name, base_op->name);
+    }
 
-  for (i = 0; i < base_op->children->nelts; i++)
+  for (i = base_op->children->nelts-1; i >= 0 ; i--)
     {
       svn_client_mtcc_op_t *cop;
 
@@ -150,7 +160,8 @@ mtcc_op_find(svn_client_mtcc_op_t **op,
 /* Gets the original repository location of RELPATH, checking things
    like copies, moves, etc.  */
 static svn_error_t *
-get_origin(const char **origin_relpath,
+get_origin(svn_boolean_t *done,
+           const char **origin_relpath,
            svn_revnum_t *rev,
            svn_client_mtcc_op_t *op,
            const char *relpath,
@@ -159,7 +170,7 @@ get_origin(const char **origin_relpath,
 {
   const char *child;
   const char *name;
-  if (!*relpath)
+  if (SVN_PATH_IS_EMPTY(relpath))
     {
       *origin_relpath = op->src_relpath
                                 ? apr_pstrdup(result_pool, op->src_relpath)
@@ -181,19 +192,25 @@ get_origin(const char **origin_relpath,
     {
       int i;
 
-      for (i = 0; i < op->children->nelts; i++)
+      for (i = op->children->nelts-1; i >= 0; i--)
         {
            svn_client_mtcc_op_t *cop;
 
            cop = APR_ARRAY_IDX(op->children, i, svn_client_mtcc_op_t *);
 
-           if (! strcmp(cop->name, name) &&  cop->kind != OP_DELETE)
+           if (! strcmp(cop->name, name))
             {
-              SVN_ERR(get_origin(origin_relpath, rev,
+              if (cop->kind == OP_DELETE)
+                {
+                  *done = TRUE;
+                  return SVN_NO_ERROR;
+                }
+
+              SVN_ERR(get_origin(done, origin_relpath, rev,
                                  cop, child ? child : "",
                                  result_pool, scratch_pool));
 
-              if (*origin_relpath)
+              if (*origin_relpath || *done)
                 return SVN_NO_ERROR;
 
               break;
@@ -201,35 +218,48 @@ get_origin(const char **origin_relpath,
         }
     }
 
-  if (op->src_relpath)
+  if (op->kind == OP_ADD_DIR || op->kind == OP_ADD_FILE)
     {
-      *origin_relpath = svn_relpath_join(op->src_relpath, relpath,
-                                         result_pool);
-      *rev = op->src_rev;
+      *done = TRUE;
+      if (op->src_relpath)
+        {
+          *origin_relpath = svn_relpath_join(op->src_relpath, relpath,
+                                             result_pool);
+          *rev = op->src_rev;
+        }
     }
 
   return SVN_NO_ERROR;
 }
 
 static svn_error_t * /* ### Make public? */
-svn_client_mtcc_get_origin(const char **origin_relpath,
-                           svn_revnum_t *rev,
-                           const char *relpath,
-                           svn_client_mtcc_t *mtcc,
-                           apr_pool_t *result_pool,
-                           apr_pool_t *scratch_pool)
+mtcc_get_origin(const char **origin_relpath,
+                svn_revnum_t *rev,
+                const char *relpath,
+                svn_boolean_t ignore_enoent,
+                svn_client_mtcc_t *mtcc,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
 {
+  svn_boolean_t done = FALSE;
+
   *origin_relpath = NULL;
   *rev = SVN_INVALID_REVNUM;
 
-  SVN_ERR(get_origin(origin_relpath, rev, mtcc->root_op, relpath,
+  SVN_ERR(get_origin(&done, origin_relpath, rev, mtcc->root_op, relpath,
                      result_pool, scratch_pool));
 
-  if (!*origin_relpath)
+  if (!*origin_relpath && !done)
     {
       *origin_relpath = apr_pstrdup(result_pool, relpath);
       *rev = mtcc->base_revision;
     }
+  else if (!ignore_enoent)
+    {
+      return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+                               _("No origin found for node at '%s'"),
+                               relpath);
+    }
 
   return SVN_NO_ERROR;
 }
@@ -258,6 +288,16 @@ svn_client_mtcc_create(svn_client_mtcc_t
                                       NULL /* wri_abspath */, ctx,
                                       mtcc_pool, scratch_pool));
 
+  SVN_ERR(svn_ra_get_latest_revnum((*mtcc)->ra_session, &(*mtcc)->head_revision,
+                                   scratch_pool));
+
+  if (! SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = (*mtcc)->head_revision;
+  else if (base_revision > (*mtcc)->head_revision)
+    return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                             _("No such revision %ld (HEAD is %ld)"),
+                             base_revision, (*mtcc)->head_revision);
+
   return SVN_NO_ERROR;
 }
 
@@ -353,8 +393,7 @@ mtcc_verify_create(svn_client_mtcc_t *mt
 
       if (op)
         return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
-                                 _("Can't create '%s': target already "
-                                   "operated on"),
+                                 _("Path '%s' already exists"),
                                  new_relpath);
 
       SVN_ERR(mtcc_op_find(&op, NULL, new_relpath, mtcc->root_op, TRUE, TRUE,
@@ -371,7 +410,7 @@ mtcc_verify_create(svn_client_mtcc_t *mt
 
   if (kind != svn_node_none)
     return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
-                             _("Can't copy to '%s': target already exists"),
+                             _("Path '%s' already exists"),
                              new_relpath);
 
   return SVN_NO_ERROR;
@@ -391,7 +430,7 @@ svn_client_mtcc_add_add_file(const char 
 
   SVN_ERR(mtcc_verify_create(mtcc, relpath, scratch_pool));
 
-  if (!*relpath && MTCC_UNMODIFIED(mtcc))
+  if (SVN_PATH_IS_EMPTY(relpath) && MTCC_UNMODIFIED(mtcc))
     {
       /* Turn the root operation into a file addition */
       op = mtcc->root_op;
@@ -429,8 +468,15 @@ svn_client_mtcc_add_copy(const char *src
   svn_node_kind_t kind;
 
   SVN_ERR_ASSERT(svn_relpath_is_canonical(src_relpath)
-                 && svn_relpath_is_canonical(dst_relpath)
-                 && SVN_IS_VALID_REVNUM(revision));
+                 && svn_relpath_is_canonical(dst_relpath));
+
+  if (! SVN_IS_VALID_REVNUM(revision))
+    revision = mtcc->head_revision;
+  else if (revision > mtcc->head_revision)
+    {
+      return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                               _("No such revision %ld"), revision);
+    }
 
   SVN_ERR(mtcc_verify_create(mtcc, dst_relpath, scratch_pool));
 
@@ -440,9 +486,8 @@ svn_client_mtcc_add_copy(const char *src
 
   if (kind != svn_node_dir && kind != svn_node_file)
     {
-      return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                               _("Can't create a copy of '%s' at revision %ld "
-                                 "as it does not exist"),
+      return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+                               _("Path '%s' not found in revision %ld"),
                                src_relpath, revision);
     }
 
@@ -483,7 +528,7 @@ svn_client_mtcc_add_delete(const char *r
                                 "does not exist"),
                              relpath);
 
-  if (! *relpath || MTCC_UNMODIFIED(mtcc))
+  if (SVN_PATH_IS_EMPTY(relpath) && MTCC_UNMODIFIED(mtcc))
     {
       /* Turn root operation into delete */
       op = mtcc->root_op;
@@ -519,7 +564,7 @@ svn_client_mtcc_add_mkdir(const char *re
 
   SVN_ERR(mtcc_verify_create(mtcc, relpath, scratch_pool));
 
-  if (! *relpath && MTCC_UNMODIFIED(mtcc))
+  if (SVN_PATH_IS_EMPTY(relpath) && MTCC_UNMODIFIED(mtcc))
     {
       /* Turn the root of the operation in an MKDIR */
       mtcc->root_op->kind = OP_ADD_DIR;
@@ -551,9 +596,9 @@ svn_client_mtcc_add_move(const char *src
   const char *origin_relpath;
   svn_revnum_t origin_rev;
 
-  SVN_ERR(svn_client_mtcc_get_origin(&origin_relpath, &origin_rev,
-                                     src_relpath, mtcc,
-                                     scratch_pool, scratch_pool));
+  SVN_ERR(mtcc_get_origin(&origin_relpath, &origin_rev,
+                          src_relpath, FALSE, mtcc,
+                          scratch_pool, scratch_pool));
 
   SVN_ERR(svn_client_mtcc_add_copy(src_relpath, mtcc->base_revision,
                                    dst_relpath, mtcc, scratch_pool));
@@ -602,7 +647,7 @@ svn_client_mtcc_add_propset(const char *
       /* ### TODO: Call svn_wc_canonicalize_svn_prop() */
     }
 
-  if (!*relpath && MTCC_UNMODIFIED(mtcc))
+  if (SVN_PATH_IS_EMPTY(relpath) && MTCC_UNMODIFIED(mtcc))
     {
       svn_node_kind_t kind;
 
@@ -724,9 +769,8 @@ svn_client_mtcc_check_path(svn_node_kind
 
   SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
 
-  if (!*relpath
-      && !mtcc->root_op->performed_stat
-      && MTCC_UNMODIFIED(mtcc))
+  if (SVN_PATH_IS_EMPTY(relpath) && MTCC_UNMODIFIED(mtcc)
+      && !mtcc->root_op->performed_stat)
     {
       /* We know nothing about the root. Perhaps it is a file? */
       SVN_ERR(svn_ra_check_path(mtcc->ra_session, "", mtcc->base_revision,
@@ -746,12 +790,15 @@ svn_client_mtcc_check_path(svn_node_kind
 
   if (!op || (check_repository && !op->performed_stat))
     {
-      SVN_ERR(svn_client_mtcc_get_origin(&origin_relpath, &origin_rev,
-                                     relpath, mtcc,
-                                     scratch_pool, scratch_pool));
+      SVN_ERR(mtcc_get_origin(&origin_relpath, &origin_rev,
+                              relpath, TRUE, mtcc,
+                              scratch_pool, scratch_pool));
 
-      SVN_ERR(svn_ra_check_path(mtcc->ra_session, origin_relpath,
-                                origin_rev, kind, scratch_pool));
+      if (!origin_relpath)
+        *kind = svn_node_none;
+      else
+        SVN_ERR(svn_ra_check_path(mtcc->ra_session, origin_relpath,
+                                  origin_rev, kind, scratch_pool));
 
       if (op && *kind == svn_node_dir)
         {

Modified: subversion/trunk/subversion/libsvn_client/mtcc.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/mtcc.h?rev=1550967&r1=1550966&r2=1550967&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/mtcc.h (original)
+++ subversion/trunk/subversion/libsvn_client/mtcc.h Sat Dec 14 20:35:08 2013
@@ -55,14 +55,18 @@ typedef struct svn_client_mtcc_op_t
 } svn_client_mtcc_op_t;
 
 /* Check if the mtcc doesn't contain any modifications yet */
-#define MTCC_UNMODIFIED(mtcc)                                                  \
-    ((mtcc->root_op->kind == OP_OPEN_DIR)                                      \
-     && (mtcc->root_op->prop_mods == NULL || !mtcc->root_op->prop_mods->nelts)
\
-     && (mtcc->root_op->children == NULL || !mtcc->root_op->children->nelts))
+#define MTCC_UNMODIFIED(mtcc)                                               \
+    ((mtcc->root_op->kind == OP_OPEN_DIR                                    \
+                            || mtcc->root_op->kind == OP_OPEN_FILE)         \
+     && (mtcc->root_op->prop_mods == NULL                                 
 \
+                            || !mtcc->root_op->prop_mods->nelts)            \
+     && (mtcc->root_op->children == NULL                                  
 \
+                            || !mtcc->root_op->children->nelts))
 
 struct svn_client_mtcc_t
 {
   apr_pool_t *pool;
+  svn_revnum_t head_revision;
   svn_revnum_t base_revision;
 
   svn_ra_session_t *ra_session;

Modified: subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c?rev=1550967&r1=1550966&r2=1550967&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_client/mtcc-test.c Sat Dec 14 20:35:08 2013
@@ -417,6 +417,42 @@ test_anchoring(const svn_test_opts_t *op
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_replace_tree(const svn_test_opts_t *opts,
+                  apr_pool_t *pool)
+{
+  svn_client_mtcc_t *mtcc;
+  svn_client_ctx_t *ctx;
+  const char *repos_abspath;
+  const char *repos_url;
+  svn_repos_t* repos;
+
+  repos_abspath = svn_test_data_path("mtcc-replace_tree", pool);
+  SVN_ERR(svn_dirent_get_absolute(&repos_abspath, repos_abspath, pool));
+  SVN_ERR(svn_uri_get_file_url_from_dirent(&repos_url, repos_abspath, pool));
+  SVN_ERR(svn_test__create_repos(&repos, repos_abspath, opts, pool));
+
+  SVN_ERR(make_greek_tree(repos_url, pool));
+
+  SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
+
+  /* Update a file as root operation */
+  SVN_ERR(svn_client_mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
+
+  SVN_ERR(svn_client_mtcc_add_delete("A", mtcc, pool));
+  SVN_ERR(svn_client_mtcc_add_delete("iota", mtcc, pool));
+  SVN_ERR(svn_client_mtcc_add_mkdir("A", mtcc, pool));
+  SVN_ERR(svn_client_mtcc_add_mkdir("A/B", mtcc, pool));
+  SVN_ERR(svn_client_mtcc_add_mkdir("A/B/C", mtcc, pool));
+  SVN_ERR(svn_client_mtcc_add_mkdir("M", mtcc, pool));
+  SVN_ERR(svn_client_mtcc_add_mkdir("M/N", mtcc, pool));
+  SVN_ERR(svn_client_mtcc_add_mkdir("M/N/O", mtcc, pool));
+
+  SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* ========================================================================== */
 
 
@@ -439,6 +475,8 @@ struct svn_test_descriptor_t test_funcs[
                        "test overwrite"),
     SVN_TEST_OPTS_PASS(test_anchoring,
                        "test mtcc anchoring for root operations"),
+    SVN_TEST_OPTS_PASS(test_replace_tree,
+                       "test mtcc replace tree"),
     SVN_TEST_NULL
   };
  



Mime
View raw message