subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhuij...@apache.org
Subject svn commit: r1569551 - in /subversion/trunk/subversion: libsvn_client/diff_local.c tests/cmdline/diff_tests.py
Date Tue, 18 Feb 2014 23:03:08 GMT
Author: rhuijben
Date: Tue Feb 18 23:03:08 2014
New Revision: 1569551

URL: http://svn.apache.org/r1569551
Log:
Reimplement the 'arbitrary nodes diff' in libsvn_client as a proper driver of
the diff processor, instead of a driver of the old diff callbacks 'with nice
output' (which was in some cases invalid and didn't follow any of the
ordering rules).

This removes the last real driver of the old diff callbacks and will finally
make it possible to convert the diff output handling to the diff processor
api, which will allow resolving some long standing bugs and feature
requests.

In theory this might even allow driving merge over this diff (to allow
things like maintaining vendor branches), but this will require more work.

* subversion/libsvn_client/diff_local.c
  (includes): Add private/svn_diff_tree.h.

  (do_file_diff,
   do_dir_diff): New prototype.

  (do_arbitrary_files_diff): Remove function.
  (arbitrary_diff_walker_baton): Remove struct.
  (arbitrary_diff_walker,
   arbitrary_diff_this_dir): Remove prototypes.

  (do_arbitrary_dirs_diff,
   arbitrary_diff_this_dir): Fold into each other and rrename to...
  (inner_dir_diff): ... this. Obtain dirents in both directories and
    handle the results recursively, following the diff editor rules.

  (do_dir_diff,
   do_file_diff): New functions.

  (arbitrary_diff_walker): Remove function.

  (svn_client__arbitrary_nodes_diff): Wrap callbacks using the standard
    wrapper. Update caller.

* subversion/tests/cmdline/diff_tests.py
  (diff_two_working_copies): Assume that additions are reported as
    'revision 0', like how all other diff drivers produce the data.
    Assume that the driver properly notices the change from F of a directory
    to a file, and as such reports a delete and add.
    (But directory deletes can't report property deletes via the old
     callbacks api)

  (diff_arbitrary_files_and_dirs): Assume that additions are reported as
    'revision 0', like how all other diff drivers produce the data.

Modified:
    subversion/trunk/subversion/libsvn_client/diff_local.c
    subversion/trunk/subversion/tests/cmdline/diff_tests.py

Modified: subversion/trunk/subversion/libsvn_client/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff_local.c?rev=1569551&r1=1569550&r2=1569551&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff_local.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff_local.c Tue Feb 18 23:03:08 2014
@@ -44,11 +44,11 @@
 #include "svn_pools.h"
 #include "svn_props.h"
 #include "svn_sorts.h"
-#include "svn_subst.h"
 #include "client.h"
 
 #include "private/svn_sorts_private.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_diff_tree.h"
 
 
 /* Try to get properties for LOCAL_ABSPATH and return them in the property
@@ -82,559 +82,640 @@ get_props(apr_hash_t **props,
   return SVN_NO_ERROR;
 }
 
-/* Produce a diff between two arbitrary files at LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2, using the diff callbacks from CALLBACKS.
- * Use PATH as the name passed to diff callbacks.
- * FILE1_IS_EMPTY and FILE2_IS_EMPTY are used as hints which diff callback
- * function to use to compare the files (added/deleted/changed).
+/* Forward declaration */
+static svn_error_t *
+do_file_diff(const char *left_abspath,
+             const char *right_abspath,
+             const char *left_root_abspath,
+             const char *right_root_abspath,
+             svn_boolean_t left_only,
+             svn_boolean_t right_only,
+             void *parent_baton,
+             const svn_diff_tree_processor_t *diff_processor,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *scratch_pool);
+
+/* Forward declaration */
+static svn_error_t *
+do_dir_diff(const char *left_abspath,
+            const char *right_abspath,
+            const char *left_root_abspath,
+            const char *right_root_abspath,
+            svn_boolean_t left_only,
+            svn_boolean_t right_only,
+            svn_boolean_t left_before_right,
+            svn_depth_t depth,
+            void *parent_baton,
+            const svn_diff_tree_processor_t *diff_processor,
+            svn_client_ctx_t *ctx,
+            apr_pool_t *scratch_pool);
+
+/* Produce a diff of depth DEPTH between two arbitrary directories at
+ * LEFT_ABSPATH1 and RIGHT_ABSPATH2, using the provided diff callbacks
+ * to show file changes and, for versioned nodes, property changes.
  *
- * If ORIGINAL_PROPS_OVERRIDE is not NULL, use it as original properties
- * instead of reading properties from LOCAL_ABSPATH1. This is required when
- * a file replaces a directory, where LOCAL_ABSPATH1 is an empty file that
- * file content must be diffed against, but properties to diff against come
- * from the replaced directory. */
+ * Report paths as relative from LEFT_ROOT_ABSPATH/RIGHT_ROOT_ABSPATH.
+ *
+ * If LEFT_ONLY is TRUE, only the left source exists (= everything will
+ * be reported as deleted). If RIGHT_ONLY is TRUE, only the right source
+ * exists (= everything will be reported as added).
+ *
+ * If LEFT_BEFORE_RIGHT is TRUE and left and right are unrelated, left is
+ * reported first. If false, right is reported first. (This is to allow
+ * producing a proper inverse diff).
+ *
+ * Walk the sources according to depth, and report with parent baton
+ * PARENT_BATON. */
 static svn_error_t *
