subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhuij...@apache.org
Subject svn commit: r1103457 - in /subversion/trunk/subversion: include/svn_wc.h libsvn_client/client.h libsvn_client/switch.c libsvn_client/update.c libsvn_wc/deprecated.c libsvn_wc/update_editor.c tests/cmdline/update_tests.py
Date Sun, 15 May 2011 16:54:44 GMT
Author: rhuijben
Date: Sun May 15 16:54:43 2011
New Revision: 1103457

URL: http://svn.apache.org/viewvc?rev=1103457&view=rev
Log:
To make myself useful while I was in the train, I resolved issue #3569 by
detecting this specific case in the update editor and then (and just then)
asking the caller for help, by asking it for a list of current children.

This new code is only active when you pass a --depth to svn update that is
smaller than the ambient depth stored on the target and with depth immediates
the child directories too.
(It is excercised by the depth tests and some update tests).

* subversion/include/svn_wc.h
  (svn_wc_dirents_func_t): New typedef.
  (svn_wc_get_update_editor4,
   svn_wc_get_switch_editor4): Add dirents callback.

* subversion/libsvn_client/client.h
  (svn_client__dirent_fetcher_baton_t): New struct.
  (svn_client__dirent_fetcher): New function.

* subversion/libsvn_client/switch.c
  (switch_internal): Update caller. Pass callback.

* subversion/libsvn_client/update.c
  (svn_client__dirent_fetcher): New function.
  (update_internal): Update caller. Pass calback.

* subversion/libsvn_wc/deprecated.c
  (svn_wc_get_update_editor3,
   svn_wc_get_switch_editor3): Update caller.

* subversion/libsvn_wc/update_editor.c
  (edit_baton): Add variable.
  (close_directory): Check if the edit baton has dirents that we should add
    as not-present children before marking ourself complete.
  (make_editor): Add callback arguments. Detect when we have a too shalow
    update and in that case try to ask the dirents callback for a list of
    children we should ensure we have before marking that directory complete.
  (svn_wc_get_update_editor4,
   svn_wc_get_switch_editor4): Update caller.

* subversion/tests/cmdline/update_tests.py
  (update_empty_hides_entries): Remove XFail marking.

Modified:
    subversion/trunk/subversion/include/svn_wc.h
    subversion/trunk/subversion/libsvn_client/client.h
    subversion/trunk/subversion/libsvn_client/switch.c
    subversion/trunk/subversion/libsvn_client/update.c
    subversion/trunk/subversion/libsvn_wc/deprecated.c
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/tests/cmdline/update_tests.py

Modified: subversion/trunk/subversion/include/svn_wc.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_wc.h?rev=1103457&r1=1103456&r2=1103457&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_wc.h (original)
+++ subversion/trunk/subversion/include/svn_wc.h Sun May 15 16:54:43 2011
@@ -5331,6 +5331,28 @@ typedef svn_error_t *(*svn_wc_get_file_t
                                           apr_pool_t *pool);
 
 /**
+ * A simple callback type to wrap svn_ra_get_dir2() for avoiding issue #3569,
+ * where a directory is updated to a revision without some of its children
+ * recorded in the working copy. A future update won't bring these files in
+ * because the repository assumes they are already there.
+ *
+ * We really only need the names of the dirents for a not-present marking,
+ * but we also store the node-kind if we receive one.
+ *
+ * *dirents should be set to a hash mapping <tt>const char *</tt> child names,
+ * to <tt>const svn_dirent_t *</tt> instances.
+ *
+ * @since New in 1.7.
+ */
+typedef svn_error_t *(*svn_wc_dirents_func_t)(void *baton,
+                                              apr_hash_t **dirents,
+                                              const char *repos_root_url,
+                                              const char *repos_relpath,
+                                              apr_pool_t *result_pool,
+                                              apr_pool_t *scratch_pool);
+
+
+/**
  * Set @a *editor and @a *edit_baton to an editor and baton for updating a
  * working copy.
  *
@@ -5398,6 +5420,10 @@ typedef svn_error_t *(*svn_wc_get_file_t
  * the ambient depth filtering, so this doesn't have to be handled in the
  * editor.
  *
+ * If @a fetch_dirents_func is not NULL, the update editor may call this
+ * callback, when asked to perform a depth restricted update. It will do this
+ * before returning the editor to allow using the primary ra session for this.
+ *
  * @since New in 1.7.
  */
 svn_error_t *
