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/08/15 14:32:43 UTC

svn commit: r1157811 [2/3] - in /subversion/branches/fs-py: ./ subversion/bindings/ctypes-python/csvn/ subversion/bindings/ctypes-python/test/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bi...

Modified: subversion/branches/fs-py/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_ra_serf/util.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_ra_serf/util.c Mon Aug 15 12:32:42 2011
@@ -821,7 +821,7 @@ start_error(svn_ra_serf__xml_parser_t *p
         }
       else
         {
-          ctx->error->apr_err = APR_EGENERAL;
+          ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
         }
 
       /* Start collecting cdata. */
@@ -1497,6 +1497,21 @@ inject_to_parser(svn_ra_serf__xml_parser
   return SVN_NO_ERROR;
 }
 
+/* Apr pool cleanup handler to release an XML_Parser in success and error
+   conditions */
+static apr_status_t
+xml_parser_cleanup(void *baton)
+{
+  XML_Parser *xmlp = baton;
+
+  if (*xmlp)
+    {
+      XML_ParserFree(*xmlp);
+      *xmlp = NULL;
+    }
+
+  return APR_SUCCESS;
+}
 
 svn_error_t *
 svn_ra_serf__process_pending(svn_ra_serf__xml_parser_t *parser,
@@ -1633,7 +1648,7 @@ svn_ra_serf__process_pending(svn_ra_serf
          return status. We just don't care.  */
       (void) XML_Parse(parser->xmlp, NULL, 0, 1);
 
-      XML_ParserFree(parser->xmlp);
+      apr_pool_cleanup_run(parser->pool, &parser->xmlp, xml_parser_cleanup);
       parser->xmlp = NULL;
       add_done_item(parser);
     }
@@ -1690,9 +1705,27 @@ svn_ra_serf__handle_xml_parser(serf_requ
       return SVN_NO_ERROR;
     }
 
+  if (ctx->headers_baton == NULL)
+    ctx->headers_baton = serf_bucket_response_get_headers(response);
+  else if (ctx->headers_baton != serf_bucket_response_get_headers(response))
+    {
+      /* We got a new response to an existing parser...
+         This tells us the connection has restarted and we should continue
+         where we stopped last time.
+       */
+
+      /* Is this a second attempt?? */
+      if (!ctx->skip_size)
+        ctx->skip_size = ctx->read_size;
+
+      ctx->read_size = 0; /* New request, nothing read */
+    }
+
   if (!ctx->xmlp)
     {
       ctx->xmlp = XML_ParserCreate(NULL);
+      apr_pool_cleanup_register(ctx->pool, &ctx->xmlp, xml_parser_cleanup,
+                                apr_pool_cleanup_null);
       XML_SetUserData(ctx->xmlp, ctx);
       XML_SetElementHandler(ctx->xmlp, start_xml, end_xml);
       if (ctx->cdata)
@@ -1732,6 +1765,35 @@ svn_ra_serf__handle_xml_parser(serf_requ
           return svn_error_wrap_apr(status, NULL);
         }
 
+      ctx->read_size += len;
+
+      if (ctx->skip_size)
+        {
+          /* Handle restarted requests correctly: Skip what we already read */
+          apr_size_t skip;
+
+          if (ctx->skip_size >= ctx->read_size)
+            {
+            /* Eek.  What did the file shrink or something? */
+              if (APR_STATUS_IS_EOF(status))
+                {
+                  SVN_ERR_MALFUNCTION();
+                }
+
+              /* Skip on to the next iteration of this loop. */
+              if (APR_STATUS_IS_EAGAIN(status))
+                {
+                  return svn_error_wrap_apr(status, NULL);
+                }
+              continue;
+            }
+
+          skip = (apr_size_t)(len - (ctx->read_size - ctx->skip_size));
+          data += skip;
+          len -= skip;
+          ctx->skip_size = 0;
+        }
+
       /* Ensure that the parser's PAUSED state is correct before we test
          the flag.  */
       PBTEST_SET_PAUSED(ctx);
@@ -1783,8 +1845,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
         {
           SVN_ERR_ASSERT(ctx->xmlp != NULL);
 
-          XML_ParserFree(ctx->xmlp);
-          ctx->xmlp = NULL;
+          apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
           add_done_item(ctx);
           return svn_error_trace(err);
         }
@@ -1818,8 +1879,7 @@ svn_ra_serf__handle_xml_parser(serf_requ
               /* Ignore the return status. We just don't care.  */
               (void) XML_Parse(ctx->xmlp, NULL, 0, 1);
 
-              XML_ParserFree(ctx->xmlp);
-              ctx->xmlp = NULL;
+              apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
               add_done_item(ctx);
             }
 
@@ -2013,17 +2073,27 @@ handle_response(serf_request_t *request,
 
   ctx->conn->last_status_code = sl.code;
 
-  if (sl.code == 409 || sl.code >= 500)
+  if (sl.code == 405 || sl.code == 409 || sl.code >= 500)
     {
-      /* 409 Conflict: can indicate a hook error.
+      /* 405 Method Not allowed.
+         409 Conflict: can indicate a hook error.
          5xx (Internal) Server error. */
       SVN_ERR(svn_ra_serf__handle_server_error(request, response, pool));
 
       if (!ctx->session->pending_error)
         {
+          apr_status_t apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
+
+          /* 405 == Method Not Allowed (Occurs when trying to lock a working
+             copy path which no longer exists at HEAD in the repository. */
+
+          if (sl.code == 405 && !strcmp(ctx->method, "LOCK"))
+            apr_err = SVN_ERR_FS_OUT_OF_DATE;
+
           return
-              svn_error_createf(APR_EGENERAL, NULL,
-              _("Unspecified error message: %d %s"), sl.code, sl.reason);
+              svn_error_createf(apr_err, NULL,
+                                _("%s request on '%s' failed: %d %s"),
+                                ctx->method, ctx->path, sl.code, sl.reason);
         }
 
       return SVN_NO_ERROR; /* Error is set in caller */
@@ -2249,7 +2319,7 @@ svn_ra_serf__discover_vcc(const char **v
           if ((err->apr_err != SVN_ERR_FS_NOT_FOUND) &&
               (err->apr_err != SVN_ERR_RA_DAV_FORBIDDEN))
             {
-              return err;  /* found a _real_ error */
+              return svn_error_trace(err);  /* found a _real_ error */
             }
           else
             {

Modified: subversion/branches/fs-py/subversion/libsvn_wc/info.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/info.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/info.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/info.c Mon Aug 15 12:32:42 2011
@@ -63,6 +63,11 @@ svn_wc_info_dup(const svn_wc_info_t *inf
     new_info->copyfrom_url = apr_pstrdup(pool, info->copyfrom_url);
   if (info->wcroot_abspath)
     new_info->wcroot_abspath = apr_pstrdup(pool, info->wcroot_abspath);
+  if (info->moved_from_abspath)
+    new_info->moved_from_abspath = apr_pstrdup(pool, info->moved_from_abspath);
+  if (info->moved_to_abspath)
+    new_info->moved_to_abspath = apr_pstrdup(pool, info->moved_to_abspath);
+
   return new_info;
 }
 
@@ -146,6 +151,12 @@ build_info_for_node(svn_wc__info2_t **in
 
               wc_info->copyfrom_rev = original_revision;
             }
+
+          SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL, NULL,
+                                           NULL, NULL, NULL,
+                                           &wc_info->moved_from_abspath, NULL,
+                                           db, local_abspath,
+                                           result_pool, scratch_pool));
         }
       else if (op_root)
         {
@@ -199,7 +210,7 @@ build_info_for_node(svn_wc__info2_t **in
                                             result_pool, scratch_pool));
 
       /* And now fetch the url and revision of what will be deleted */
-      SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
+      SVN_ERR(svn_wc__db_scan_deletion(NULL, &wc_info->moved_to_abspath,
                                        &work_del_abspath, NULL,
                                        db, local_abspath,
                                        scratch_pool, scratch_pool));

Modified: subversion/branches/fs-py/subversion/libsvn_wc/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/merge.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/merge.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/merge.c Mon Aug 15 12:32:42 2011
@@ -814,7 +814,7 @@ setup_text_conflict_desc(const char *lef
   svn_wc_conflict_description2_t *cdesc;
 
   cdesc = svn_wc_conflict_description_create_text2(target_abspath, pool);
-  cdesc->is_binary = FALSE;
+  cdesc->is_binary = is_binary;
   cdesc->mime_type = (mimeprop && mimeprop->value)
                      ? mimeprop->value->data : NULL,
   cdesc->base_abspath = left_abspath;

Modified: subversion/branches/fs-py/subversion/libsvn_wc/node.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/node.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/node.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/node.c Mon Aug 15 12:32:42 2011
@@ -1647,7 +1647,6 @@ svn_wc__check_for_obstructions(svn_wc_no
                                svn_node_kind_t *kind,
                                svn_boolean_t *added,
                                svn_boolean_t *deleted,
-                               svn_boolean_t *conflicted,
                                svn_wc_context_t *wc_ctx,
                                const char *local_abspath,
                                svn_boolean_t no_wcroot_check,
@@ -1656,7 +1655,6 @@ svn_wc__check_for_obstructions(svn_wc_no
   svn_wc__db_status_t status;
   svn_wc__db_kind_t db_kind;
   svn_node_kind_t disk_kind;
-  svn_boolean_t conflicted_p;
   svn_error_t *err;
 
   *obstruction_state = svn_wc_notify_state_inapplicable;
@@ -1666,14 +1664,12 @@ svn_wc__check_for_obstructions(svn_wc_no
     *added = FALSE;
   if (deleted)
     *deleted = FALSE;
-  if (conflicted)
-    *conflicted = FALSE;
 
   SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
 
   err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
                              NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                             NULL, NULL, NULL, NULL, NULL, &conflicted_p, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                              NULL, NULL, NULL, NULL, NULL,
                              wc_ctx->db, local_abspath,
                              scratch_pool, scratch_pool);
@@ -1779,17 +1775,6 @@ svn_wc__check_for_obstructions(svn_wc_no
         SVN_ERR_MALFUNCTION();
     }
 
-  if (conflicted_p && (conflicted != NULL))
-    {
-      svn_boolean_t text_c, prop_c, tree_c;
-
-      SVN_ERR(svn_wc__internal_conflicted_p(&text_c, &prop_c, &tree_c,
-                                            wc_ctx->db, local_abspath,
-                                            scratch_pool));
-
-      *conflicted = (text_c || prop_c || tree_c);
-    }
-
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/fs-py/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/status.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/status.c Mon Aug 15 12:32:42 2011
@@ -365,7 +365,7 @@ internal_status(svn_wc_status3_t **statu
 /* Fill in *STATUS for LOCAL_ABSPATH, using DB. Allocate *STATUS in
    RESULT_POOL and use SCRATCH_POOL for temporary allocations.
 
-   PARENT_REPOS_ROOT_URL and PARENT_REPOS_RELPATH are the the repository root
+   PARENT_REPOS_ROOT_URL and PARENT_REPOS_RELPATH are the repository root
    and repository relative path of the parent of LOCAL_ABSPATH or NULL if
    LOCAL_ABSPATH doesn't have a versioned parent directory.
 
@@ -403,6 +403,9 @@ assemble_status(svn_wc_status3_t **statu
   const char *repos_relpath;
   const char *repos_root_url;
   const char *repos_uuid;
+  const char *moved_from_abspath = NULL;
+  const char *moved_to_abspath = NULL;
+  const char *moved_to_op_root_abspath = NULL;
   svn_filesize_t filesize = (dirent && (dirent->kind == svn_node_file))
                                 ? dirent->filesize
                                 : SVN_INVALID_FILESIZE;
@@ -426,7 +429,7 @@ assemble_status(svn_wc_status3_t **statu
       switched_p = !name || (strcmp(name, svn_dirent_basename(local_abspath, NULL)) != 0);
     }
 
-  /* Examine whether our target is missing or obstructed or missing.
+  /* Examine whether our target is missing or obstructed.
 
      While we are not completely in single-db mode yet, data about
      obstructed or missing nodes might be incomplete here. This is
@@ -608,6 +611,24 @@ assemble_status(svn_wc_status3_t **statu
         }
     }
 
+  /* Get moved-to info. */
+  if (info->status == svn_wc__db_status_deleted)
+    SVN_ERR(svn_wc__db_scan_deletion(NULL,
+                                     &moved_to_abspath,
+                                     NULL,
+                                     &moved_to_op_root_abspath,
+                                     db, local_abspath,
+                                     result_pool, scratch_pool));
+
+  /* Get moved-from info. */
+  if (info->status == svn_wc__db_status_added)
+    SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL,
+                                     NULL, NULL, NULL, NULL,
+                                     &moved_from_abspath,
+                                     NULL,
+                                     db, local_abspath,
+                                     result_pool, scratch_pool));
+
   if (node_status == svn_wc_status_normal)
     node_status = text_status;
 
@@ -700,6 +721,10 @@ assemble_status(svn_wc_status3_t **statu
   stat->repos_relpath = repos_relpath;
   stat->repos_uuid = repos_uuid;
 
+  stat->moved_from_abspath = moved_from_abspath;
+  stat->moved_to_abspath = moved_to_abspath;
+  stat->moved_to_op_root_abspath = moved_to_op_root_abspath;
+
   *status = stat;
 
   return SVN_NO_ERROR;
@@ -2591,6 +2616,18 @@ svn_wc_dup_status3(const svn_wc_status3_
     new_stat->repos_uuid
       = apr_pstrdup(pool, orig_stat->repos_uuid);
 
+  if (orig_stat->moved_from_abspath)
+    new_stat->moved_from_abspath
+      = apr_pstrdup(pool, orig_stat->moved_from_abspath);
+
+  if (orig_stat->moved_to_abspath)
+    new_stat->moved_to_abspath
+      = apr_pstrdup(pool, orig_stat->moved_to_abspath);
+
+  if (orig_stat->moved_to_op_root_abspath)
+    new_stat->moved_to_op_root_abspath
+      = apr_pstrdup(pool, orig_stat->moved_to_op_root_abspath);
+
   /* Return the new hotness. */
   return new_stat;
 }

Modified: subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c Mon Aug 15 12:32:42 2011
@@ -3935,10 +3935,13 @@ close_file(void *file_baton,
   if (fb->new_text_base_md5_checksum && expected_md5_checksum
       && !svn_checksum_match(expected_md5_checksum,
                              fb->new_text_base_md5_checksum))
-    return svn_checksum_mismatch_err(expected_md5_checksum,
-                            fb->new_text_base_md5_checksum, scratch_pool,
-                            _("Checksum mismatch for '%s'"),
-                            svn_dirent_local_style(fb->local_abspath, pool));
+    return svn_error_trace(
+                svn_checksum_mismatch_err(expected_md5_checksum,
+                                          fb->new_text_base_md5_checksum,
+                                          scratch_pool,
+                                          _("Checksum mismatch for '%s'"),
+                                          svn_dirent_local_style(
+                                                fb->local_abspath, pool)));
 
   /* Gather the changes for each kind of property.  */
   SVN_ERR(svn_categorize_props(fb->propchanges, &entry_prop_changes,

Modified: subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c Mon Aug 15 12:32:42 2011
@@ -1106,6 +1106,18 @@ migrate_text_bases(apr_hash_t **text_bas
             is_revert_base = FALSE;
           }
 
+        if (! versioned_file_name)
+          {
+             /* Some file that doesn't end with .svn-base or .svn-revert.
+                No idea why that would be in our administrative area, but
+                we shouldn't segfault on this case.
+
+                Note that we already copied this file in the pristine store,
+                but the next cleanup will take care of that.
+              */
+            continue;
+          }
+
         /* Create a new info struct for this versioned file, or fill in the
          * existing one if this is the second text-base we've found for it. */
         info = apr_hash_get(*text_bases_info, versioned_file_name,

Modified: subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql Mon Aug 15 12:32:42 2011
@@ -29,7 +29,7 @@
 -- STMT_SELECT_NODE_INFO
 SELECT op_depth, repos_id, repos_path, presence, kind, revision, checksum,
   translated_size, changed_revision, changed_date, changed_author, depth,
-  symlink_target, last_mod_time, properties
+  symlink_target, last_mod_time, properties, moved_here
 FROM nodes
 WHERE wc_id = ?1 AND local_relpath = ?2
 ORDER BY op_depth DESC
@@ -38,7 +38,7 @@ ORDER BY op_depth DESC
 SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision,
   checksum, translated_size, changed_revision, changed_date, changed_author,
   depth, symlink_target, last_mod_time, properties, lock_token, lock_owner,
-  lock_comment, lock_date
+  lock_comment, lock_date, moved_here
 FROM nodes
 LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id
   AND nodes.repos_path = lock.repos_relpath
@@ -603,8 +603,8 @@ WHERE wc_id = ?1
   AND local_relpath = ?2
   AND (changelist IS NULL
        OR NOT EXISTS (SELECT 1 FROM nodes_current c
-                      WHERE c.wc_id = ?1 AND c.local_relpath = local_relpath
-                        AND kind = 'file'))
+                      WHERE c.wc_id = ?1 AND c.local_relpath = ?2
+                        AND c.kind = 'file'))
 
 -- STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE
 DELETE FROM actual_node
@@ -614,8 +614,9 @@ WHERE wc_id = ?1
        OR (local_relpath > ?2 || '/' AND local_relpath < ?2 || '0'))
   AND (changelist IS NULL
        OR NOT EXISTS (SELECT 1 FROM nodes_current c
-                      WHERE c.wc_id = ?1 AND c.local_relpath = local_relpath
-                        AND kind = 'file'))
+                      WHERE c.wc_id = ?1 
+                        AND c.local_relpath = actual_node.local_relpath
+                        AND c.kind = 'file'))
 
 -- STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST
 UPDATE actual_node

Modified: subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c Mon Aug 15 12:32:42 2011
@@ -367,7 +367,7 @@ scan_addition(svn_wc__db_status_t *statu
               apr_int64_t *original_repos_id,
               svn_revnum_t *original_revision,
               const char **moved_from_relpath,
-              const char **delete_op_root_relpath,
+              const char **moved_from_op_root_relpath,
               svn_wc__db_wcroot_t *wcroot,
               const char *local_relpath,
               apr_pool_t *result_pool,
@@ -377,7 +377,7 @@ static svn_error_t *
 scan_deletion(const char **base_del_relpath,
               const char **moved_to_relpath,
               const char **work_del_relpath,
-              const char **copy_op_root_relpath,
+              const char **moved_to_op_root_relpath,
               svn_wc__db_wcroot_t *wcroot,
               const char *local_relpath,
               apr_pool_t *result_pool,
@@ -5159,6 +5159,39 @@ svn_wc__db_op_set_tree_conflict(svn_wc__
 }
 
 
+/* Clear moved-to information at the delete-half of the move which
+ * moved LOCAL_RELPATH here. This transforms the move into a simple delete. */
+static svn_error_t *
+clear_moved_to(const char *local_relpath,
+               svn_wc__db_wcroot_t *wcroot,
+               apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  const char *moved_from_relpath;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_MOVED_FROM_RELPATH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (!have_row)
+    {
+      SVN_ERR(svn_sqlite__reset(stmt));
+      return SVN_NO_ERROR;
+    }
+
+  moved_from_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_CLEAR_MOVED_TO_RELPATH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
+                            moved_from_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  return SVN_NO_ERROR;
+}
+
 /* This implements svn_wc__db_txn_callback_t */
 static svn_error_t *
 op_revert_txn(void *baton,
@@ -5169,6 +5202,7 @@ op_revert_txn(void *baton,
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   apr_int64_t op_depth;
+  svn_boolean_t moved_here;
   int affected_rows;
 
   /* ### Similar structure to op_revert_recursive_txn, should they be
@@ -5214,6 +5248,7 @@ op_revert_txn(void *baton,
     }
 
   op_depth = svn_sqlite__column_int64(stmt, 0);
+  moved_here = svn_sqlite__column_boolean(stmt, 15);
   SVN_ERR(svn_sqlite__reset(stmt));
 
   if (op_depth > 0 && op_depth == relpath_depth(local_relpath))
@@ -5253,6 +5288,9 @@ op_revert_txn(void *baton,
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
 
+      if (moved_here)
+        SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
+
       /* Clear the moved-to path of the BASE node. */
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                         STMT_CLEAR_MOVED_TO_RELPATH));
@@ -5288,6 +5326,7 @@ op_revert_recursive_txn(void *baton,
   svn_boolean_t have_row;
   apr_int64_t op_depth;
   int affected_rows;
+  apr_pool_t *iterpool;
 
   /* ### Similar structure to op_revert_txn, should they be
          combined? */
@@ -5355,6 +5394,25 @@ op_revert_recursive_txn(void *baton,
                             local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_MOVED_HERE_CHILDREN));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  iterpool = svn_pool_create(scratch_pool);
+  while (have_row)
+    {
+      const char *moved_here_child_relpath;
+
+      svn_pool_clear(iterpool);
+
+      moved_here_child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
+      SVN_ERR(clear_moved_to(moved_here_child_relpath, wcroot, iterpool));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  svn_pool_destroy(iterpool);
+
   /* Clear any moved-to paths of the BASE nodes. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_CLEAR_MOVED_TO_RELPATH_RECURSIVE));
@@ -9102,7 +9160,8 @@ svn_wc__db_scan_base_repos(const char **
 /* A helper for scan_addition().
  * Compute moved-from information for the node at LOCAL_RELPATH which
  * has been determined as having been moved-here.
- * Return an appropriate status in *STATUS (usually "moved-here").
+ * If STATUS is not NULL, return an appropriate status in *STATUS (usually
+ * "moved-here").
  * If MOVED_FROM_RELPATH is not NULL, set *MOVED_FROM_RELPATH to the
  * path of the move-source node in *MOVED_FROM_RELPATH.
  * If DELETE_OP_ROOT_RELPATH is not NULL, set *DELETE_OP_ROOT_RELPATH
@@ -9114,8 +9173,8 @@ svn_wc__db_scan_base_repos(const char **
 static svn_error_t *
 get_moved_from_info(svn_wc__db_status_t *status,
                     const char **moved_from_relpath,
-                    const char **delete_op_root_relpath,
-                    const char *copy_op_root_relpath,
+                    const char **moved_from_op_root_relpath,
+                    const char *moved_to_op_root_relpath,
                     svn_wc__db_wcroot_t *wcroot,
                     const char *local_relpath,
                     apr_pool_t *result_pool,
@@ -9127,7 +9186,8 @@ get_moved_from_info(svn_wc__db_status_t 
   /* Run a query to get the moved-from path from the DB. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_MOVED_FROM_RELPATH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, copy_op_root_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                            wcroot->wc_id, moved_to_op_root_relpath));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
   if (!have_row)
@@ -9135,20 +9195,22 @@ get_moved_from_info(svn_wc__db_status_t 
       /* The move was only recorded at the copy-half, possibly because
        * the move operation was interrupted mid-way between the copy
        * and the delete. Treat this node as a normal copy. */
-      *status = svn_wc__db_status_copied;
+      if (status)
+        *status = svn_wc__db_status_copied;
       if (moved_from_relpath)
         *moved_from_relpath = NULL;
-      if (delete_op_root_relpath)
-        *delete_op_root_relpath = NULL;
+      if (moved_from_op_root_relpath)
+        *moved_from_op_root_relpath = NULL;
 
       SVN_ERR(svn_sqlite__reset(stmt));
       return SVN_NO_ERROR;
     }
 
   /* It's a properly recorded move. */
-  *status = svn_wc__db_status_moved_here;
+  if (status)
+    *status = svn_wc__db_status_moved_here;
 
-  if (moved_from_relpath || delete_op_root_relpath)
+  if (moved_from_relpath || moved_from_op_root_relpath)
     {
       const char *db_delete_op_root_relpath;
 
@@ -9156,12 +9218,12 @@ get_moved_from_info(svn_wc__db_status_t 
        * the op_root of the delete-half of the move. */
       db_delete_op_root_relpath = svn_sqlite__column_text(stmt, 0,
                                                           result_pool);
-      if (delete_op_root_relpath)
-        *delete_op_root_relpath = db_delete_op_root_relpath;
+      if (moved_from_op_root_relpath)
+        *moved_from_op_root_relpath = db_delete_op_root_relpath;
 
       if (moved_from_relpath)
         {
-          if (strcmp(copy_op_root_relpath, local_relpath) == 0)
+          if (strcmp(moved_to_op_root_relpath, local_relpath) == 0)
             {
               /* LOCAL_RELPATH is the op_root of the copied-half of the
                * move, so the correct MOVED_FROM_ABSPATH is the op-root
@@ -9176,10 +9238,10 @@ get_moved_from_info(svn_wc__db_status_t 
                * op_root of the copied-half of the move. Construct the
                * corresponding path beneath the op_root of the delete-half. */
 
-              /* Grab the child path relative to the path of the
-               * copied-half's op_root. */
-              child_relpath = svn_relpath_skip_ancestor(copy_op_root_relpath,
-                                                        local_relpath);
+              /* Grab the child path relative to the op_root of the move
+               * destination. */
+              child_relpath = svn_relpath_skip_ancestor(
+                                moved_to_op_root_relpath, local_relpath);
 
               SVN_ERR_ASSERT(child_relpath && strlen(child_relpath) > 0);
 
@@ -9208,7 +9270,7 @@ struct scan_addition_baton_t
   apr_int64_t *original_repos_id;
   svn_revnum_t *original_revision;
   const char **moved_from_relpath;
-  const char **delete_op_root_relpath;
+  const char **moved_from_op_root_relpath;
   apr_pool_t *result_pool;
 };
 
@@ -9236,8 +9298,8 @@ scan_addition_txn(void *baton,
     *sab->original_revision = SVN_INVALID_REVNUM;
   if (sab->moved_from_relpath)
     *sab->moved_from_relpath = NULL;
-  if (sab->delete_op_root_relpath)
-    *sab->delete_op_root_relpath = NULL;
+  if (sab->moved_from_op_root_relpath)
+    *sab->moved_from_op_root_relpath = NULL;
 
   {
     svn_sqlite__stmt_t *stmt;
@@ -9303,11 +9365,16 @@ scan_addition_txn(void *baton,
     if (sab->op_root_relpath)
       *sab->op_root_relpath = apr_pstrdup(sab->result_pool, op_root_relpath);
 
+    /* ### This if-statement is quite redundant.
+     * ### We're checking all these values again within the body anyway.
+     * ### The body should be broken up appropriately and move into the
+     * ### outer scope. */
     if (sab->original_repos_relpath
         || sab->original_repos_id
         || (sab->original_revision
                 && *sab->original_revision == SVN_INVALID_REVNUM)
-        || sab->status)
+        || sab->status
+        || sab->moved_from_relpath || sab->moved_from_op_root_relpath)
       {
         if (local_relpath != op_root_relpath)
           /* requery to get the add/copy root */
@@ -9342,24 +9409,26 @@ scan_addition_txn(void *baton,
 
         if (!svn_sqlite__column_is_null(stmt, 10)
             && (sab->status
-                || sab->original_repos_id))
+                || sab->original_repos_id
+                || sab->moved_from_relpath || sab->moved_from_op_root_relpath))
           /* If column 10 (original_repos_id) is NULL,
              this is a plain add, not a copy or a move */
           {
             if (sab->original_repos_id)
               *sab->original_repos_id = svn_sqlite__column_int64(stmt, 10);
 
-            if (sab->status)
+            if (sab->status ||
+                sab->moved_from_relpath || sab->moved_from_op_root_relpath)
               {
                 if (svn_sqlite__column_boolean(stmt, 13 /* moved_here */))
                   SVN_ERR(get_moved_from_info(sab->status,
                                               sab->moved_from_relpath,
-                                              sab->delete_op_root_relpath,
+                                              sab->moved_from_op_root_relpath,
                                               op_root_relpath, wcroot,
                                               local_relpath,
                                               sab->result_pool,
                                               scratch_pool));
-                else
+                else if (sab->status)
                   *sab->status = svn_wc__db_status_copied;
               }
           }
@@ -9475,7 +9544,7 @@ scan_addition(svn_wc__db_status_t *statu
               apr_int64_t *original_repos_id,
               svn_revnum_t *original_revision,
               const char **moved_from_relpath,
-              const char **delete_op_root_relpath,
+              const char **moved_from_op_root_relpath,
               svn_wc__db_wcroot_t *wcroot,
               const char *local_relpath,
               apr_pool_t *result_pool,
@@ -9491,7 +9560,7 @@ scan_addition(svn_wc__db_status_t *statu
   sab.original_repos_id = original_repos_id;
   sab.original_revision = original_revision;
   sab.moved_from_relpath = moved_from_relpath;
-  sab.delete_op_root_relpath = delete_op_root_relpath;
+  sab.moved_from_op_root_relpath = moved_from_op_root_relpath;
   sab.result_pool = result_pool;
 
   return svn_error_trace(svn_wc__db_with_txn(wcroot, local_relpath,
@@ -9511,7 +9580,7 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                          const char **original_uuid,
                          svn_revnum_t *original_revision,
                          const char **moved_from_abspath,
-                         const char **delete_op_root_abspath,
+                         const char **moved_from_op_root_abspath,
                          svn_wc__db_t *db,
                          const char *local_abspath,
                          apr_pool_t *result_pool,
@@ -9527,7 +9596,7 @@ svn_wc__db_scan_addition(svn_wc__db_stat
   apr_int64_t *original_repos_id_p
     = (original_root_url || original_uuid) ? &original_repos_id : NULL;
   const char *moved_from_relpath;
-  const char *delete_op_root_relpath;
+  const char *moved_from_op_root_relpath;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -9538,7 +9607,7 @@ svn_wc__db_scan_addition(svn_wc__db_stat
   SVN_ERR(scan_addition(status, &op_root_relpath, repos_relpath, repos_id_p,
                         original_repos_relpath, original_repos_id_p,
                         original_revision, &moved_from_relpath,
-                        &delete_op_root_relpath, wcroot, local_relpath,
+                        &moved_from_op_root_relpath, wcroot, local_relpath,
                         result_pool, scratch_pool));
 
   if (op_root_abspath)
@@ -9553,14 +9622,27 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                            wcroot->sdb, original_repos_id,
                            result_pool));
 
-  if (moved_from_abspath && moved_from_relpath)
-    *moved_from_abspath = svn_dirent_join(wcroot->abspath,
-                                          moved_from_relpath,
-                                          result_pool);
-  if (delete_op_root_abspath && delete_op_root_relpath)
-    *delete_op_root_abspath = svn_dirent_join(wcroot->abspath,
-                                              delete_op_root_relpath,
+  if (moved_from_abspath)
+    {
+      if (moved_from_relpath)
+        *moved_from_abspath = svn_dirent_join(wcroot->abspath,
+                                              moved_from_relpath,
                                               result_pool);
+      else
+        *moved_from_abspath = NULL;
+    }
+
+  if (moved_from_op_root_abspath)
+    {
+      if (moved_from_op_root_relpath)
+        *moved_from_op_root_abspath =
+          svn_dirent_join(wcroot->abspath,
+                          moved_from_op_root_relpath,
+                          result_pool);
+      else
+        *moved_from_op_root_abspath = NULL;
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -9570,7 +9652,7 @@ struct scan_deletion_baton_t
   const char **base_del_relpath;
   const char **moved_to_relpath;
   const char **work_del_relpath;
-  const char **copy_op_root_relpath;
+  const char **moved_to_op_root_relpath;
   apr_pool_t *result_pool;
 };
 
@@ -9595,8 +9677,8 @@ scan_deletion_txn(void *baton,
     *sd_baton->moved_to_relpath = NULL;
   if (sd_baton->work_del_relpath != NULL)
     *sd_baton->work_del_relpath = NULL;
-  if (sd_baton->copy_op_root_relpath != NULL)
-    *sd_baton->copy_op_root_relpath = NULL;
+  if (sd_baton->moved_to_op_root_relpath != NULL)
+    *sd_baton->moved_to_op_root_relpath = NULL;
 
   /* Initialize to something that won't denote an important parent/child
      transition.  */
@@ -9714,15 +9796,15 @@ scan_deletion_txn(void *baton,
         }
 
       if ((sd_baton->moved_to_relpath != NULL
-                || sd_baton->copy_op_root_relpath != NULL
+                || sd_baton->moved_to_op_root_relpath != NULL
                 || sd_baton->base_del_relpath != NULL)
           && !svn_sqlite__column_is_null(stmt, 2 /* moved_to */))
         {
-          const char *copy_op_root_relpath;
+          const char *moved_to_op_root_relpath;
           const char *moved_to_relpath;
 
-          copy_op_root_relpath = svn_sqlite__column_text(stmt, 2,
-                                                         scratch_pool);
+          moved_to_op_root_relpath = svn_sqlite__column_text(stmt, 2,
+                                                             scratch_pool);
           if (current_relpath == local_relpath)
             {
               /* The starting node is the op_root of the delete-half of
@@ -9731,7 +9813,7 @@ scan_deletion_txn(void *baton,
                * is kept up-to-date if a node is moved multiple times. */
               if (sd_baton->moved_to_relpath)
                 *sd_baton->moved_to_relpath =
-                  apr_pstrdup(sd_baton->result_pool, copy_op_root_relpath);
+                  apr_pstrdup(sd_baton->result_pool, moved_to_op_root_relpath);
             }
           else
             {
@@ -9747,7 +9829,7 @@ scan_deletion_txn(void *baton,
                                                               local_relpath);
               SVN_ERR_ASSERT(moved_child_relpath &&
                              strlen(moved_child_relpath) > 0);
-              moved_to_relpath = svn_relpath_join(copy_op_root_relpath,
+              moved_to_relpath = svn_relpath_join(moved_to_op_root_relpath,
                                                   moved_child_relpath,
                                                   scratch_pool);
               
@@ -9771,7 +9853,7 @@ scan_deletion_txn(void *baton,
                        * Just treat this as a normal deletion. */
                       svn_error_clear(err); 
                       moved_to_relpath = NULL;
-                      copy_op_root_relpath = NULL;
+                      moved_to_op_root_relpath = NULL;
                       found_child = FALSE;
                     }
                   else
@@ -9802,10 +9884,10 @@ scan_deletion_txn(void *baton,
             *sd_baton->base_del_relpath =
               apr_pstrdup(sd_baton->result_pool, current_relpath);
 
-          /* The copy_op_root_relpath is the moved-to relpath from the DB. */
-          if (sd_baton->copy_op_root_relpath)
-            *sd_baton->copy_op_root_relpath = copy_op_root_relpath ?
-              apr_pstrdup(sd_baton->result_pool, copy_op_root_relpath) : NULL;
+          if (sd_baton->moved_to_op_root_relpath)
+            *sd_baton->moved_to_op_root_relpath = moved_to_op_root_relpath ?
+              apr_pstrdup(sd_baton->result_pool, moved_to_op_root_relpath)
+              : NULL;
         }
 
       op_depth = svn_sqlite__column_int64(stmt, 3);
@@ -9846,7 +9928,7 @@ static svn_error_t *
 scan_deletion(const char **base_del_relpath,
               const char **moved_to_relpath,
               const char **work_del_relpath,
-              const char **copy_op_root_relpath,
+              const char **moved_to_op_root_relpath,
               svn_wc__db_wcroot_t *wcroot,
               const char *local_relpath,
               apr_pool_t *result_pool,
@@ -9857,7 +9939,7 @@ scan_deletion(const char **base_del_relp
   sd_baton.base_del_relpath = base_del_relpath;
   sd_baton.work_del_relpath = work_del_relpath;
   sd_baton.moved_to_relpath = moved_to_relpath;
-  sd_baton.copy_op_root_relpath = copy_op_root_relpath;
+  sd_baton.moved_to_op_root_relpath = moved_to_op_root_relpath;
   sd_baton.result_pool = result_pool;
 
   return svn_error_trace(svn_wc__db_with_txn(wcroot, local_relpath,
@@ -9870,7 +9952,7 @@ svn_error_t *
 svn_wc__db_scan_deletion(const char **base_del_abspath,
                          const char **moved_to_abspath,
                          const char **work_del_abspath,
-                         const char **copy_op_root_abspath,
+                         const char **moved_to_op_root_abspath,
                          svn_wc__db_t *db,
                          const char *local_abspath,
                          apr_pool_t *result_pool,
@@ -9879,7 +9961,7 @@ svn_wc__db_scan_deletion(const char **ba
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
   const char *base_del_relpath, *moved_to_relpath, *work_del_relpath;
-  const char *copy_op_root_relpath;
+  const char *moved_to_op_root_relpath;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -9888,7 +9970,7 @@ svn_wc__db_scan_deletion(const char **ba
   VERIFY_USABLE_WCROOT(wcroot);
 
   SVN_ERR(scan_deletion(&base_del_relpath, &moved_to_relpath,
-                        &work_del_relpath, &copy_op_root_relpath, wcroot,
+                        &work_del_relpath, &moved_to_op_root_relpath, wcroot,
                         local_relpath, scratch_pool, scratch_pool));
 
   if (base_del_abspath)
@@ -9912,11 +9994,12 @@ svn_wc__db_scan_deletion(const char **ba
                                              work_del_relpath, result_pool)
                            : NULL);
     }
-  if (copy_op_root_abspath)
+  if (moved_to_op_root_abspath)
     {
-      *copy_op_root_abspath = (copy_op_root_relpath
+      *moved_to_op_root_abspath = (moved_to_op_root_relpath
                            ? svn_dirent_join(wcroot->abspath,
-                                             copy_op_root_relpath, result_pool)
+                                             moved_to_op_root_relpath,
+                                             result_pool)
                            : NULL);
     }
 

Modified: subversion/branches/fs-py/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/wc_db.h?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/wc_db.h Mon Aug 15 12:32:42 2011
@@ -338,7 +338,7 @@ svn_wc__db_init(svn_wc__db_t *db,
    be returned.
 
    The LOCAL_RELPATH should ONLY be used for persisting paths to disk.
-   Those patsh should not be an abspath, otherwise the working copy cannot
+   Those paths should not be abspaths, otherwise the working copy cannot
    be moved. The working copy library should not make these paths visible
    in its API (which should all be abspaths), and it should not be using
    relpaths for other processing.
@@ -2419,8 +2419,9 @@ svn_wc__db_scan_base_repos(const char **
        Additionally, information about the local move source is provided.
        If MOVED_FROM_ABSPATH is not NULL, set *MOVED_FROM_ABSPATH to the
        absolute path of the move source node in the working copy.
-       If DELETE_OP_ROOT_ABSPATH is not NULL, set *DELETE_OP_ROOT_ABSPATH
-       to the absolute path of the op-root of the delete-half of the move.
+       If MOVED_FROM_OP_ROOT_ABSPATH is not NULL, set
+       *MOVED_FROM_OP_ROOT_ABSPATH to the absolute path of the op-root of the
+       delete-half of the move.
 
    All OUT parameters may be NULL to indicate a lack of interest in
    that piece of information.
@@ -2452,7 +2453,7 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                          const char **original_uuid,
                          svn_revnum_t *original_revision,
                          const char **moved_from_abspath,
-                         const char **delete_op_root_abspath,
+                         const char **moved_from_oproot_abspath,
                          svn_wc__db_t *db,
                          const char *local_abspath,
                          apr_pool_t *result_pool,
@@ -2543,9 +2544,9 @@ svn_wc__db_scan_addition(svn_wc__db_stat
    MOVED_TO_ABSPATH will specify the path where this node was moved to
    if the node has moved-away.
 
-   If the node was moved-away, COPY_OP_ROOT_ABSPATH will specify the root
-   of the copy operation that created the copy-half of the move. 
-   If LOCAL_ABSPATH itself is the root of the copy, COPY_OP_ROOT_ABSPATH
+   If the node was moved-away, MOVED_TO_OP_ROOT_ABSPATH will specify the root
+   of the copy operation that created the move destination.
+   If LOCAL_ABSPATH itself is the root of the copy, MOVED_TO_OP_ROOT_ABSPATH
    equals MOVED_TO_ABSPATH.
 
    All OUT parameters may be set to NULL to indicate a lack of interest in
@@ -2562,7 +2563,7 @@ svn_error_t *
 svn_wc__db_scan_deletion(const char **base_del_abspath,
                          const char **moved_to_abspath,
                          const char **work_del_abspath,
-                         const char **copy_op_root_abspath,
+                         const char **moved_to_op_root_abspath,
                          svn_wc__db_t *db,
                          const char *local_abspath,
                          apr_pool_t *result_pool,

Modified: subversion/branches/fs-py/subversion/svn/info-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/info-cmd.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/info-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/info-cmd.c Mon Aug 15 12:32:42 2011
@@ -172,6 +172,35 @@ print_info_xml(void *baton,
         svn_cl__xml_tagged_cdata(&sb, pool, "changelist",
                                  info->wc_info->changelist);
 
+      if (info->wc_info->moved_from_abspath)
+        {
+          const char *relpath;
+
+          relpath = svn_dirent_skip_ancestor(info->wc_info->wcroot_abspath,
+                                             info->wc_info->moved_from_abspath);
+
+          /* <moved-from> xx </moved-from> */
+          if (relpath && relpath[0] != '\0')
+            svn_cl__xml_tagged_cdata(&sb, pool, "moved-from", relpath);
+          else
+            svn_cl__xml_tagged_cdata(&sb, pool, "moved-from",
+                                     info->wc_info->moved_from_abspath);
+        }
+
+      if (info->wc_info->moved_to_abspath)
+        {
+          const char *relpath;
+
+          relpath = svn_dirent_skip_ancestor(info->wc_info->wcroot_abspath,
+                                             info->wc_info->moved_to_abspath);
+          /* <moved-to> xx </moved-to> */
+          if (relpath && relpath[0] != '\0')
+            svn_cl__xml_tagged_cdata(&sb, pool, "moved-to", relpath);
+          else
+            svn_cl__xml_tagged_cdata(&sb, pool, "moved-to",
+                                     info->wc_info->moved_to_abspath);
+        }
+
       /* "</wc-info>" */
       svn_xml_make_close_tag(&sb, pool, "wc-info");
     }
@@ -376,6 +405,31 @@ print_info(void *baton,
       if (SVN_IS_VALID_REVNUM(info->wc_info->copyfrom_rev))
         SVN_ERR(svn_cmdline_printf(pool, _("Copied From Rev: %ld\n"),
                                    info->wc_info->copyfrom_rev));
+      if (info->wc_info->moved_from_abspath)
+        {
+          const char *relpath;
+
+          relpath = svn_dirent_skip_ancestor(info->wc_info->wcroot_abspath,
+                                             info->wc_info->moved_from_abspath);
+          if (relpath && relpath[0] != '\0')
+            SVN_ERR(svn_cmdline_printf(pool, _("Moved From: %s\n"), relpath));
+          else
+            SVN_ERR(svn_cmdline_printf(pool, _("Moved From: %s\n"),
+                                       info->wc_info->moved_from_abspath));
+        }
+
+      if (info->wc_info->moved_to_abspath)
+        {
+          const char *relpath;
+
+          relpath = svn_dirent_skip_ancestor(info->wc_info->wcroot_abspath,
+                                             info->wc_info->moved_to_abspath);
+          if (relpath && relpath[0] != '\0')
+            SVN_ERR(svn_cmdline_printf(pool, _("Moved To: %s\n"), relpath));
+          else
+            SVN_ERR(svn_cmdline_printf(pool, _("Moved To: %s\n"),
+                                       info->wc_info->moved_to_abspath));
+        }
     }
 
   if (info->last_changed_author)

Modified: subversion/branches/fs-py/subversion/svn/schema/info.rnc
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/schema/info.rnc?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/schema/info.rnc (original)
+++ subversion/branches/fs-py/subversion/svn/schema/info.rnc Mon Aug 15 12:32:42 2011
@@ -61,7 +61,9 @@ wc-info =
     depth?,
     text-updated?,
     prop-updated?,
-    checksum?
+    checksum?,
+    moved-from?,
+    moved-to?
   }
 
 wcroot-abspath = element wcroot-abspath { string }
@@ -84,6 +86,10 @@ prop-updated = element prop-updated { xs
 
 checksum = element checksum { md5sum.type }
 
+moved-from = element moved-from { string }
+
+moved-to = element moved-to { string }
+
 conflict =
   element conflict {
     prev-base-file,

Modified: subversion/branches/fs-py/subversion/svn/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/status.c?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/status.c (original)
+++ subversion/branches/fs-py/subversion/svn/status.c Mon Aug 15 12:32:42 2011
@@ -124,6 +124,54 @@ generate_status_desc(enum svn_wc_status_
     }
 }
 
+/* Make a relative path containing '..' elements as needed.
+   RELATIVE_TO_PATH must be the path to a directory (not a file!) and
+   TARGET_PATH must be the path to any file or directory. Both
+   RELATIVE_TO_PATH and TARGET_PATH must be based on the same parent path,
+   i.e. they can either both be absolute or they can both be relative to the
+   same parent directory. Both paths are expected to be canonical.
+   
+   If above conditions are met, a relative path that leads to TARGET_ABSPATH
+   from RELATIVE_TO_PATH is returned, but there is no error checking involved.
+   
+   The returned path is allocated from RESULT_POOL, all other allocations are
+   made in SCRATCH_POOL. */
+static const char *
+make_relpath(const char *relative_to_path,
+             const char *target_path,
+             apr_pool_t *result_pool,
+             apr_pool_t *scratch_pool)
+{
+  const char *la;
+  const char *parent_dir_els = "";
+
+  /* An example:
+   *  relative_to_path = /a/b/c
+   *  target_path      = /a/x/y/z
+   *  result           = ../../x/y/z */
+
+  /* Skip the common ancestor of both paths, here '/a'. */
+  la = svn_dirent_get_longest_ancestor(relative_to_path, target_path,
+                                       scratch_pool);
+  relative_to_path = svn_dirent_skip_ancestor(la, relative_to_path);
+  target_path = svn_dirent_skip_ancestor(la, target_path);
+
+  /* In above example, we'd now have:
+   *  relative_to_path = b/c
+   *  target_path      = x/y/z */
+
+  /* Count the elements of relative_to_path and prepend as many '..' elements
+   * to target_path. */
+  while (*relative_to_path)
+    {
+      svn_dirent_split(&relative_to_path, NULL, relative_to_path,
+                       scratch_pool);
+      parent_dir_els = svn_dirent_join(parent_dir_els, "..", scratch_pool);
+    }
+
+  return svn_dirent_join(parent_dir_els, target_path, result_pool);
+}
+
 
 /* Print STATUS and PATH in a format determined by DETAILED and
    SHOW_LAST_COMMITTED. */
@@ -143,6 +191,8 @@ print_status(const char *path,
   enum svn_wc_status_kind prop_status = status->prop_status;
   char tree_status_code = ' ';
   const char *tree_desc_line = "";
+  const char *moved_from_line = "";
+  const char *moved_to_line = "";
 
   /* For historic reasons svn ignores the property status for added nodes, even
      if these nodes were copied and have local property changes.
@@ -211,6 +261,40 @@ print_status(const char *path,
         (*prop_conflicts)++;
     }
 
+  if (status->moved_from_abspath)
+    {
+      const char *cwd;
+      const char *relpath;
+      SVN_ERR(svn_dirent_get_absolute(&cwd, "", pool));
+      relpath = make_relpath(cwd, status->moved_from_abspath, pool, pool);
+      relpath = svn_dirent_local_style(relpath, pool);
+      moved_from_line = apr_psprintf(pool,
+                                     apr_psprintf(pool,
+                                                  "\n        > %s",
+                                                  _("moved from %s")),
+                                     relpath);
+    }
+
+  /* Only print an extra moved-to line for the op-root of a move-away.
+   * As each and every child node of a deleted tree is printed in status
+   * output, each of them would be "duplicated" with a moved-to line. */
+  if (status->moved_to_abspath
+      && status->moved_to_op_root_abspath
+      && 0 == strcmp(status->moved_to_op_root_abspath,
+                     status->moved_to_abspath))
+    {
+      const char *cwd;
+      const char *relpath;
+      SVN_ERR(svn_dirent_get_absolute(&cwd, "", pool));
+      relpath = make_relpath(cwd, status->moved_to_abspath, pool, pool);
+      relpath = svn_dirent_local_style(relpath, pool);
+      moved_to_line = apr_psprintf(pool,
+                                   apr_psprintf(pool,
+                                                "\n        > %s",
+                                                _("moved to %s")),
+                                   relpath);
+    }
+
   if (detailed)
     {
       char ood_status, lock_status;
@@ -273,7 +357,7 @@ print_status(const char *path,
 
           SVN_ERR
             (svn_cmdline_printf(pool,
-                                "%c%c%c%c%c%c%c %c   %6s   %6s %-12s %s%s\n",
+                                "%c%c%c%c%c%c%c %c   %6s   %6s %-12s %s%s%s%s\n",
                                 generate_status_code(combined_status(status)),
                                 generate_status_code(prop_status),
                                 status->wc_is_locked ? 'L' : ' ',
@@ -286,11 +370,13 @@ print_status(const char *path,
                                 commit_rev,
                                 commit_author,
                                 path,
+                                moved_to_line,
+                                moved_from_line,
                                 tree_desc_line));
         }
       else
         SVN_ERR(
-           svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %c   %6s   %s%s\n",
+           svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %c   %6s   %s%s%s%s\n",
                               generate_status_code(combined_status(status)),
                               generate_status_code(prop_status),
                               status->wc_is_locked ? 'L' : ' ',
@@ -301,11 +387,13 @@ print_status(const char *path,
                               ood_status,
                               working_rev,
                               path,
+                              moved_to_line,
+                              moved_from_line,
                               tree_desc_line));
     }
   else
     SVN_ERR(
-       svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %s%s\n",
+       svn_cmdline_printf(pool, "%c%c%c%c%c%c%c %s%s%s%s\n",
                           generate_status_code(combined_status(status)),
                           generate_status_code(prop_status),
                           status->wc_is_locked ? 'L' : ' ',
@@ -315,6 +403,8 @@ print_status(const char *path,
                            ? 'K' : ' '),
                           tree_status_code,
                           path,
+                          moved_to_line,
+                          moved_from_line,
                           tree_desc_line));
 
   return svn_cmdline_fflush(stdout);

Modified: subversion/branches/fs-py/subversion/tests/cmdline/changelist_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/changelist_tests.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/changelist_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/changelist_tests.py Mon Aug 15 12:32:42 2011
@@ -1170,6 +1170,26 @@ def add_remove_unversioned_target(sbox):
                                      'changelist', unversioned,
                                       '--remove')
 
+@Issue(3985)
+def readd_after_revert(sbox):
+  "add new file to changelist, revert and readd"
+  sbox.build(read_only = True)
+
+  dummy = sbox.ospath('dummy')
+  svntest.main.file_write(dummy, "dummy contents")
+
+  sbox.simple_add('dummy')
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'changelist', 'testlist',
+                                     dummy)
+
+  sbox.simple_revert('dummy')
+
+  svntest.main.file_write(dummy, "dummy contents")
+
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'add', dummy)
+
 
 ########################################################################
 # Run the tests
@@ -1192,6 +1212,7 @@ test_list = [ None,
               revert_deleted_in_changelist,
               add_remove_non_existent_target,
               add_remove_unversioned_target,
+              readd_after_revert,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/copy_tests.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/copy_tests.py Mon Aug 15 12:32:42 2011
@@ -5477,30 +5477,23 @@ def commit_copied_half_of_move(sbox):
   sbox.build(read_only = True)
   wc_dir = sbox.wc_dir
 
-  iota_path = os.path.join(wc_dir, 'iota')
-  D_path = os.path.join(wc_dir, 'A', 'D')
-
-  svntest.actions.run_and_verify_svn(None, None, [], 'mv', iota_path, D_path)
-
-  expected_error = "svn: E200009: Cannot commit"
-  svntest.actions.run_and_verify_svn(None, None, expected_error,
-                                     'commit', '-m', 'foo', D_path)
-
-@Issue(3631)
-def commit_copied_half_of_nested_move(sbox):
-  "attempt to commit the copied part of a nested move"
-  sbox.build(read_only = True)
-  wc_dir = sbox.wc_dir
-
   iota_path = sbox.ospath('iota')
   D_path = sbox.ospath('A/D')
 
-  # iota -> A/D/iota; verify we cannot commit just A/D
+  # iota -> A/D/iota; verify we cannot commit just A/D/iota
   svntest.actions.run_and_verify_svn(None, None, [], 'mv', iota_path, D_path)
   expected_error = "svn: E200009: Cannot commit '.*%s' because it was " \
                     "moved from '.*%s'" % (re.escape(sbox.ospath('A/D/iota')),
                                            re.escape(iota_path))
   svntest.actions.run_and_verify_svn(None, None, expected_error,
+                                     'commit', '-m', 'foo',
+                                     os.path.join(D_path, 'iota'))
+
+  # verify we cannot commit just A/D
+  expected_error = "svn: E200009: Cannot commit '.*%s' because it was " \
+                    "moved from '.*%s'" % (re.escape(sbox.ospath('A/D/iota')),
+                                           re.escape(iota_path))
+  svntest.actions.run_and_verify_svn(None, None, expected_error,
                                      'commit', '-m', 'foo', D_path)
 
   # A/D -> A/C/D; verify we cannot commit just A/C
@@ -5531,15 +5524,28 @@ def commit_deleted_half_of_move(sbox):
   sbox.build(read_only = True)
   wc_dir = sbox.wc_dir
 
-  iota_path = os.path.join(wc_dir, 'iota')
-  D_path = os.path.join(wc_dir, 'A', 'D')
+  iota_path = sbox.ospath('iota')
+  A_path = sbox.ospath('A')
+  D_path = sbox.ospath('A/D')
 
+  # iota -> A/D/iota; verify we cannot commit just iota
   svntest.actions.run_and_verify_svn(None, None, [], 'mv', iota_path, D_path)
 
-  expected_error = "svn: E200009: Cannot commit"
+  expected_error = "svn: E200009: Cannot commit '.*%s' because it was moved " \
+                    "to '.*%s'" % (re.escape(iota_path),
+                                   re.escape(os.path.join(D_path, "iota")))
   svntest.actions.run_and_verify_svn(None, None, expected_error,
                                      'commit', '-m', 'foo', iota_path)
 
+  # A/D -> C; verify we cannot commit just A
+  C_path = sbox.ospath('C')
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'mv', D_path, C_path)
+  expected_error = "svn: E200009: Cannot commit '.*%s' because it was moved " \
+                    "to '.*%s'" % (re.escape(D_path), re.escape(C_path))
+  svntest.actions.run_and_verify_svn(None, None, expected_error,
+                                     'commit', '-m', 'foo', A_path)
+
 ########################################################################
 # Run the tests
 
@@ -5651,7 +5657,6 @@ test_list = [ None,
               copy_and_move_conflicts,
               copy_deleted_dir,
               commit_copied_half_of_move,
-              commit_copied_half_of_nested_move,
               commit_deleted_half_of_move,
              ]
 

Modified: subversion/branches/fs-py/subversion/tests/cmdline/import_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/import_tests.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/import_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/import_tests.py Mon Aug 15 12:32:42 2011
@@ -370,6 +370,21 @@ enable-auto-props = yes
                                      '--config-dir', config_dir)
 
 #----------------------------------------------------------------------
+@Issue(3983)
+def import_into_foreign_repo(sbox):
+  "import into a foreign repo"
+
+  sbox.build(read_only=True)
+
+  other_repo_dir, other_repo_url = sbox.add_repo_path('other')
+  svntest.main.safe_rmtree(other_repo_dir, 1)
+  svntest.main.create_repos(other_repo_dir)
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'import',
+                                     '-m', 'Log message for new import',
+                                     sbox.ospath('A/mu'), other_repo_url + '/f')
+
+#----------------------------------------------------------------------
 ########################################################################
 # Run the tests
 
@@ -381,6 +396,7 @@ test_list = [ None,
               import_avoid_empty_revision,
               import_no_ignores,
               import_eol_style,
+              import_into_foreign_repo,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/lock_tests.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/lock_tests.py Mon Aug 15 12:32:42 2011
@@ -1499,9 +1499,9 @@ def lock_path_not_in_head(sbox):
   svntest.actions.run_and_verify_svn(None, None, [], 'commit',
                                      '-m', 'Some deletions', wc_dir)
   svntest.actions.run_and_verify_svn(None, None, [], 'up', '-r1', wc_dir)
-  expected_lock_fail_err_re = "svn:.*" \
+  expected_lock_fail_err_re = "svn: warning: W160042: " \
   "((Path .* doesn't exist in HEAD revision)" \
-  "|(Lock request failed: 405 Method Not Allowed))"
+  "|(L(ock|OCK) request (on '.*' )?failed: 405 Method Not Allowed))"
   # Issue #3524 These lock attemtps were triggering an assert over ra_serf:
   #
   # working_copies\lock_tests-37>svn lock A\D

Modified: subversion/branches/fs-py/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/merge_tests.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/merge_tests.py Mon Aug 15 12:32:42 2011
@@ -16838,6 +16838,140 @@ def merge_adds_subtree_with_mergeinfo(sb
                                        None, None, None, None,
                                        None, 1, False)
 
+#----------------------------------------------------------------------
+# A test for issue #3978 'reverse merge which adds subtree fails'.
+@Issue(3978)
+@SkipUnless(server_has_mergeinfo)
+def reverse_merge_adds_subtree(sbox):
+  "reverse merge adds subtree"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  wc_disk, wc_status = set_up_branch(sbox)
+
+  A_path       = os.path.join(wc_dir, 'A')
+  chi_path     = os.path.join(wc_dir, 'A', 'D', 'H', 'chi')
+  A_COPY_path  = os.path.join(wc_dir, 'A_COPY')
+  H_COPY_path  = os.path.join(wc_dir, 'A_COPY', 'D', 'H')
+
+  # r7 - Delete A\D\H\chi
+  svntest.actions.run_and_verify_svn(None, None, [], 'delete', chi_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Delete a file', wc_dir)
+
+  # r8 - Merge r7 from A to A_COPY
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A',
+                                     A_COPY_path, '-c7')
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Cherry-pick r7 from A to A_COPY', wc_dir)
+
+  # r9 - File depth sync merge from A/D/H to A_COPY/D/H/
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A/D/H',
+                                     H_COPY_path, '--depth', 'files')
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Cherry-pick r7 from A to A_COPY', wc_dir)
+
+  # Reverse merge r7 from A to A_COPY
+  #
+  # Prior to the issue #3978 fix this merge failed with an assertion:
+  #
+  # >svn merge ^/A A_COPY -c-7
+  # --- Reverse-merging r7 into 'A_COPY\D\H':
+  # A    A_COPY\D\H\chi
+  # --- Recording mergeinfo for reverse merge of r7 into 'A_COPY':
+  #  U   A_COPY
+  # --- Recording mergeinfo for reverse merge of r7 into 'A_COPY\D\H':
+  #  U   A_COPY\D\H
+  # ..\..\..\subversion\svn\util.c:913: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_client\merge.c:10990: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_client\merge.c:10944: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_client\merge.c:10944: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_client\merge.c:10914: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_client\merge.c:8928: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_client\merge.c:7850: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_client\mergeinfo.c:120: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_wc\props.c:2472: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_wc\props.c:2247: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_wc\props.c:2576: (apr_err=200020)
+  # ..\..\..\subversion\libsvn_subr\mergeinfo.c:705: (apr_err=200020)
+  # svn: E200020: Could not parse mergeinfo string '-7'
+  # ..\..\..\subversion\libsvn_subr\mergeinfo.c:688: (apr_err=200022)
+  # ..\..\..\subversion\libsvn_subr\mergeinfo.c:607: (apr_err=200022)
+  # ..\..\..\subversion\libsvn_subr\mergeinfo.c:504: (apr_err=200022)
+  # ..\..\..\subversion\libsvn_subr\kitchensink.c:57: (apr_err=200022)
+  # svn: E200022: Negative revision number found parsing '-7'
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  expected_output = wc.State(A_COPY_path, {
+    'D/H/chi' : Item(status='A '),
+    })
+  expected_mergeinfo_output = wc.State(A_COPY_path, {
+    ''    : Item(status=' U'),
+    'D/H' : Item(status=' U'),
+    })
+  expected_elision_output = wc.State(A_COPY_path, {
+    '' : Item(status=' U'),
+    })
+  expected_status = wc.State(A_COPY_path, {
+    ''          : Item(status=' M'),
+    'B'         : Item(status='  '),
+    'mu'        : Item(status='  '),
+    'B/E'       : Item(status='  '),
+    'B/E/alpha' : Item(status='  '),
+    'B/E/beta'  : Item(status='  '),
+    'B/lambda'  : Item(status='  '),
+    'B/F'       : Item(status='  '),
+    'C'         : Item(status='  '),
+    'D'         : Item(status='  '),
+    'D/G'       : Item(status='  '),
+    'D/G/pi'    : Item(status='  '),
+    'D/G/rho'   : Item(status='  '),
+    'D/G/tau'   : Item(status='  '),
+    'D/gamma'   : Item(status='  '),
+    'D/H'       : Item(status=' M'),
+    'D/H/chi'   : Item(status='A ', copied='+'),
+    'D/H/psi'   : Item(status='  '),
+    'D/H/omega' : Item(status='  '),
+    })
+  expected_status.tweak(wc_rev=9)
+  expected_status.tweak('D/H/chi', wc_rev='-')
+  expected_disk = wc.State('', {
+    'B'         : Item(),
+    'mu'        : Item("This is the file 'mu'.\n"),
+    'B/E'       : Item(),
+    'B/E/alpha' : Item("This is the file 'alpha'.\n"),
+    'B/E/beta'  : Item("This is the file 'beta'.\n"),
+    'B/lambda'  : Item("This is the file 'lambda'.\n"),
+    'B/F'       : Item(),
+    'C'         : Item(),
+    'D'         : Item(),
+    'D/G'       : Item(),
+    'D/G/pi'    : Item("This is the file 'pi'.\n"),
+    'D/G/rho'   : Item("This is the file 'rho'.\n"),
+    'D/G/tau'   : Item("This is the file 'tau'.\n"),
+    'D/gamma'   : Item("This is the file 'gamma'.\n"),
+    'D/H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:2-6*,8*'}),
+    'D/H/chi'   : Item("This is the file 'chi'.\n"),
+    'D/H/psi'   : Item("New content",
+                       props={SVN_PROP_MERGEINFO : '/A/D/H/psi:2-8'}),
+    'D/H/omega' : Item("New content",
+                       props={SVN_PROP_MERGEINFO : '/A/D/H/omega:2-8'}),
+    })
+  expected_skip = wc.State('.', { })
+  svntest.actions.run_and_verify_merge(A_COPY_path, 7, 6,
+                                       sbox.repo_url + '/A', None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, None, None, None,
+                                       None, 1, False)
+
 ########################################################################
 # Run the tests
 
@@ -16963,6 +17097,7 @@ test_list = [ None,
               dry_run_merge_conflicting_binary,
               foreign_repos_prop_conflict,
               merge_adds_subtree_with_mergeinfo,
+              reverse_merge_adds_subtree,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/mergeinfo_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/mergeinfo_tests.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/mergeinfo_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/mergeinfo_tests.py Mon Aug 15 12:32:42 2011
@@ -489,6 +489,141 @@ def mergeinfo_on_pegged_wc_path(sbox):
     adjust_error_for_server_version(''),
     ['4', '5'], A_path, A_COPY_path + '@PREV', '--show-revs', 'eligible')
 
+#----------------------------------------------------------------------
+# A test for issue 3986 'svn_client_mergeinfo_log API is broken'.
+@Issue(3986)
+@SkipUnless(server_has_mergeinfo)
+def wc_target_inherits_mergeinfo_from_repos(sbox):
+  "wc target inherits mergeinfo from repos"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  wc_disk, wc_status = set_up_branch(sbox, nbr_of_branches=2)
+
+  A_COPY_path   = os.path.join(wc_dir, 'A_COPY')
+  rho_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D', 'G', 'rho')
+  gamma_2_path  = os.path.join(wc_dir, 'A_COPY_2', 'D', 'gamma')
+  tau_path      = os.path.join(wc_dir, 'A', 'D', 'G', 'tau')
+  D_COPY_path   = os.path.join(wc_dir, 'A_COPY', 'D')
+  
+  # Merge -c5 ^/A/D/G/rho A_COPY\D\G\rho
+  # Merge -c7 ^/A A_COPY
+  # Commit as r8
+  #
+  # This gives us some explicit mergeinfo on the "branch" root and
+  # one of its subtrees:
+  #
+  #   Properties on 'A_COPY\D\G\rho':
+  #     svn:mergeinfo
+  #       /A/D/G/rho:5
+  #   Properties on 'A_COPY':
+  #     svn:mergeinfo
+  #       /A:7
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A/D/G/rho',
+                                     rho_COPY_path, '-c5')
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A',
+                                     A_COPY_path, '-c7')
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Cherrypicks to branch subtree and root',
+                                     wc_dir)
+
+  # Checkout a new wc rooted at ^/A_COPY/D.
+  subtree_wc = sbox.add_wc_path('D_COPY')
+  svntest.actions.run_and_verify_svn(None, None, [], 'co',
+                                     sbox.repo_url + '/A_COPY/D',
+                                     subtree_wc)
+
+  # Check the merged and eligible revisions both recursively and
+  # non-recursively.
+
+  # Eligible : Non-recursive  
+  svntest.actions.run_and_verify_mergeinfo(
+    adjust_error_for_server_version(''),
+    ['4','5'], sbox.repo_url + '/A/D', subtree_wc,
+    '--show-revs', 'eligible')
+
+  # Eligible : Recursive
+  svntest.actions.run_and_verify_mergeinfo(
+    adjust_error_for_server_version(''),
+    ['4'], sbox.repo_url + '/A/D', subtree_wc,
+    '--show-revs', 'eligible', '-R')
+
+  # Merged : Non-recursive
+  svntest.actions.run_and_verify_mergeinfo(
+    adjust_error_for_server_version(''),
+    ['7'], sbox.repo_url + '/A/D', subtree_wc,
+    '--show-revs', 'merged')
+
+  # Merged : Recursive
+  svntest.actions.run_and_verify_mergeinfo(
+    adjust_error_for_server_version(''),
+    ['5','7'], sbox.repo_url + '/A/D', subtree_wc,
+    '--show-revs', 'merged', '-R')
+
+  # Test that intersecting revisions in the 'svn mergeinfo' target
+  # from one source don't show up as merged when asking about a different
+  # source.
+  #
+  # In r9 make a change that effects two branches:
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svntest.main.file_write(gamma_2_path, "New content.\n")
+  svntest.main.file_write(tau_path, "New content.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Make changes under both A and A_COPY_2',
+                                     wc_dir)
+
+  # In r10 merge r9 from A_COPY_2 to A_COPY.
+  #
+  # This gives us this mergeinfo:
+  #
+  #   Properties on 'A_COPY':
+  #     svn:mergeinfo
+  #       /A:7
+  #       /A_COPY_2:9
+  #   Properties on 'A_COPY\D\G\rho':
+  #     svn:mergeinfo
+  #       /A/D/G/rho:5
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A_COPY_2',
+                                     A_COPY_path, '-c9')
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Merge r8 from A_COPY_2 to A_COPY',
+                                     wc_dir)
+ 
+  def test_svn_mergeinfo_4_way(wc_target):
+    # Eligible : Non-recursive
+    svntest.actions.run_and_verify_mergeinfo(
+      adjust_error_for_server_version(''),
+      ['4','5','9'], sbox.repo_url + '/A/D', wc_target,
+      '--show-revs', 'eligible')
+
+    # Eligible : Recursive
+    svntest.actions.run_and_verify_mergeinfo(
+      adjust_error_for_server_version(''),
+      ['4','9'], sbox.repo_url + '/A/D', wc_target,
+      '--show-revs', 'eligible', '-R')
+
+    # Merged : Non-recursive
+    svntest.actions.run_and_verify_mergeinfo(
+      adjust_error_for_server_version(''),
+      ['7'], sbox.repo_url + '/A/D', wc_target,
+      '--show-revs', 'merged')
+
+    # Merged : Recursive
+    svntest.actions.run_and_verify_mergeinfo(
+      adjust_error_for_server_version(''),
+      ['5','7'], sbox.repo_url + '/A/D', wc_target,
+      '--show-revs', 'merged', '-R')
+
+  # Test while the target is the full WC and then with the subtree WC:
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', subtree_wc)
+
+  test_svn_mergeinfo_4_way(D_COPY_path)
+  test_svn_mergeinfo_4_way(subtree_wc)
+
 ########################################################################
 # Run the tests
 
@@ -503,6 +638,7 @@ test_list = [ None,
               non_inheritable_mergeinfo,
               recursive_mergeinfo,
               mergeinfo_on_pegged_wc_path,
+              wc_target_inherits_mergeinfo_from_repos,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py Mon Aug 15 12:32:42 2011
@@ -3484,6 +3484,137 @@ def patch_add_symlink(sbox):
                                        1, # check-props
                                        1) # dry-run
 
+def patch_moved_away(sbox):
+  "patch a file that was moved away"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  patch_file_path = make_patch_path(sbox)
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+
+  mu_contents = [
+    "Dear internet user,\n",
+    "\n",
+    "We wish to congratulate you over your email success in our computer\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 13th June. 2009\n",
+    "\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+    "\n",
+    "Again, we wish to congratulate you over your email success in our\n"
+    "computer Balloting.\n"
+  ]
+
+  # Set mu contents
+  svntest.main.file_write(mu_path, ''.join(mu_contents))
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/mu'       : Item(verb='Sending'),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', wc_rev=2)
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+
+  # Move mu away
+  sbox.simple_move("A/mu", "A/mu2")
+
+  # Apply patch
+  unidiff_patch = [
+    "--- A/mu.orig	2009-06-24 15:23:55.000000000 +0100\n",
+    "+++ A/mu	2009-06-24 15:21:23.000000000 +0100\n",
+    "@@ -6,6 +6,9 @@\n",
+    " through a computer ballot system drawn from over 100,000 company\n",
+    " and 50,000,000 individual email addresses from all over the world.\n",
+    " \n",
+    "+It is a promotional program aimed at encouraging internet users;\n",
+    "+therefore you do not need to buy ticket to enter for it.\n",
+    "+\n",
+    " Your email address drew and have won the sum of  750,000 Euros\n",
+    " ( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    " file with\n",
+    "@@ -14,11 +17,8 @@\n",
+    "     BATCH NUMBERS :\n",
+    "     EULO/1007/444/606/08;\n",
+    "     SERIAL NUMBER: 45327\n",
+    "-and PROMOTION DATE: 13th June. 2009\n",
+    "+and PROMOTION DATE: 14th June. 2009\n",
+    " \n",
+    " To claim your winning prize, you are to contact the appointed\n",
+    " agent below as soon as possible for the immediate release of your\n",
+    " winnings with the below details.\n",
+    "-\n",
+    "-Again, we wish to congratulate you over your email success in our\n",
+    "-computer Balloting.\n",
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  mu_contents = [
+    "Dear internet user,\n",
+    "\n",
+    "We wish to congratulate you over your email success in our computer\n",
+    "Balloting. This is a Millennium Scientific Electronic Computer Draw\n",
+    "in which email addresses were used. All participants were selected\n",
+    "through a computer ballot system drawn from over 100,000 company\n",
+    "and 50,000,000 individual email addresses from all over the world.\n",
+    "\n",
+    "It is a promotional program aimed at encouraging internet users;\n",
+    "therefore you do not need to buy ticket to enter for it.\n",
+    "\n",
+    "Your email address drew and have won the sum of  750,000 Euros\n",
+    "( Seven Hundred and Fifty Thousand Euros) in cash credited to\n",
+    "file with\n",
+    "    REFERENCE NUMBER: ESP/WIN/008/05/10/MA;\n",
+    "    WINNING NUMBER : 14-17-24-34-37-45-16\n",
+    "    BATCH NUMBERS :\n",
+    "    EULO/1007/444/606/08;\n",
+    "    SERIAL NUMBER: 45327\n",
+    "and PROMOTION DATE: 14th June. 2009\n",
+    "\n",
+    "To claim your winning prize, you are to contact the appointed\n",
+    "agent below as soon as possible for the immediate release of your\n",
+    "winnings with the below details.\n",
+  ]
+
+  expected_output = [
+    'U         %s\n' % os.path.join(wc_dir, 'A', 'mu2'),
+  ]
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({'A/mu2': Item(contents=''.join(mu_contents))})
+  expected_disk.remove('A/mu')
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({'A/mu2' : Item(status='A ', copied='+', wc_rev='-')})
+
+  expected_status.tweak('A/mu', status='D ', wc_rev=2)
+
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1) # dry-run
+
 
 ########################################################################
 #Run the tests
@@ -3520,6 +3651,7 @@ test_list = [ None,
               patch_strip_cwd,
               patch_set_prop_no_eol,
               patch_add_symlink,
+              patch_moved_away,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/tools/dev/benchmarks/suite1/benchmark.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/tools/dev/benchmarks/suite1/benchmark.py?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/tools/dev/benchmarks/suite1/benchmark.py (original)
+++ subversion/branches/fs-py/tools/dev/benchmarks/suite1/benchmark.py Mon Aug 15 12:32:42 2011
@@ -164,10 +164,10 @@ class Timings:
     s = ['COMPARE %s to %s' % (othername, selfname)]
 
     if TOTAL_RUN in self.timings and TOTAL_RUN in other.timings:
-      s.append('  %s times: %5.1f seconds avg for %s' % (TOTAL_RUN,
-                                                         othertotal, othername))
-      s.append('  %s        %5.1f seconds avg for %s' % (' ' * len(TOTAL_RUN),
-                                                         selftotal, selfname))
+      s.append('  %s timings: %5.1f seconds avg for %s'
+               % (TOTAL_RUN, othertotal, othername))
+      s.append('  %s          %5.1f seconds avg for %s'
+               % (' ' * len(TOTAL_RUN), selftotal, selfname))
 
 
     s.append('      min              max              avg         operation')
@@ -201,9 +201,9 @@ class Timings:
                  name))
 
     s.extend([
-         '("1.23|+0.45"  means factor=1.23, difference in seconds = 0.45',
-         'factor < 1 or difference < 0 means \'%s\' is faster than \'%s\')'
-           % (self.name, othername)])
+      '(legend: "1.23|+0.45" means: slower by factor 1.23 and by 0.45 seconds;',
+      ' factor < 1 and difference < 0 means \'%s\' is faster than \'%s\')'
+      % (self.name, othername)])
 
     return '\n'.join(s)
 
@@ -418,7 +418,8 @@ def run(levels, spread, N):
 
       so, se = svn('--version')
       if not so:
-        print "Can't find svn."
+        ### options comes from the global namespace; it should be passed
+        print "Can't find svn at", options.svn
         exit(1)
       version = ', '.join([s.strip() for s in so.split('\n')[:2]])
 
@@ -565,6 +566,9 @@ def cmd_run(timings_path, levels, spread
   print '\n\nHi, going to run a Subversion benchmark series of %d runs...' % N
 
   ### UGH! should pass to run()
+  ### neels: Today I contemplated doing that, but at the end of the day
+  ###        it merely blows up the code without much benefit. If this
+  ###        ever becomes part of an imported python package, call again.
   global timings
 
   if os.path.isfile(timings_path):

Modified: subversion/branches/fs-py/tools/dev/benchmarks/suite1/run
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/tools/dev/benchmarks/suite1/run?rev=1157811&r1=1157810&r2=1157811&view=diff
==============================================================================
--- subversion/branches/fs-py/tools/dev/benchmarks/suite1/run (original)
+++ subversion/branches/fs-py/tools/dev/benchmarks/suite1/run Mon Aug 15 12:32:42 2011
@@ -19,11 +19,15 @@
 
 # Where are the svn binaries you want to benchmark?
 if [ "$USER" = "neels" ]; then
-  SVN_1_6="$HOME/pat/stable/prefix/bin/svn"
-  SVN_trunk="$HOME/pat/trunk/prefix/bin/svn"
+  SVN_A_NAME="1.7.x"
+  SVN_A="$HOME/pat/bench/prefix/bin/svn"
+  SVN_B_NAME="trunk"
+  SVN_B="$HOME/pat/trunk/prefix/bin/svn"
 else
-  SVN_1_6="$HOME/src/svn-1.6.x/subversion/svn/svn"
-  SVN_trunk="$HOME/src/svn/subversion/svn/svn"
+  SVN_A_NAME="1.6"
+  SVN_A="$HOME/src/svn-1.6.x/subversion/svn/svn"
+  SVN_B_NAME="trunk"
+  SVN_B="$HOME/src/svn/subversion/svn/svn"
 fi
 
 benchmark="$PWD/benchmark.py"
@@ -44,9 +48,9 @@ batch(){
   echo "---------------------------------------------------------------------"
   echo
   echo "Results for dir levels: $levels  spread: $spread"
-  "$benchmark" "--svn=${SVN_1_6}" run ${pre}1.6 $levels $spread $N >/dev/null
-  "$benchmark" "--svn=${SVN_trunk}" run ${pre}trunk $levels $spread $N > /dev/null
-  "$benchmark" compare ${pre}1.6 ${pre}trunk
+  "$benchmark" "--svn=$SVN_A" run "${pre}$SVN_A_NAME" $levels $spread $N >/dev/null
+  "$benchmark" "--svn=$SVN_B" run "${pre}$SVN_B_NAME" $levels $spread $N >/dev/null
+  "$benchmark" compare "${pre}$SVN_A_NAME" "${pre}$SVN_B_NAME"
 }
 
 N=6
@@ -80,11 +84,11 @@ batch $cl $cs $N
 echo ""
 echo =========================================================================
 echo ""
-"$benchmark" combine total_1.6 *x*_1.6 >/dev/null
-"$benchmark" combine total_trunk *x*_trunk >/dev/null
+"$benchmark" combine "total_$SVN_A_NAME" *x*"_$SVN_A_NAME" >/dev/null
+"$benchmark" combine "total_$SVN_B_NAME" *x*"_$SVN_B_NAME" >/dev/null
 
 echo "comparing averaged totals..."
-"$benchmark" compare total_1.6 total_trunk
+"$benchmark" compare "total_$SVN_A_NAME" "total_$SVN_B_NAME"
 
 echo ""
 echo "Had started at $started,"