-do_arbitrary_files_diff(const char *local_abspath1,
-                        const char *local_abspath2,
-                        const char *path,
-                        svn_boolean_t file1_is_empty,
-                        svn_boolean_t file2_is_empty,
-                        apr_hash_t *original_props_override,
-                        const svn_wc_diff_callbacks4_t *callbacks,
-                        void *diff_baton,
-                        svn_client_ctx_t *ctx,
-                        apr_pool_t *scratch_pool)
+inner_dir_diff(const char *left_abspath,
+               const char *right_abspath,
+               const char *left_root_abspath,
+               const char *right_root_abspath,
+               svn_boolean_t left_only,
+               svn_boolean_t right_only,
+               svn_boolean_t left_before_right,
+               svn_depth_t depth,
+               void *parent_baton,
+               const svn_diff_tree_processor_t *diff_processor,
+               svn_client_ctx_t *ctx,
+               apr_pool_t *scratch_pool)
 {
-  apr_hash_t *original_props;
-  apr_hash_t *modified_props;
-  apr_array_header_t *prop_changes;
-  svn_string_t *original_mime_type = NULL;
-  svn_string_t *modified_mime_type = NULL;
-
-  if (ctx->cancel_func)
-    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
-
-  /* Try to get properties from either file. It's OK if the files do not
-   * have properties, or if they are unversioned. */
-  if (original_props_override)
-    original_props = original_props_override;
-  else
-    SVN_ERR(get_props(&original_props, local_abspath1, ctx->wc_ctx,
-                      scratch_pool, scratch_pool));
-  SVN_ERR(get_props(&modified_props, local_abspath2, ctx->wc_ctx,
-                    scratch_pool, scratch_pool));
-
-  SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props,
-                         scratch_pool));
-
-  /* Try to determine the mime-type of each file. */
-  original_mime_type = svn_hash_gets(original_props, SVN_PROP_MIME_TYPE);
-  if (!file1_is_empty && !original_mime_type)
-    {
-      const char *mime_type;
-      SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1,
-                                      ctx->mimetypes_map, scratch_pool));
-
-      if (mime_type)
-        original_mime_type = svn_string_create(mime_type, scratch_pool);
-    }
-
-  modified_mime_type = svn_hash_gets(modified_props, SVN_PROP_MIME_TYPE);
-  if (!file2_is_empty && !modified_mime_type)
-    {
-      const char *mime_type;
-      SVN_ERR(svn_io_detect_mimetype2(&mime_type, local_abspath1,
-                                      ctx->mimetypes_map, scratch_pool));
-
-      if (mime_type)
-        modified_mime_type = svn_string_create(mime_type, scratch_pool);
-    }
-
-  /* Produce the diff. */
-  if (file1_is_empty && !file2_is_empty)
-    SVN_ERR(callbacks->file_added(NULL, NULL, NULL, path,
-                                  local_abspath1, local_abspath2,
-                                  /* ### TODO get real revision info
-                                   * for versioned files? */
-                                  SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
-                                  original_mime_type ?
-                                    original_mime_type->data : NULL,
-                                  modified_mime_type ?
-                                    modified_mime_type->data : NULL,
-                                  /* ### TODO get copyfrom? */
-                                  NULL, SVN_INVALID_REVNUM,
-                                  prop_changes, original_props,
-                                  diff_baton, scratch_pool));
-  else if (!file1_is_empty && file2_is_empty)
-    SVN_ERR(callbacks->file_deleted(NULL, NULL, path,
-                                    local_abspath1, local_abspath2,
-                                    original_mime_type ?
-                                      original_mime_type->data : NULL,
-                                    modified_mime_type ?
-                                      modified_mime_type->data : NULL,
-                                    original_props,
-                                    diff_baton, scratch_pool));
-  else
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_t *left_dirents;
+  apr_hash_t *right_dirents;
+  apr_array_header_t *sorted_dirents;
+  svn_error_t *err;
+  svn_depth_t depth_below_here;
+  int i;
+
+  SVN_ERR_ASSERT(depth >= svn_depth_files && depth <= svn_depth_infinity);
+
+  if (!right_only)
     {
-      svn_stream_t *file1;
-      svn_stream_t *file2;
-      svn_boolean_t same;
-      svn_string_t *val;
-      /* We have two files, which may or may not be the same.
+      err = svn_io_get_dirents3(&left_dirents, left_abspath, FALSE,
+                                scratch_pool, iterpool);
 
-         ### Our caller assumes that we should ignore symlinks here and
-             handle them as normal paths. Perhaps that should change?
-      */
-      SVN_ERR(svn_stream_open_readonly(&file1, local_abspath1, scratch_pool,
-                                       scratch_pool));
+      if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
+                  || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
+        {
+          svn_error_clear(err);
+          left_dirents = apr_hash_make(scratch_pool);
+          right_only = TRUE;
+        }
+      else
+        SVN_ERR(err);
+    }
+  else
+    left_dirents = apr_hash_make(scratch_pool);
 
-      SVN_ERR(svn_stream_open_readonly(&file2, local_abspath2, scratch_pool,
-                                       scratch_pool));
+  if (!left_only)
+    {
+      err = svn_io_get_dirents3(&right_dirents, right_abspath, FALSE,
+                                scratch_pool, iterpool);
 
-      /* Wrap with normalization, etc. if necessary */
-      if (original_props)
+      if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
+                  || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
         {
-          val = svn_hash_gets(original_props, SVN_PROP_EOL_STYLE);
+          svn_error_clear(err);
+          right_dirents = apr_hash_make(scratch_pool);
+          right_only = TRUE;
+        }
+      else
+        SVN_ERR(err);
+    }
+  else
+    right_dirents = apr_hash_make(scratch_pool);
+
+  if (left_only && right_only)
+    return SVN_NO_ERROR; /* Somebody deleted the directory?? */
+
+  if (depth != svn_depth_infinity)
+    depth_below_here = svn_depth_empty;
+  else
+    depth_below_here = svn_depth_infinity;
+
+  sorted_dirents = svn_sort__hash(apr_hash_merge(iterpool, left_dirents,
+                                                 right_dirents, NULL, NULL),
+                                  svn_sort_compare_items_as_paths,
+                                  scratch_pool);
 
