All pastes #709865 Raw Edit

Something

public text v1 · immutable
#709865 ·published 2007-09-25 01:21 UTC
rendered paste body
[[[
                ### PATCH IN PROGRESS, DO NOT COMMIT ###

Filter ambient depth as well as requested depth.
For issue #2842 and issue #695.

* subversion/libsvn_wc/update_editor.c
  (struct edit_baton): Document that 'depth' is requested depth.
  (struct file_baton): Add new 'depth' field.
  (make_dir_baton, make_file_baton): Add code to detect depth
    situation and flag whether or not this baton is the end of the
    line by setting the depth field appropriately.  Return new baton
    by reference, to enable returning an error directly if the new
    code raises an error.
  (open_directory, open_root, add_file_with_history, delete_entry,
   change_dir_prop, close_directory, absent_file_or_dir, apply_textdelta,
   change_file_prop): Adjust for above.
  (add_directory, open_file, add_file): Same.  Note that this changes
    the semantics slightly: previously, the new baton pointer might
    have remained untouched if we returned early due to an error.  But
    now it will definitely have been set.  I don't think any callers
    care about this; the previous behavior was just an accident of how
    the code was written.
]]]

Index: subversion/libsvn_wc/update_editor.c
===================================================================
--- subversion/libsvn_wc/update_editor.c	(revision 26768)
+++ subversion/libsvn_wc/update_editor.c	(working copy)
@@ -89,7 +89,7 @@
      pointing to the final revision. */
   svn_revnum_t *target_revision;
 
-  /* The depth of this edit */
+  /* The requested depth of this edit */
   svn_depth_t depth;
 
   /* Need to know if the user wants us to overwrite the 'now' times on
@@ -193,7 +193,12 @@
   /* The current log buffer. */
   svn_stringbuf_t *log_accum;
 
-  /* The working copy depth of the directory. */
+  /* The working copy depth of the directory.
+
+     If this is svn_depth_exclude, then all other fields in this
+     structure are undefined, and no editor calls at or below this
+     directory should have any effect -- they should return
+     immediately with SVN_NO_ERROR. */ 
   svn_depth_t depth;
 
   /* The pool in which this baton itself is allocated. */
@@ -338,20 +343,74 @@
 /* Return a new dir_baton to represent NAME (a subdirectory of
    PARENT_BATON).  If PATH is NULL, this is the root directory of the
    edit. */