@@ -5415,6 +5441,8 @@ svn_wc_get_update_editor4(const svn_delt
                           svn_boolean_t server_performs_filtering,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
+                          svn_wc_dirents_func_t fetch_dirents_func,
+                          void *fetch_dirents_baton,
                           svn_wc_conflict_resolver_func2_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,
@@ -5446,6 +5474,8 @@ svn_wc_get_update_editor4(const svn_delt
  * This function assumes that @a diff3_cmd is path encoded. Later versions
  * assume utf-8.
  *
+ * Always passes a null dirent function.
+ *
  * @since New in 1.5.
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
@@ -5551,6 +5581,8 @@ svn_wc_get_switch_editor4(const svn_delt
                           svn_boolean_t server_performs_filtering,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
+                          svn_wc_dirents_func_t fetch_dirents_func,
+                          void *fetch_dirents_baton,
                           svn_wc_conflict_resolver_func2_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,

Modified: subversion/trunk/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/client.h?rev=1103457&r1=1103456&r2=1103457&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/client.h (original)
+++ subversion/trunk/subversion/libsvn_client/client.h Sun May 15 16:54:43 2011
@@ -1029,8 +1029,23 @@ svn_client__external_info_gatherer(void 
                                    svn_depth_t depth,
                                    apr_pool_t *scratch_pool);
 
+/* Baton for svn_client__dirent_fetcher */
+struct svn_client__dirent_fetcher_baton_t
+{
+  svn_ra_session_t *ra_session;
+  svn_revnum_t target_revision;
+  const char *anchor_url;
+};
 
-
+/* Implements svn_wc_dirents_func_t for update and switch handling. Assumes
+   a struct svn_client__dirent_fetcher_baton_t * baton */
+svn_error_t *
+svn_client__dirent_fetcher(void *baton,
+                           apr_hash_t **dirents,
+                           const char *repos_root_url,
+                           const char *repos_relpath,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
 
 /* Retrieve log messages using the first provided (non-NULL) callback
    in the set of *CTX->log_msg_func3, CTX->log_msg_func2, or

Modified: subversion/trunk/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/switch.c?rev=1103457&r1=1103456&r2=1103457&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/switch.c (original)
+++ subversion/trunk/subversion/libsvn_client/switch.c Sun May 15 16:54:43 2011
@@ -88,6 +88,7 @@ switch_internal(svn_revnum_t *result_rev
   const char *preserved_exts_str;
   apr_array_header_t *preserved_exts;
   svn_boolean_t server_supports_depth;
+  struct svn_client__dirent_fetcher_baton_t dfb;
   svn_client__external_func_baton_t efb;
   svn_config_t *cfg = ctx->config ? apr_hash_get(ctx->config,
                                                  SVN_CONFIG_CATEGORY_CONFIG,
@@ -231,6 +232,10 @@ switch_internal(svn_revnum_t *result_rev
   SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                 SVN_RA_CAPABILITY_DEPTH, pool));
 
+  dfb.ra_session = ra_session;
+  SVN_ERR(svn_ra_get_session_url(ra_session, &dfb.anchor_url, pool));
+  dfb.target_revision = revnum;
+
   SVN_ERR(svn_wc_get_switch_editor4(&switch_editor, &switch_edit_baton,
                                     &revnum, ctx->wc_ctx, anchor_abspath,
                                     target, switch_rev_url, use_commit_times,
@@ -238,6 +243,7 @@ switch_internal(svn_revnum_t *result_rev
                                     depth_is_sticky, allow_unver_obstructions,
                                     server_supports_depth,
                                     diff3_cmd, preserved_exts,
+                                    svn_client__dirent_fetcher, &dfb,
                                     ctx->conflict_func2, ctx->conflict_baton2,
                                     svn_client__external_info_gatherer, &efb,
                                     ctx->cancel_func, ctx->cancel_baton,

Modified: subversion/trunk/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/update.c?rev=1103457&r1=1103456&r2=1103457&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/update.c (original)
+++ subversion/trunk/subversion/libsvn_client/update.c Sun May 15 16:54:43 2011
@@ -41,6 +41,54 @@
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
 
+/* Implements svn_wc_dirents_func_t for update and switch handling. Assumes
+   a struct svn_client__dirent_fetcher_baton_t * baton */
+svn_error_t *
+svn_client__dirent_fetcher(void *baton,
+                           apr_hash_t **dirents,
+                           const char *repos_root_url,
+                           const char *repos_relpath,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  struct svn_client__dirent_fetcher_baton_t *dfb = baton;
+  const char *old_url = NULL;
+  const char *session_relpath;
+  svn_node_kind_t kind;
+  const char *url;
+
+  url = svn_path_url_add_component2(repos_root_url, repos_relpath,
+                                    scratch_pool);
+
+  if (!svn_uri_is_ancestor(dfb->anchor_url, url))
+    {
+      SVN_ERR(svn_client__ensure_ra_session_url(&old_url, dfb->ra_session,
+                                                url, scratch_pool));
+      session_relpath = "";
+    }
+  else
+    SVN_ERR(svn_ra_get_path_relative_to_session(dfb->ra_session,
+                                                &session_relpath, url,
+                                                scratch_pool));
+
+  /* Is session_relpath still a directory? */
+  SVN_ERR(svn_ra_check_path(dfb->ra_session, session_relpath,
+                            dfb->target_revision, &kind, scratch_pool));
+
+  if (kind == svn_node_dir)
+    SVN_ERR(svn_ra_get_dir2(dfb->ra_session, dirents, NULL, NULL,
+                            session_relpath, dfb->target_revision,
+                            SVN_DIRENT_KIND, result_pool));
+  else
+    *dirents = NULL;
+
+  if (old_url)
+    SVN_ERR(svn_client__ensure_ra_session_url(&old_url, dfb->ra_session,
+                                              old_url, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 /*** Code. ***/
 
@@ -91,6 +139,7 @@ update_internal(svn_revnum_t *result_rev
   const char *preserved_exts_str;
   apr_array_header_t *preserved_exts;
   svn_client__external_func_baton_t efb;
+  struct svn_client__dirent_fetcher_baton_t dfb;
   svn_boolean_t server_supports_depth;
   svn_config_t *cfg = ctx->config ? apr_hash_get(ctx->config,
                                                  SVN_CONFIG_CATEGORY_CONFIG,
@@ -202,12 +251,24 @@ update_internal(svn_revnum_t *result_rev
                                                anchor_abspath, NULL, TRUE,
                                                TRUE, ctx, pool));
 
+  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, pool));
+
   /* If we got a corrected URL from the RA subsystem, we'll need to
      relocate our working copy first. */
   if (corrected_url)
     {
-      SVN_ERR(svn_client_relocate2(anchor_abspath, anchor_url, corrected_url,
-                                   TRUE, ctx, pool));
+      const char *current_repos_root;
+      const char *current_uuid;
+
+      /* To relocate everything inside our repository we need the old and new
+         repos root. ### And we should only perform relocates on the wcroot */
+      SVN_ERR(svn_wc__node_get_repos_info(&current_repos_root, &current_uuid,
+                                          ctx->wc_ctx, anchor_abspath,
+                                          pool, pool));
+
+      /* ### Check uuid here before calling relocate? */
+      SVN_ERR(svn_client_relocate2(anchor_abspath, current_repos_root,
+                                   repos_root, ignore_externals, ctx, pool));
       anchor_url = corrected_url;
     }
 
@@ -217,12 +278,6 @@ update_internal(svn_revnum_t *result_rev
                                           local_abspath, ra_session, revision,
                                           pool));
 
-  /* Take the chance to set the repository root on the target.
-     It's nice to get this information into old WCs so they are "ready"
-     when we start depending on it.  (We can never *depend* upon it in
-     a strict sense, however.) */
-  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, pool));
-
   /* Build a baton for the externals-info-gatherer callback. */
   efb.externals_new = apr_hash_make(pool);
   efb.externals_old = apr_hash_make(pool);
@@ -232,6 +287,10 @@ update_internal(svn_revnum_t *result_rev
   SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                 SVN_RA_CAPABILITY_DEPTH, pool));
 
+  dfb.ra_session = ra_session;
+  dfb.target_revision = revnum;
+  dfb.anchor_url = anchor_url;
+
   /* Fetch the update editor.  If REVISION is invalid, that's okay;
      the RA driver will call editor->set_target_revision later on. */
   SVN_ERR(svn_wc_get_update_editor4(&update_editor, &update_edit_baton,
@@ -241,6 +300,7 @@ update_internal(svn_revnum_t *result_rev
                                     adds_as_modification,
                                     server_supports_depth,
                                     diff3_cmd, preserved_exts,
+                                    svn_client__dirent_fetcher, &dfb,
                                     ctx->conflict_func2, ctx->conflict_baton2,
                                     ignore_externals
                                         ? NULL

Modified: subversion/trunk/subversion/libsvn_wc/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/deprecated.c?rev=1103457&r1=1103456&r2=1103457&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_wc/deprecated.c Sun May 15 16:54:43 2011
@@ -3099,6 +3099,7 @@ svn_wc_get_update_editor3(svn_revnum_t *
                                     FALSE /* server_performs_filtering */,
                                     diff3_cmd,
                                     preserved_exts,
+                                    NULL, NULL, /* fetch_dirents_func, baton */
                                     conflict_func ? conflict_func_1to2_wrapper
                                                   : NULL,
                                     cfw,
@@ -3229,6 +3230,7 @@ svn_wc_get_switch_editor3(svn_revnum_t *
                                     FALSE /* server_performs_filtering */,
                                     diff3_cmd,
                                     preserved_exts,
+                                    NULL, NULL, /* fetch_dirents_func, baton */
                                     conflict_func ? conflict_func_1to2_wrapper
                                                   : NULL,
                                     cfw,

Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1103457&r1=1103456&r2=1103457&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Sun May 15 16:54:43 2011
@@ -230,6 +230,12 @@ struct edit_baton
      relative to the working copy root and the values unspecified. */
   apr_hash_t *skipped_trees;
 
+  /* A mapping from const char * repos_relpaths to the apr_hash_t * instances
+     returned from fetch_dirents_func for that repos_relpath. These
+     are used to avoid issue #3569 in specific update scenarios where a
+     restricted depth is used. */
+  apr_hash_t *dir_dirents;
+
   /* Absolute path of the working copy root or NULL if not initialized yet */
   const char *wcroot_abspath;
 
@@ -2442,6 +2448,84 @@ close_directory(void *dir_baton,
                                      scratch_pool, scratch_pool));
     }
 
+  /* Check if we should add some not-present markers before marking the
+     directory complete (Issue #3569) */
+  {
+    apr_hash_t *new_children = apr_hash_get(eb->dir_dirents, db->new_relpath,
+                                            APR_HASH_KEY_STRING);
+
+    if (new_children != NULL)
+      {
+        apr_hash_index_t *hi;
+        apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+        for (hi = apr_hash_first(scratch_pool, new_children);
+             hi;
+             hi = apr_hash_next(hi))
+          {
+            const char *child_name;
+            const char *child_abspath;
+            const char *child_relpath;
+            const svn_dirent_t *dirent;
+            svn_wc__db_status_t status;
+            svn_wc__db_kind_t child_kind;
+            svn_error_t *err;
+
+            svn_pool_clear(iterpool);
+
+            child_name = svn__apr_hash_index_key(hi);
+            child_abspath = svn_dirent_join(db->local_abspath, child_name,
+                                            iterpool);
+
+            dirent = svn__apr_hash_index_val(hi);
+            child_kind = (dirent->kind == svn_node_dir)
+                                        ? svn_wc__db_kind_dir
+                                        : svn_wc__db_kind_file;
+
+            if (db->ambient_depth < svn_depth_immediates
+                && child_kind == svn_wc__db_kind_dir)
+              continue; /* We don't need the subdirs */
+
+            /* ### We just check if there is some node in BASE at this path */
+            err = svn_wc__db_base_get_info(&status, NULL, NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL, NULL,
+                                           eb->db, child_abspath,
+                                           iterpool, iterpool);
+
+            if (!err)
+              {
+                svn_boolean_t is_wcroot;
+                SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, eb->db, child_abspath,
+                                             iterpool));
+
+                if (!is_wcroot)
+                  continue; /* Everything ok... Nothing to do here */
+                /* Fall through to allow recovering later */
+              }
+            else if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+              return svn_error_return(err);
+
+            svn_error_clear(err);
+
+            child_relpath = svn_relpath_join(db->new_relpath, child_name,
+                                             iterpool);
+
+            SVN_ERR(svn_wc__db_base_add_not_present_node(eb->db,
+                                                         child_abspath,
+                                                         child_relpath,
+                                                         eb->repos_root,
+                                                         eb->repos_uuid,
+                                                         *eb->target_revision,
+                                                         child_kind,
+                                                         NULL, NULL,
+                                                         iterpool));
+          }
+
+        svn_pool_destroy(iterpool);
+      }
+  }
+
   /* If this directory is merely an anchor for a targeted child, then we
      should not be updating the node at all.  */
   if (db->parent_baton == NULL
@@ -2454,7 +2538,6 @@ close_directory(void *dir_baton,
     }
   else
     {
-      svn_depth_t depth;
       svn_revnum_t changed_rev;
       apr_time_t changed_date;
       const char *changed_author;
@@ -2468,7 +2551,7 @@ close_directory(void *dir_baton,
                                        &changed_rev,
                                        &changed_date,
                                        &changed_author,
-                                       &depth, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL,
                                        NULL, NULL,
                                        eb->db, db->local_abspath,
                                        scratch_pool, scratch_pool));
@@ -2482,11 +2565,11 @@ close_directory(void *dir_baton,
         changed_author = new_changed_author;
 
       /* If no depth is set yet, set to infinity. */
-      if (depth == svn_depth_unknown)
-        depth = svn_depth_infinity;
+      if (db->ambient_depth == svn_depth_unknown)
+        db->ambient_depth = svn_depth_infinity;
 
       if (eb->depth_is_sticky
-          && depth != eb->requested_depth)
+          && db->ambient_depth != eb->requested_depth)
         {
           /* After a depth upgrade the entry must reflect the new depth.
              Upgrading to infinity changes the depth of *all* directories,
@@ -2494,9 +2577,9 @@ close_directory(void *dir_baton,
 
           if (eb->requested_depth == svn_depth_infinity
               || (strcmp(db->local_abspath, eb->target_abspath) == 0
-                  && eb->requested_depth > depth))
+                  && eb->requested_depth > db->ambient_depth))
             {
-              depth = eb->requested_depth;
+              db->ambient_depth = eb->requested_depth;
             }
         }
 
@@ -2517,7 +2600,7 @@ close_directory(void *dir_baton,
                 props,
                 changed_rev, changed_date, changed_author,
                 NULL /* children */,
-                depth,
+                db->ambient_depth,
                 (dav_prop_changes->nelts > 0)
                     ? svn_prop_array_to_hash(dav_prop_changes, pool)
                     : NULL,
@@ -4216,6 +4299,8 @@ make_editor(svn_revnum_t *target_revisio
             void *notify_baton,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
+            svn_wc_dirents_func_t fetch_dirents_func,
+            void *fetch_dirents_baton,
             svn_wc_conflict_resolver_func2_t conflict_func,
             void *conflict_baton,
             svn_wc_external_update_t external_func,
@@ -4295,6 +4380,7 @@ make_editor(svn_revnum_t *target_revisio
   eb->allow_unver_obstructions = allow_unver_obstructions;
   eb->adds_as_modification     = adds_as_modification;
   eb->skipped_trees            = apr_hash_make(edit_pool);
+  eb->dir_dirents              = apr_hash_make(edit_pool);
   eb->ext_patterns             = preserved_exts;
 
   apr_pool_cleanup_register(edit_pool, eb, cleanup_edit_baton,
@@ -4321,6 +4407,116 @@ make_editor(svn_revnum_t *target_revisio
   inner_editor = tree_editor;
   inner_baton = eb;
 
+  if (!depth_is_sticky
+      && depth != svn_depth_unknown
+      && svn_depth_empty <= depth && depth < svn_depth_infinity
+      && fetch_dirents_func)
+    {
+      /* We are asked to perform an update at a depth less than the ambient
+         depth. In this case the update won't describe additions that would
+         have been reported if we updated at the ambient depth. */
+      svn_error_t *err;
+      svn_wc__db_kind_t dir_kind;
+      svn_wc__db_status_t dir_status;
+      const char *dir_repos_relpath;
+      svn_depth_t dir_depth;
+
+      /* we have to do this on the target of the update, not the anchor */
+      err = svn_wc__db_base_get_info(&dir_status, &dir_kind, NULL,
+                                     &dir_repos_relpath, NULL, NULL, NULL,
+                                     NULL, NULL, &dir_depth, NULL, NULL, NULL,
+                                     NULL, NULL, NULL,
+                                     db, eb->target_abspath,
+                                     scratch_pool, scratch_pool);
+
+      if (!err
+          && dir_kind == svn_wc__db_kind_dir
+          && dir_status == svn_wc__db_status_normal)
+        {
+          if (dir_depth > depth)
+            {
+              apr_hash_t *dirents;
+
+              /* If we switch, we should look at the new relpath */
+              if (eb->switch_relpath)
+                dir_repos_relpath = eb->switch_relpath;
+
+              SVN_ERR(fetch_dirents_func(fetch_dirents_baton, &dirents,
+                                         repos_root, dir_repos_relpath,
+                                         edit_pool, scratch_pool));
+
+              if (dirents != NULL && apr_hash_count(dirents))
+                apr_hash_set(eb->dir_dirents,
+                             apr_pstrdup(edit_pool, dir_repos_relpath),
+                             APR_HASH_KEY_STRING,
+                             dirents);
+            }
+
+          if (depth == svn_depth_immediates)
+            {
+              /* Worst case scenario of issue #3569 fix: We have to do the
+                 same for all existing subdirs, but then we check for
+                 svn_depth_empty. */
+              apr_array_header_t *children;
+              apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+              int i;
+              SVN_ERR(svn_wc__db_base_get_children(&children, db,
+                                                   eb->target_abspath,
+                                                   scratch_pool,
+                                                   iterpool));
+
+              for (i = 0; i < children->nelts; i++)
+                {
+                  const char *child_abspath;
+                  const char *child_name;
+
+                  svn_pool_clear(iterpool);
+
+                  child_name = APR_ARRAY_IDX(children, i, const char *);
+
+                  child_abspath = svn_dirent_join(eb->target_abspath,
+                                                  child_name, iterpool);
+
+                  SVN_ERR(svn_wc__db_base_get_info(&dir_status, &dir_kind,
+                                                   NULL, &dir_repos_relpath,
+                                                   NULL, NULL, NULL, NULL,
+                                                   NULL, &dir_depth, NULL,
+                                                   NULL, NULL, NULL, NULL,
+                                                   NULL,
+                                                   db, child_abspath,
+                                                   iterpool, iterpool));
+
+                  if (dir_kind == svn_wc__db_kind_dir
+                      && dir_status == svn_wc__db_status_normal
+                      && dir_depth > svn_depth_empty)
+                    {
+                      apr_hash_t *dirents;
+
+                      /* If we switch, we should look at the new relpath */
+                      if (eb->switch_relpath)
+                        dir_repos_relpath = svn_relpath_join(
+                                                eb->switch_relpath,
+                                                child_name, iterpool);
+
+                      SVN_ERR(fetch_dirents_func(fetch_dirents_baton, &dirents,
+                                                 repos_root, dir_repos_relpath,
+                                                 edit_pool, iterpool));
+
+                      if (dirents != NULL && apr_hash_count(dirents))
+                        apr_hash_set(eb->dir_dirents,
+                                     apr_pstrdup(edit_pool, dir_repos_relpath),
+                                     APR_HASH_KEY_STRING,
+                                     dirents);
+                    }
+                }
+            }
+        }
+      else if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        svn_error_clear(err);
+      else
+        SVN_ERR(err);
+    }
+
   /* We need to limit the scope of our operation to the ambient depths
      present in the working copy already, but only if the requested
      depth is not sticky. If a depth was explicitly requested,
@@ -4366,6 +4562,8 @@ svn_wc_get_update_editor4(const svn_delt
                           svn_boolean_t server_performs_filtering,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
+                          svn_wc_dirents_func_t fetch_dirents_func,
+                          void *fetch_dirents_baton,
                           svn_wc_conflict_resolver_func2_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,
@@ -4383,6 +4581,7 @@ svn_wc_get_update_editor4(const svn_delt
                      adds_as_modification, server_performs_filtering,
                      notify_func, notify_baton,
                      cancel_func, cancel_baton,
+                     fetch_dirents_func, fetch_dirents_baton,
                      conflict_func, conflict_baton,
                      external_func, external_baton,
                      diff3_cmd, preserved_exts, editor, edit_baton,
@@ -4404,6 +4603,8 @@ svn_wc_get_switch_editor4(const svn_delt
                           svn_boolean_t server_performs_filtering,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
+                          svn_wc_dirents_func_t fetch_dirents_func,
+                          void *fetch_dirents_baton,
                           svn_wc_conflict_resolver_func2_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,
@@ -4425,6 +4626,7 @@ svn_wc_get_switch_editor4(const svn_delt
                      server_performs_filtering,
                      notify_func, notify_baton,
                      cancel_func, cancel_baton,
+                     fetch_dirents_func, fetch_dirents_baton,
                      conflict_func, conflict_baton,
                      external_func, external_baton,
                      diff3_cmd, preserved_exts,

Modified: subversion/trunk/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/update_tests.py?rev=1103457&r1=1103456&r2=1103457&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/update_tests.py Sun May 15 16:54:43 2011
@@ -5156,11 +5156,6 @@ def update_deleted_locked_files(sbox):
 #----------------------------------------------------------------------
 # Test for issue #3569 svn update --depth <DEPTH> allows making a working
 # copy incomplete.
-#
-# XFail until issue #3569 is fixed.  This test needs extension to map some
-# real use cases (all add operations are missing if a directory is updated
-# without its children.)
-@XFail()
 @Issue(3569)
 def update_empty_hides_entries(sbox):
   "svn up --depth empty hides entries for next update"



Mime
View raw message