-          if (val)
+  for (i = 0; i < sorted_dirents->nelts; i++)
+    {
+      svn_sort__item_t* elt = &APR_ARRAY_IDX(sorted_dirents, i, svn_sort__item_t);
+      svn_io_dirent2_t *left_dirent;
+      svn_io_dirent2_t *right_dirent;
+      const char *child_left_abspath;
+      const char *child_right_abspath;
+
+      svn_pool_clear(iterpool);
+
+      if (ctx->cancel_func)
+        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+
+      if (svn_wc_is_adm_dir(elt->key, iterpool))
+        continue;
+
+      left_dirent = right_only ? NULL : svn_hash_gets(left_dirents, elt->key);
+      right_dirent = left_only ? NULL : svn_hash_gets(right_dirents, elt->key);
+
+      child_left_abspath = svn_dirent_join(left_abspath, elt->key, iterpool);
+      child_right_abspath = svn_dirent_join(right_abspath, elt->key, iterpool);
+
+      if (((left_dirent == NULL) != (right_dirent == NULL))
+          || (left_dirent->kind != right_dirent->kind))
+        {
+          /* Report delete and/or add */
+          if (left_dirent && left_before_right)
             {
-              svn_subst_eol_style_t style;
-              const char *eol;
-              svn_subst_eol_style_from_value(&style, &eol, val->data);
-
-              /* ### Ignoring keywords */
-              if (eol)
-                file1 = svn_subst_stream_translated(file1, eol, TRUE,
-                                                    NULL, FALSE,
-                                                    scratch_pool);
+              if (left_dirent->kind == svn_node_file)
+                SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, parent_baton,
+                                     diff_processor, ctx, iterpool));
+              else if (depth >= svn_depth_immediates)
+                SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE, left_before_right,
+                                    depth_below_here, parent_baton,
+                                    diff_processor, ctx, iterpool));
             }
-        }
 
-      if (modified_props)
-        {
-          val = svn_hash_gets(modified_props, SVN_PROP_EOL_STYLE);
+          if (right_dirent)
+            {
+              if (right_dirent->kind == svn_node_file)
+                SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     FALSE, TRUE, parent_baton,
+                                     diff_processor, ctx, iterpool));
+              else if (depth >= svn_depth_immediates)
+                SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    FALSE, TRUE,  left_before_right,
+                                    depth_below_here, parent_baton,
+                                    diff_processor, ctx, iterpool));
+            }
 
-          if (val)
+          if (left_dirent && !left_before_right)
             {
-              svn_subst_eol_style_t style;
-              const char *eol;
-              svn_subst_eol_style_from_value(&style, &eol, val->data);
-
-              /* ### Ignoring keywords */
-              if (eol)
-                file2 = svn_subst_stream_translated(file2, eol, TRUE,
-                                                    NULL, FALSE,
-                                                    scratch_pool);
+              if (left_dirent->kind == svn_node_file)
+                SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, parent_baton,
+                                     diff_processor, ctx, iterpool));
+              else if (depth >= svn_depth_immediates)
+                SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE,  left_before_right,
+                                    depth_below_here, parent_baton,
+                                    diff_processor, ctx, iterpool));
             }
         }
-
-      SVN_ERR(svn_stream_contents_same2(&same, file1, file2, scratch_pool));
-
-      if (! same || prop_changes->nelts > 0)
+      else if (left_dirent->kind == svn_node_file)
         {
-          /* ### We should probably pass the normalized data we created using
-                 the subst streams as that is what diff users expect */
-          SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, path,
-                                          same ? NULL : local_abspath1,
-                                          same ? NULL : local_abspath2,
-                                          /* ### TODO get real revision info
-                                           * for versioned files? */
-                                          SVN_INVALID_REVNUM /* rev1 */,
-                                          SVN_INVALID_REVNUM /* rev2 */,
-                                          original_mime_type ?
-                                            original_mime_type->data : NULL,
-                                          modified_mime_type ?
-                                            modified_mime_type->data : NULL,
-                                          prop_changes, original_props,
-                                          diff_baton, scratch_pool));
+          /* Perform file-file diff */
+          SVN_ERR(do_file_diff(child_left_abspath, child_right_abspath,
+                               left_root_abspath, right_root_abspath,
+                               FALSE, FALSE, parent_baton,
+                               diff_processor, ctx, iterpool));
+        }
+      else if (depth >= svn_depth_immediates)
+        {
+          /* Perform dir-dir diff */
+          SVN_ERR(do_dir_diff(child_left_abspath, child_right_abspath,
+                              left_root_abspath, right_root_abspath,
+                              FALSE, FALSE,  left_before_right,
+                              depth_below_here, parent_baton,
+                              diff_processor, ctx, iterpool));
         }
     }
 
   return SVN_NO_ERROR;
 }
-
-struct arbitrary_diff_walker_baton {
-  /* The root directories of the trees being compared. */
-  const char *root1_abspath;
-  const char *root2_abspath;
-
-  /* TRUE if recursing within an added subtree of root2_abspath that
-   * does not exist in root1_abspath. */
-  svn_boolean_t recursing_within_added_subtree;
-
-  /* TRUE if recursing within an administrative (.i.e. .svn) directory. */
-  svn_boolean_t recursing_within_adm_dir;
-
-  /* The absolute path of the adm dir if RECURSING_WITHIN_ADM_DIR is TRUE.
-   * Else this is NULL.*/
-  const char *adm_dir_abspath;
-
-  /* A path to an empty file used for diffs that add/delete files. */
-  const char *empty_file_abspath;
-
-  const svn_wc_diff_callbacks4_t *callbacks;
-  void *diff_baton;
-  svn_client_ctx_t *ctx;
-  apr_pool_t *pool;
-} arbitrary_diff_walker_baton;
-
-/* Forward declaration needed because this function has a cyclic
- * dependency with do_arbitrary_dirs_diff(). */
+/* Handles reporting of a file for inner_dir_diff */
 static svn_error_t *
-arbitrary_diff_walker(void *baton, const char *local_abspath,
-                      const apr_finfo_t *finfo,
-                      apr_pool_t *scratch_pool);
+do_file_diff(const char *left_abspath,
+             const char *right_abspath,
+             const char *left_root_abspath,
+             const char *right_root_abspath,
+             svn_boolean_t left_only,
+             svn_boolean_t right_only,
+             void *parent_baton,
+             const svn_diff_tree_processor_t *diff_processor,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *scratch_pool)
+{
+  const char *relpath;
+  svn_diff_source_t *left_source;
+  svn_diff_source_t *right_source;
+  svn_boolean_t skip = FALSE;
+  apr_hash_t *left_props;
+  apr_hash_t *right_props;
+  void *file_baton;
 
-/* Another forward declaration. */
-static svn_error_t *
-arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b,
-                        const char *local_abspath,
-                        svn_depth_t depth,
-                        apr_pool_t *scratch_pool);
+  relpath = svn_dirent_skip_ancestor(left_root_abspath, left_abspath);
 