-static struct dir_baton *
-make_dir_baton(const char *path,
+static svn_error_t *
+make_dir_baton(struct dir_baton **d_p,
+               const char *path,
                struct edit_baton *eb,
                struct dir_baton *pb,
                svn_boolean_t added,
                apr_pool_t *pool)
 {
-  struct dir_baton *d = apr_pcalloc(pool, sizeof(*d));
+  struct dir_baton *d;
   struct bump_dir_info *bdi;
 
   /* Don't do this.  Just do NOT do this to me. */
   if (pb && (! path))
     abort();
 
+  if (pb && pb->depth == svn_depth_exclude)
+    {
+      /* Just re-use the parent baton, since the only field that
+         matters is depth==svn_depth_exclude. */
+      *d_p = pb;
+      return SVN_NO_ERROR;
+    }
+
+  /* Okay, no easy out, so allocate and initialize a dir baton. */
+  d = apr_pcalloc(pool, sizeof(*d));
+
+  /* Construct the PATH and baseNAME of this directory. */
+  d->path = apr_pstrdup(pool, eb->anchor);
+  if (path)
+    {
+      d->path = svn_path_join(d->path, path, pool);
+      d->name = svn_path_basename(path, pool);
+    }
+  else
+    {
+      d->name = NULL;
+    }
+
+  if (eb->depth == svn_depth_unknown
+      && pb && pb->depth == svn_depth_empty)
+    {
+      /* This is not a depth upgrade, and the parent directory is
+         depth==empty.  So if the parent doesn't already have an entry
+         for the new dir, then the parent doesn't want the new dir at
+         all, thus we should initialize it at svn_depth_exclude. */
+      svn_error_t *err;
+      const svn_wc_entry_t *entry;
+      svn_wc_adm_access_t *adm_access;
+      
+      err = svn_wc_adm_retrieve(&adm_access, eb->adm_access, d->path, pool);
+      if (err)
+        {
+          svn_error_clear(err);
+          d->depth = svn_depth_exclude;
+          *d_p = d;
+          return SVN_NO_ERROR;
+        }
+
+      err = svn_wc_entry(&entry, d->path, adm_access, FALSE, pool);
+      if (err)
+        {
+          svn_error_clear(err);
+          d->depth = svn_depth_exclude;
+          *d_p = d;
+          return SVN_NO_ERROR;
+        }
+    }
+
   if (added)
     {
       if (strcmp(eb->target, path) == 0)
@@ -379,18 +438,6 @@
       d->depth = svn_depth_infinity;
     }
 
-  /* Construct the PATH and baseNAME of this directory. */
-  d->path = apr_pstrdup(pool, eb->anchor);
-  if (path)
-    {
-      d->path = svn_path_join(d->path, path, pool);
-      d->name = svn_path_basename(path, pool);
-    }
-  else
-    {
-      d->name = NULL;
-    }
-
   /* Figure out the new_URL for this directory. */
   if (eb->switch_url)
     {
@@ -454,7 +501,8 @@
   apr_pool_cleanup_register(d->pool, d, cleanup_dir_baton,
                             cleanup_dir_baton_child);
 
-  return d;
+  *d_p = d;
+  return SVN_NO_ERROR;
 }
 
 
@@ -671,13 +719,22 @@
      last window is handled by the handler returned from
      apply_textdelta(). */
   unsigned char digest[APR_MD5_DIGESTSIZE];
+
+  /* Files don't have depth, this field just signifies whether editor
+     calls on this file should be ignored for depth reasons.  If this
+     is svn_depth_exclude, then all other fields in this baton are
+     undefined and no editor call should do anything with this file.
+     If it is any other value, proceed as usual. */
+  svn_depth_t depth;
 };
 
 
 /* Make a new file baton in the provided POOL, with PB as the parent baton.
    PATH is relative to the root of the edit. */
-static struct file_baton *
-make_file_baton(struct dir_baton *pb,
+
+static svn_error_t *
+make_file_baton(struct file_baton **f_p,
+                struct dir_baton *pb,
                 const char *path,
                 svn_boolean_t adding,
                 apr_pool_t *pool)
@@ -688,10 +745,49 @@
   if (! path)
     abort();
 
+  /* If parent is being ignored, then everything under it is too. */
+  if (pb->depth == svn_depth_exclude)
+    {
+      f->depth = svn_depth_exclude;
+      *f_p = f;
+      return SVN_NO_ERROR;
+    }
+
   /* Make the file's on-disk name. */
   f->path = svn_path_join(pb->edit_baton->anchor, path, pool);
   f->name = svn_path_basename(path, pool);
 
+  if (pb->edit_baton->depth == svn_depth_unknown
+      && pb->depth == svn_depth_empty)
+    {
+      /* This is not a depth upgrade, and the parent directory is
+         depth==empty.  So if the parent doesn't already have an entry
+         for the file, then the parent doesn't want to hear about the
+         file at all, thus we should initialize it at svn_depth_exclude. */
+      svn_error_t *err;
+      const svn_wc_entry_t *entry;
+      svn_wc_adm_access_t *adm_access;
+      
+      err = svn_wc_adm_retrieve(&adm_access, pb->edit_baton->adm_access,
+                                f->path, pool);
+      if (err)
+        {
+          svn_error_clear(err);
+          f->depth = svn_depth_exclude;
+          *f_p = f;
+          return SVN_NO_ERROR;
+        }
+
+      err = svn_wc_entry(&entry, f->path, adm_access, FALSE, pool);
+      if (err)
+        {
+          svn_error_clear(err);
+          f->depth = svn_depth_exclude;
+          *f_p = f;
+          return SVN_NO_ERROR;
+        }
+    }
+
   /* Figure out the new_URL for this file. */
   if (pb->edit_baton->switch_url)
     {
@@ -712,13 +808,15 @@
   f->add_existed  = FALSE;
   f->send_notification = TRUE;
   f->dir_baton    = pb;
+  f->depth        = svn_depth_empty;
 
   /* No need to initialize f->digest, since we used pcalloc(). */
 
   /* the directory's bump info has one more referer now */
   ++f->bump_info->ref_count;
 
-  return f;
+  *f_p = f;
+  return SVN_NO_ERROR;
 }
 
 
@@ -1005,7 +1103,12 @@
      edit run. */
   eb->root_opened = TRUE;
 
-  *dir_baton = d = make_dir_baton(NULL, eb, NULL, FALSE, pool);
+  SVN_ERR(make_dir_baton(&d, NULL, eb, NULL, FALSE, pool));
+  *dir_baton = d;
+
+  if (d->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   if (! *eb->target)
     {
       /* For an update with a NULL target, this is equivalent to open_dir(): */
@@ -1187,6 +1290,10 @@
              apr_pool_t *pool)
 {
   struct dir_baton *pb = parent_baton;
+
+  if (pb->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   SVN_ERR(check_path_under_root(pb->path, svn_path_basename(path, pool),
                                 pool));
   return do_entry_deletion(pb->edit_baton, pb->path, path, &pb->log_number,
@@ -1204,9 +1311,15 @@
 {
   struct dir_baton *pb = parent_baton;
   struct edit_baton *eb = pb->edit_baton;
-  struct dir_baton *db = make_dir_baton(path, eb, pb, TRUE, pool);
+  struct dir_baton *db;
   svn_node_kind_t kind;
 
+  SVN_ERR(make_dir_baton(&db, path, eb, pb, TRUE, pool));
+  *child_baton = db;
+
+  if (db->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   /* Flush the log for the parent directory before going into this subtree. */
   SVN_ERR(flush_log(pb, pool));
 
@@ -1374,8 +1487,6 @@
                          *(eb->target_revision),
                          db->pool));
 
-  *child_baton = db;
-
   /* If this add was obstructed by dir scheduled for addition without
      history let close_file() handle the notification because there
      might be properties to deal with. */
@@ -1410,16 +1521,15 @@
 
   svn_wc_adm_access_t *adm_access;
 
+  SVN_ERR(make_dir_baton(&db, path, eb, pb, FALSE, pool));
+  *child_baton = db;
+
+  if (db->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   /* Flush the log for the parent directory before going into this subtree. */
   SVN_ERR(flush_log(pb, pool));
 
-  /* kff todo: check that the dir exists locally, find it somewhere if
-     its not there?  Yes, all this and more...  And ancestor_url and
-     ancestor_revision need to get used. */
-
-  db = make_dir_baton(path, eb, pb, FALSE, pool);
-  *child_baton = db;
-
   SVN_ERR(check_path_under_root(pb->path, db->name, pool));
 
   /* Skip this directory if it has property conflicts. */
@@ -1487,6 +1597,9 @@
   svn_prop_t *propchange;
   struct dir_baton *db = dir_baton;
 
+  if (db->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   if (db->bump_info->skipped)
     return SVN_NO_ERROR;
 
@@ -1527,6 +1640,9 @@
   apr_array_header_t *entry_props, *wc_props, *regular_props;
   svn_wc_adm_access_t *adm_access;
 
+  if (db->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   SVN_ERR(svn_categorize_props(db->propchanges, &entry_props, &wc_props,
                                &regular_props, pool));
 
@@ -1654,6 +1770,9 @@
   const svn_wc_entry_t *ent;
   svn_wc_entry_t tmp_entry;
 
+  if (pb->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   /* Extra check: an item by this name may not exist, but there may
      still be one scheduled for addition.  That's a genuine
      tree-conflict.  */
@@ -1753,8 +1872,12 @@
      use a subpool for any temporary allocations. */
   subpool = svn_pool_create(pool);
 
-  fb = make_file_baton(pb, path, TRUE, pool);
+  SVN_ERR(make_file_baton(&fb, pb, path, TRUE, pool));
+  *file_baton = fb;
 
+  if (fb->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   SVN_ERR(check_path_under_root(fb->dir_baton->path, fb->name, subpool));
 
   /* It is interesting to note: everything below is just validation. We
@@ -1822,7 +1945,6 @@
 
   svn_pool_destroy(subpool);
 
-  *file_baton = fb;
   return SVN_NO_ERROR;
 }
 
@@ -1847,8 +1969,12 @@
      a subpool for any temporary allocations. */
   apr_pool_t *subpool = svn_pool_create(pool);
 
-  fb = make_file_baton(pb, path, FALSE, pool);
+  SVN_ERR(make_file_baton(&fb, pb, path, FALSE, pool));
+  *file_baton = fb;
 
+  if (fb->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   SVN_ERR(check_path_under_root(fb->dir_baton->path, fb->name, subpool));
 
   /* It is interesting to note: everything below is just validation. We
@@ -1894,7 +2020,6 @@
 
   svn_pool_destroy(subpool);
 
-  *file_baton = fb;
   return SVN_NO_ERROR;
 }
 
@@ -1916,7 +2041,7 @@
   svn_boolean_t replaced;
   svn_boolean_t use_revert_base;
 
-  if (fb->skipped)
+  if (fb->skipped || fb->depth == svn_depth_exclude)
     {
       *handler = svn_delta_noop_window_handler;
       *handler_baton = NULL;
@@ -2057,7 +2182,7 @@
   struct edit_baton *eb = fb->edit_baton;
   svn_prop_t *propchange;
 
-  if (fb->skipped)
+  if (fb->skipped || fb->depth == svn_depth_exclude)
     return SVN_NO_ERROR;
 
   /* Push a new propchange to the file baton's array of propchanges */
@@ -2550,6 +2675,9 @@
   svn_wc_notify_state_t content_state, prop_state;
   svn_wc_notify_lock_state_t lock_state;
 
+  if (fb->depth == svn_depth_exclude)
+    return SVN_NO_ERROR;
+
   if (fb->skipped)
     {
       SVN_ERR(maybe_bump_dir_info(eb, fb->bump_info, pool));
@@ -2640,6 +2768,12 @@
   SVN_ERR(add_file(path, parent_baton, NULL, SVN_INVALID_REVNUM, pool, &fb));
   tfb = (struct file_baton *)fb;
 
+  if (tfb->depth == svn_depth_exclude)
+    {
+      *file_baton = tfb;
+      return SVN_NO_ERROR;
+    }
+
   /* Initialize the text-bases for an incoming file, the same way
      apply_textdelta() does. */
   tfb->text_base_path = svn_wc__text_base_path(tfb->path, FALSE, tfb->pool);
@@ -2687,11 +2821,17 @@
      editor-driver needs a file_baton that can be safely passed to
      apply_textdelta(), which means re-opening the file. */
   SVN_ERR(open_file(path, parent_baton, SVN_INVALID_REVNUM, pool, &fb));
+  tfb = (struct file_baton *)fb;
 
+  if (tfb->depth == svn_depth_exclude)
+    {
+      *file_baton = tfb;
+      return SVN_NO_ERROR;
+    }
+
   /* We don't want this trailing open_file()/close_file() combo to be
      signaled to the client, however.  The general policy is to call
      the notification callback only -once- per file. */
-  tfb = (struct file_baton *)fb;
   tfb->send_notification = FALSE;
 
   *file_baton = tfb;