-/* Produce a diff of depth DEPTH between two arbitrary directories at
- * LOCAL_ABSPATH1 and LOCAL_ABSPATH2, using the provided diff callbacks
- * to show file changes and, for versioned nodes, property changes.
- *
- * If ROOT_ABSPATH1 and ROOT_ABSPATH2 are not NULL, show paths in diffs
- * relative to these roots, rather than relative to LOCAL_ABSPATH1 and
- * LOCAL_ABSPATH2. This is needed when crawling a subtree that exists
- * only within LOCAL_ABSPATH2. */
-static svn_error_t *
-do_arbitrary_dirs_diff(const char *local_abspath1,
-                       const char *local_abspath2,
-                       const char *root_abspath1,
-                       const char *root_abspath2,
-                       svn_depth_t depth,
-                       const svn_wc_diff_callbacks4_t *callbacks,
-                       void *diff_baton,
-                       svn_client_ctx_t *ctx,
-                       apr_pool_t *scratch_pool)
-{
-  apr_file_t *empty_file;
-  svn_node_kind_t kind1;
+ if (! right_only)
+    left_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+  else
+    left_source = NULL;
 
-  struct arbitrary_diff_walker_baton b;
+  if (! left_only)
+    right_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+  else
+    right_source = NULL;
 
-  /* If LOCAL_ABSPATH1 is not a directory, crawl LOCAL_ABSPATH2 instead
-   * and compare it to LOCAL_ABSPATH1, showing only additions.
-   * This case can only happen during recursion from arbitrary_diff_walker(),
-   * because do_arbitrary_nodes_diff() prevents this from happening at
-   * the root of the comparison. */
-  SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
-  b.recursing_within_added_subtree = (kind1 != svn_node_dir);
-
-  b.root1_abspath = root_abspath1 ? root_abspath1 : local_abspath1;
-  b.root2_abspath = root_abspath2 ? root_abspath2 : local_abspath2;
-  b.recursing_within_adm_dir = FALSE;
-  b.adm_dir_abspath = NULL;
-  b.callbacks = callbacks;
-  b.diff_baton = diff_baton;
-  b.ctx = ctx;
-  b.pool = scratch_pool;
-
-  SVN_ERR(svn_io_open_unique_file3(&empty_file, &b.empty_file_abspath,
-                                   NULL, svn_io_file_del_on_pool_cleanup,
-                                   scratch_pool, scratch_pool));
-
-  if (depth <= svn_depth_immediates)
-    SVN_ERR(arbitrary_diff_this_dir(&b, local_abspath1, depth, scratch_pool));
-  else if (depth == svn_depth_infinity)
-    SVN_ERR(svn_io_dir_walk2(b.recursing_within_added_subtree ? local_abspath2
-                                                              : local_abspath1,
-                             0, arbitrary_diff_walker, &b, scratch_pool));
-  return SVN_NO_ERROR;
-}
+  SVN_ERR(diff_processor->file_opened(&file_baton, &skip,
+                                      relpath,
+                                      left_source,
+                                      right_source,
+                                      NULL /* copyfrom_source */,
+                                      parent_baton,
+                                      diff_processor,
+                                      scratch_pool,
+                                      scratch_pool));
 
-/* Produce a diff of depth DEPTH for the directory at LOCAL_ABSPATH,
- * using information from the arbitrary_diff_walker_baton B.
- * LOCAL_ABSPATH is the path being crawled and can be on either side
- * of the diff depending on baton->recursing_within_added_subtree. */
-static svn_error_t *
-arbitrary_diff_this_dir(struct arbitrary_diff_walker_baton *b,
-                        const char *local_abspath,
-                        svn_depth_t depth,
-                        apr_pool_t *scratch_pool)
-{
-  const char *local_abspath1;
-  const char *local_abspath2;
-  svn_node_kind_t kind1;
-  svn_node_kind_t kind2;
-  const char *child_relpath;
-  apr_hash_t *dirents1;
-  apr_hash_t *dirents2;
-  apr_hash_t *merged_dirents;
-  apr_array_header_t *sorted_dirents;
-  int i;
-  apr_pool_t *iterpool;
+  if (skip)
+    return SVN_NO_ERROR;
 
-  if (b->recursing_within_adm_dir)
+   if (! right_only)
     {
-      if (svn_dirent_skip_ancestor(b->adm_dir_abspath, local_abspath))
-        return SVN_NO_ERROR;
-      else
+      SVN_ERR(get_props(&left_props, left_abspath, ctx->wc_ctx,
+                        scratch_pool, scratch_pool));
+
+      /* We perform a mimetype detection to avoid diffing binary files
+         for textual changes.*/
+      if (! svn_hash_gets(left_props, SVN_PROP_MIME_TYPE))
         {
-          b->recursing_within_adm_dir = FALSE;
-          b->adm_dir_abspath = NULL;
+          const char *mime_type;
+
+          /* ### Use libmagic magic? */
+          SVN_ERR(svn_io_detect_mimetype2(&mime_type, left_abspath,
+                                          ctx->mimetypes_map, scratch_pool));
+
+          if (mime_type)
+            svn_hash_sets(left_props, SVN_PROP_MIME_TYPE,
+                          svn_string_create(mime_type, scratch_pool));
         }
     }
-  else if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, NULL),
-                             scratch_pool))
-    {
-      b->recursing_within_adm_dir = TRUE;
-      b->adm_dir_abspath = apr_pstrdup(b->pool, local_abspath);
-      return SVN_NO_ERROR;
-    }
-
-  if (b->recursing_within_added_subtree)
-    child_relpath = svn_dirent_skip_ancestor(b->root2_abspath, local_abspath);
   else
-    child_relpath = svn_dirent_skip_ancestor(b->root1_abspath, local_abspath);
-  if (!child_relpath)
-    return SVN_NO_ERROR;
-
-  local_abspath1 = svn_dirent_join(b->root1_abspath, child_relpath,
-                                   scratch_pool);
-  SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
-
-  local_abspath2 = svn_dirent_join(b->root2_abspath, child_relpath,
-                                   scratch_pool);
-  SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool));
-
-  if (depth > svn_depth_empty)
-    {
-      if (kind1 == svn_node_dir)
-        SVN_ERR(svn_io_get_dirents3(&dirents1, local_abspath1,
-                                    TRUE, /* only_check_type */
-                                    scratch_pool, scratch_pool));
-      else
-        dirents1 = apr_hash_make(scratch_pool);
-    }
+    left_props = NULL;
 
-  if (kind2 == svn_node_dir)
+  if (! left_only)
     {
-      apr_hash_t *original_props;
-      apr_hash_t *modified_props;
-      apr_array_header_t *prop_changes;
-
-      /* Show any property changes for this directory. */
-      SVN_ERR(get_props(&original_props, local_abspath1, b->ctx->wc_ctx,
+      SVN_ERR(get_props(&right_props, right_abspath, ctx->wc_ctx,
                         scratch_pool, scratch_pool));
-      SVN_ERR(get_props(&modified_props, local_abspath2, b->ctx->wc_ctx,
-                        scratch_pool, scratch_pool));
-      SVN_ERR(svn_prop_diffs(&prop_changes, modified_props, original_props,
-                             scratch_pool));
-      if (prop_changes->nelts > 0)
-        SVN_ERR(b->callbacks->dir_props_changed(NULL, NULL, child_relpath,
-                                                FALSE /* was_added */,
-                                                prop_changes, original_props,
-                                                b->diff_baton,
-                                                scratch_pool));
-
-      if (depth > svn_depth_empty)
-        {
-          /* Read directory entries. */
-          SVN_ERR(svn_io_get_dirents3(&dirents2, local_abspath2,
-                                      TRUE, /* only_check_type */
-                                      scratch_pool, scratch_pool));
+
+      /* We perform a mimetype detection to avoid diffing binary files
+         for textual changes.*/
+      if (! svn_hash_gets(right_props, SVN_PROP_MIME_TYPE))
+        {
+          const char *mime_type;
+
+          /* ### Use libmagic magic? */
+          SVN_ERR(svn_io_detect_mimetype2(&mime_type, right_abspath,
+                                          ctx->mimetypes_map, scratch_pool));
+
+          if (mime_type)
+            svn_hash_sets(right_props, SVN_PROP_MIME_TYPE,
+                          svn_string_create(mime_type, scratch_pool));
         }
     }
-  else if (depth > svn_depth_empty)
-    dirents2 = apr_hash_make(scratch_pool);
-
-  if (depth <= svn_depth_empty)
-    return SVN_NO_ERROR;
+  else
+    right_props = NULL;
 
-  /* Compare dirents1 to dirents2 and show added/deleted/changed files. */
-  merged_dirents = apr_hash_merge(scratch_pool, dirents1, dirents2,
-                                  NULL, NULL);
-  sorted_dirents = svn_sort__hash(merged_dirents,
-                                  svn_sort_compare_items_as_paths,
-                                  scratch_pool);
-  iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < sorted_dirents->nelts; i++)
+  if (left_only)
     {
-      svn_sort__item_t elt = APR_ARRAY_IDX(sorted_dirents, i, svn_sort__item_t);
-      const char *name = elt.key;
-      svn_io_dirent2_t *dirent1;
-      svn_io_dirent2_t *dirent2;
-      const char *child1_abspath;
-      const char *child2_abspath;
-
-      svn_pool_clear(iterpool);
+      SVN_ERR(diff_processor->file_deleted(relpath,
+                                           left_source,
+                                           left_abspath,
+                                           left_props,
+                                           file_baton,
+                                           diff_processor,
+                                           scratch_pool));
+    }
+  else if (right_only)
+    {
+      SVN_ERR(diff_processor->file_added(relpath,
+                                         NULL /* copyfrom_source */,
+                                         right_source,
+                                         NULL /* copyfrom_file */,
+                                         right_abspath,
+                                         NULL /* copyfrom_props */,
+                                         right_props,
+                                         file_baton,
+                                         diff_processor,
+                                         scratch_pool));
+    }
+  else
+    {
+      /* ### Perform diff -> close/changed */
+      svn_boolean_t same;
+      apr_array_header_t *prop_changes;
 
-      if (b->ctx->cancel_func)
-        SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
+      SVN_ERR(svn_io_files_contents_same_p(&same, left_abspath, right_abspath,
+                                           scratch_pool));
 
-      if (strcmp(name, SVN_WC_ADM_DIR_NAME) == 0)
-        continue;
+      SVN_ERR(svn_prop_diffs(&prop_changes, right_props, left_props,
+                             scratch_pool));
 
-      dirent1 = svn_hash_gets(dirents1, name);
-      if (!dirent1)
+      if (!same || prop_changes->nelts > 0)
         {
-          dirent1 = svn_io_dirent2_create(iterpool);
-          dirent1->kind = svn_node_none;
+          SVN_ERR(diff_processor->file_changed(relpath,
+                                               left_source,
+                                               right_source,
+                                               same ? NULL : left_abspath,
+                                               same ? NULL : right_abspath,
+                                               left_props,
+                                               right_props,
+                                               !same,
+                                               prop_changes,
+                                               file_baton,
+                                               diff_processor,
+                                               scratch_pool));
         }
-      dirent2 = svn_hash_gets(dirents2, name);
-      if (!dirent2)
+      else
         {
-          dirent2 = svn_io_dirent2_create(iterpool);
-          dirent2->kind = svn_node_none;
+          SVN_ERR(diff_processor->file_closed(relpath,
+                                            left_source,
+                                            right_source,
+                                            file_baton,
+                                            diff_processor,
+                                            scratch_pool));
         }
+    }
+  return SVN_NO_ERROR;
+}
 
-      child1_abspath = svn_dirent_join(local_abspath1, name, iterpool);
-      child2_abspath = svn_dirent_join(local_abspath2, name, iterpool);
 
-      if (dirent1->special)
-        SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent1->kind,
-                                           iterpool));
-      if (dirent2->special)
-        SVN_ERR(svn_io_check_resolved_path(child1_abspath, &dirent2->kind,
-                                           iterpool));
+/* Handles reporting of a directory and its children for inner_dir_diff */
+static svn_error_t *
+do_dir_diff(const char *left_abspath,
+            const char *right_abspath,
+            const char *left_root_abspath,
+            const char *right_root_abspath,
+            svn_boolean_t left_only,
+            svn_boolean_t right_only,
+            svn_boolean_t left_before_right,
+            svn_depth_t depth,
+            void *parent_baton,
+            const svn_diff_tree_processor_t *diff_processor,
+            svn_client_ctx_t *ctx,
+            apr_pool_t *scratch_pool)
+{
+  const char *relpath;
+  svn_diff_source_t *left_source;
+  svn_diff_source_t *right_source;
+  svn_boolean_t skip = FALSE;
+  svn_boolean_t skip_children = FALSE;
+  void *dir_baton;
+  apr_hash_t *left_props;
+  apr_hash_t *right_props;
 
-      if (dirent1->kind == svn_node_dir &&
-          dirent2->kind == svn_node_dir)
-        {
-          if (depth == svn_depth_immediates)
-            {
-              /* Not using the walker, so show property diffs on these dirs. */
-              SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath,
-                                             b->root1_abspath, b->root2_abspath,
-                                             svn_depth_empty,
-                                             b->callbacks, b->diff_baton,
-                                             b->ctx, iterpool));
-            }
-          else
-            {
-              /* Either the walker will visit these directories (with
-               * depth=infinity) and they will be processed as 'this dir'
-               * later, or we're showing file children only (depth=files). */
-              continue;
-            }
+  relpath = svn_dirent_skip_ancestor(left_root_abspath, left_abspath);
 
-        }
+  if (! right_only)
+    {
+      left_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+      SVN_ERR(get_props(&left_props, left_abspath, ctx->wc_ctx,
+                        scratch_pool, scratch_pool));
+    }
+  else
+    {
+      left_source = NULL;
+      left_props = NULL;
+    }
 
-      /* Files that exist only in dirents1. */
-      if (dirent1->kind == svn_node_file &&
-          (dirent2->kind == svn_node_dir || dirent2->kind == svn_node_none))
-        SVN_ERR(do_arbitrary_files_diff(child1_abspath, b->empty_file_abspath,
-                                        svn_relpath_join(child_relpath, name,
-                                                         iterpool),
-                                        FALSE, TRUE, NULL,
-                                        b->callbacks, b->diff_baton,
-                                        b->ctx, iterpool));
-
-      /* Files that exist only in dirents2. */
-      if (dirent2->kind == svn_node_file &&
-          (dirent1->kind == svn_node_dir || dirent1->kind == svn_node_none))
-        {
-          apr_hash_t *original_props;
-
-          SVN_ERR(get_props(&original_props, child1_abspath, b->ctx->wc_ctx,
-                            scratch_pool, scratch_pool));
-          SVN_ERR(do_arbitrary_files_diff(b->empty_file_abspath, child2_abspath,
-                                          svn_relpath_join(child_relpath, name,
-                                                           iterpool),
-                                          TRUE, FALSE, original_props,
-                                          b->callbacks, b->diff_baton,
-                                          b->ctx, iterpool));
-        }
-
-      /* Files that exist in dirents1 and dirents2. */
-      if (dirent1->kind == svn_node_file && dirent2->kind == svn_node_file)
-        SVN_ERR(do_arbitrary_files_diff(child1_abspath, child2_abspath,
-                                        svn_relpath_join(child_relpath, name,
-                                                         iterpool),
-                                        FALSE, FALSE, NULL,
-                                        b->callbacks, b->diff_baton,
-                                        b->ctx, scratch_pool));
-
-      /* Directories that only exist in dirents2. These aren't crawled
-       * by this walker so we have to crawl them separately. */
-      if (depth > svn_depth_files &&
-          dirent2->kind == svn_node_dir &&
-          (dirent1->kind == svn_node_file || dirent1->kind == svn_node_none))
-        SVN_ERR(do_arbitrary_dirs_diff(child1_abspath, child2_abspath,
-                                       b->root1_abspath, b->root2_abspath,
-                                       depth <= svn_depth_immediates
-                                         ? svn_depth_empty
-                                         : svn_depth_infinity ,
-                                       b->callbacks, b->diff_baton,
-                                       b->ctx, iterpool));
+  if (! left_only)
+    {
+      right_source = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+      SVN_ERR(get_props(&right_props, right_abspath, ctx->wc_ctx,
+                        scratch_pool, scratch_pool));
+    }
+  else
+    {
+      right_source = NULL;
+      right_props = NULL;
     }
 
-  svn_pool_destroy(iterpool);
+  SVN_ERR(diff_processor->dir_opened(&dir_baton, &skip, &skip_children,
+                                     relpath,
+                                     left_source,
+                                     right_source,
+                                     NULL /* copyfrom_source */,
+                                     parent_baton,
+                                     diff_processor,
+                                     scratch_pool, scratch_pool));
 
-  return SVN_NO_ERROR;
-}
+  if (!skip_children)
+    {
+      if (depth >= svn_depth_files)
+        SVN_ERR(inner_dir_diff(left_abspath, right_abspath,
+                               left_root_abspath, right_root_abspath,
+                               left_only, right_only,
+                               left_before_right, depth,
+                               dir_baton,
+                               diff_processor, ctx, scratch_pool));
+    }
+  else if (skip)
+    return SVN_NO_ERROR;
 
-/* An implementation of svn_io_walk_func_t.
- * Note: LOCAL_ABSPATH is the path being crawled and can be on either side
- * of the diff depending on baton->recursing_within_added_subtree. */
-static svn_error_t *
-arbitrary_diff_walker(void *baton, const char *local_abspath,
-                      const apr_finfo_t *finfo,
-                      apr_pool_t *scratch_pool)
-{
-  struct arbitrary_diff_walker_baton *b = baton;
+  if (left_props && right_props)
+    {
+      apr_array_header_t *prop_diffs;
 
-  if (b->ctx->cancel_func)
-    SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
+      SVN_ERR(svn_prop_diffs(&prop_diffs, right_props, left_props,
+                             scratch_pool));
 
-  if (finfo->filetype != APR_DIR)
-    return SVN_NO_ERROR;
+      if (prop_diffs->nelts)
+        {
+          SVN_ERR(diff_processor->dir_changed(relpath,
+                                              left_source,
+                                              right_source,
+                                              left_props,
+                                              right_props,
+                                              prop_diffs,
+                                              dir_baton,
+                                              diff_processor,
+                                              scratch_pool));
+          return SVN_NO_ERROR;
+        }
+    }
 
-  SVN_ERR(arbitrary_diff_this_dir(b, local_abspath, svn_depth_infinity,
-                                  scratch_pool));
+  if (left_source && right_source)
+    {
+      SVN_ERR(diff_processor->dir_closed(relpath,
+                                         left_source,
+                                         right_source,
+                                         dir_baton,
+                                         diff_processor,
+                                         scratch_pool));
+    }
+  else if (left_source)
+    {
+      SVN_ERR(diff_processor->dir_deleted(relpath,
+                                          left_source,
+                                          left_props,
+                                          dir_baton,
+                                          diff_processor,
+                                          scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(diff_processor->dir_added(relpath,
+                                        NULL /* copyfrom_source */,
+                                        right_source,
+                                        NULL /* copyfrom_props */,
+                                        right_props,
+                                        dir_baton,
+                                        diff_processor,
+                                        scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_client__arbitrary_nodes_diff(const char *local_abspath1,
-                                 const char *local_abspath2,
+svn_client__arbitrary_nodes_diff(const char *left_abspath,
+                                 const char *right_abspath,
                                  svn_depth_t depth,
                                  const svn_wc_diff_callbacks4_t *callbacks,
                                  void *diff_baton,
                                  svn_client_ctx_t *ctx,
                                  apr_pool_t *scratch_pool)
 {
-  svn_node_kind_t kind1;
-  svn_node_kind_t kind2;
+  svn_node_kind_t left_kind;
+  svn_node_kind_t right_kind;
+  const char *left_root_abspath;
+  const char *right_root_abspath;
+  svn_boolean_t left_before_right = FALSE; /* Future argument */
+  const svn_diff_tree_processor_t *diff_processor;
+
+  SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
+                                      callbacks, diff_baton,
+                                      TRUE /* walk_deleted_dirs */,
+                                      scratch_pool, scratch_pool));
 
-  SVN_ERR(svn_io_check_resolved_path(local_abspath1, &kind1, scratch_pool));
-  SVN_ERR(svn_io_check_resolved_path(local_abspath2, &kind2, scratch_pool));
+  if (depth == svn_depth_unknown)
+    depth = svn_depth_infinity;
 
-  if (kind1 != kind2)
-    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
-                             _("'%s' is not the same node kind as '%s'"),
-                             svn_dirent_local_style(local_abspath1,
-                                                    scratch_pool),
-                             svn_dirent_local_style(local_abspath2,
-                                                    scratch_pool));
+  SVN_ERR(svn_io_check_resolved_path(left_abspath, &left_kind, scratch_pool));
+  SVN_ERR(svn_io_check_resolved_path(right_abspath, &right_kind, scratch_pool));
 
   if (depth == svn_depth_unknown)
     depth = svn_depth_infinity;
 
-  if (kind1 == svn_node_file)
-    SVN_ERR(do_arbitrary_files_diff(local_abspath1, local_abspath2,
-                                    svn_dirent_basename(local_abspath1,
-                                                        scratch_pool),
-                                    FALSE, FALSE, NULL,
-                                    callbacks, diff_baton,
-                                    ctx, scratch_pool));
-  else if (kind1 == svn_node_dir)
-    SVN_ERR(do_arbitrary_dirs_diff(local_abspath1, local_abspath2,
-                                   NULL, NULL, depth,
-                                   callbacks, diff_baton,
-                                   ctx, scratch_pool));
+  if (left_kind == svn_node_dir && right_kind == svn_node_dir)
+    {
+      left_root_abspath = left_abspath;
+      right_root_abspath = right_abspath;
+    }
+  else
+    {
+      left_root_abspath = svn_dirent_dirname(left_abspath, scratch_pool);
+      right_root_abspath = svn_dirent_dirname(right_abspath, scratch_pool);
+    }
+
+  if (left_kind == svn_node_dir && right_kind == svn_node_dir)
+    {
+      SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                          left_root_abspath, right_root_abspath,
+                          FALSE, FALSE, left_before_right,
+                          depth, NULL /* parent_baton */,
+                          diff_processor, ctx, scratch_pool));
+    }
+  else if (left_kind == svn_node_file && right_kind == svn_node_file)
+    {
+      SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                           left_root_abspath, right_root_abspath,
+                           FALSE, FALSE,
+                           NULL /* parent_baton */,
+                           diff_processor, ctx, scratch_pool));
+    }
+  else if (left_kind == svn_node_file || left_kind == svn_node_dir
+           || right_kind == svn_node_file || right_kind == svn_node_dir)
+    {
+      void *dir_baton;
+      svn_boolean_t skip = FALSE;
+      svn_boolean_t skip_children = FALSE;
+      svn_diff_source_t *left_src;
+      svn_diff_source_t *right_src;
+
+      left_src = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+      right_src = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool);
+
+      /* The root is replaced... */
+      /* Report delete and/or add */
+
+      SVN_ERR(diff_processor->dir_opened(&dir_baton, &skip, &skip_children, "",
+                                         left_src,
+                                         right_src,
+                                         NULL /* copyfrom_src */,
+                                         NULL,
+                                         diff_processor,
+                                         scratch_pool, scratch_pool));
+
+      if (skip)
+        return SVN_NO_ERROR;
+      else if (!skip_children)
+        {
+          if (left_before_right)
+            {
+              if (left_kind == svn_node_file)
+                SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, NULL /* parent_baton */,
+                                     diff_processor, ctx, scratch_pool));
+              else if (left_kind == svn_node_dir)
+                SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE, left_before_right,
+                                    depth, NULL /* parent_baton */,
+                                    diff_processor, ctx, scratch_pool));
+            }
+
+          if (right_kind == svn_node_file)
+            SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                                 left_root_abspath, right_root_abspath,
+                                 FALSE, TRUE, NULL /* parent_baton */,
+                                 diff_processor, ctx, scratch_pool));
+          else if (right_kind == svn_node_dir)
+            SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                                left_root_abspath, right_root_abspath,
+                                FALSE, TRUE,  left_before_right,
+                                depth, NULL /* parent_baton */,
+                                diff_processor, ctx, scratch_pool));
+
+          if (! left_before_right)
+            {
+              if (left_kind == svn_node_file)
+                SVN_ERR(do_file_diff(left_abspath, right_abspath,
+                                     left_root_abspath, right_root_abspath,
+                                     TRUE, FALSE, NULL /* parent_baton */,
+                                     diff_processor, ctx, scratch_pool));
+              else if (left_kind == svn_node_dir)
+                SVN_ERR(do_dir_diff(left_abspath, right_abspath,
+                                    left_root_abspath, right_root_abspath,
+                                    TRUE, FALSE,  left_before_right,
+                                    depth, NULL /* parent_baton */,
+                                    diff_processor, ctx, scratch_pool));
+            }
+        }
+
+      SVN_ERR(diff_processor->dir_closed("",
+                                         left_src,
+                                         right_src,
+                                         dir_baton,
+                                         diff_processor,
+                                         scratch_pool));
+    }
   else
     return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                              _("'%s' is not a file or directory"),
-                             kind1 == svn_node_none
-                               ? svn_dirent_local_style(local_abspath1,
-                                                        scratch_pool)
-                               : svn_dirent_local_style(local_abspath2,
-                                                        scratch_pool));
+                             svn_dirent_local_style(
+                                    (left_kind == svn_node_none)
+                                        ? left_abspath
+                                        : right_abspath,
+                                    scratch_pool));
+
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/diff_tests.py?rev=1569551&r1=1569550&r2=1569551&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/diff_tests.py Tue Feb 18 23:03:08 2014
@@ -3935,7 +3935,7 @@ def diff_two_working_copies(sbox):
 
   src_label = os.path.basename(wc_dir_old)
   dst_label = os.path.basename(wc_dir)
-  expected_output = make_diff_header('newdir/newfile', 'working copy',
+  expected_output = make_diff_header('newdir/newfile', 'revision 0',
                                      'working copy',
                                      src_label, dst_label) + [
                       "@@ -0,0 +1 @@\n",
@@ -3945,13 +3945,13 @@ def diff_two_working_copies(sbox):
                                          src_label, dst_label) + [
                       "@@ -1 +0,0 @@\n",
                       "-This is the file 'mu'.\n",
-                    ] + make_diff_header('A/B/F', 'working copy',
+                    ] + make_diff_header('A/B/F', 'revision 0',
                                          'working copy',
                                          src_label, dst_label) + [
                       "@@ -0,0 +1 @@\n",
                       "+new text\n",
                     ] + make_diff_prop_header('A/B/F') + \
-                        make_diff_prop_modified("newprop", "propval-old\n",
+                        make_diff_prop_added("newprop",
                                                 "propval-new\n") + \
                     make_diff_header('A/B/lambda', 'working copy',
                                          'working copy',
@@ -3973,7 +3973,7 @@ def diff_two_working_copies(sbox):
                                          src_label, dst_label) + [
                       "@@ -1 +0,0 @@\n",
                       "-This is the file 'pi'.\n",
-                    ] + make_diff_header('A/D/G/pi', 'working copy',
+                    ] + make_diff_header('A/D/G/pi', 'revision 0',
                                          'working copy',
                                          src_label, dst_label) + \
                         make_diff_prop_header('A/D/G/pi') + \
@@ -4047,27 +4047,27 @@ def diff_arbitrary_files_and_dirs(sbox):
                                      '--new', sbox.ospath('A/mu'))
 
   # diff A/B/E with A/D
-  expected_output = make_diff_header("G/pi", "working copy", "working copy",
+  expected_output = make_diff_header("G/pi", "revision 0", "working copy",
                                      "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'pi'.\n"
-                    ] + make_diff_header("G/rho", "working copy",
+                    ] + make_diff_header("G/rho", "revision 0",
                                          "working copy", "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'rho'.\n"
-                    ] + make_diff_header("G/tau", "working copy",
+                    ] + make_diff_header("G/tau", "revision 0",
                                          "working copy", "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'tau'.\n"
-                    ] + make_diff_header("H/chi", "working copy",
+                    ] + make_diff_header("H/chi", "revision 0",
                                          "working copy", "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'chi'.\n"
-                    ] + make_diff_header("H/omega", "working copy",
+                    ] + make_diff_header("H/omega", "revision 0",
                                          "working copy", "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'omega'.\n"
-                    ] + make_diff_header("H/psi", "working copy",
+                    ] + make_diff_header("H/psi", "revision 0",
                                          "working copy", "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'psi'.\n"
@@ -4079,7 +4079,7 @@ def diff_arbitrary_files_and_dirs(sbox):
                                          "working copy", "B/E", "D") + [
                       "@@ -1 +0,0 @@\n",
                       "-This is the file 'beta'.\n"
-                    ] + make_diff_header("gamma", "working copy",
+                    ] + make_diff_header("gamma", "revision 0",
                                          "working copy", "B/E", "D") + [
                       "@@ -0,0 +1 @@\n",
                       "+This is the file 'gamma'.\n"



Mime
View raw message