Author: rhuijben
Date: Sun May  8 09:06:31 2011
New Revision: 1100708

URL: http://svn.apache.org/viewvc?rev=1100708&view=rev
Log:
Plug the accidentally reopened hole that allowed us to introduce file
externals in 1.6: stop allowing switching uncommitted paths.

File externals are introduced in a much cleaner way now, and this scenario
wasn't supported in 1.6 either.

* subversion/include/private/svn_wc_private.h
  (svn_wc__node_has_working): New function.

* subversion/libsvn_client/switch.c
  (switch_internal): Allow all excluded switches, not just sticky ones.
    Deny switch targets that are shadowed and/or do not exist in BASE.
    Add note on svn_client__get_youngest_common_ancestor.

* subversion/libsvn_wc/node.c
  (svn_wc__node_has_working): New function.

* subversion/libsvn_wc/update_editor.c
  (make_editor): Use db argument and just use svn_wc__db_scan_base_repos,
    which also performs a does exist in BASE check for us.
  (svn_wc_get_update_editor4,
   svn_wc_get_switch_editor4): Update caller.

* subversion/tests/cmdline/switch_tests.py
  (switch_scheduled_add): Expect a proper error instead of accepting a tree
    conflict as success.

Modified:
    subversion/trunk/subversion/include/private/svn_wc_private.h
    subversion/trunk/subversion/libsvn_client/switch.c
    subversion/trunk/subversion/libsvn_wc/node.c
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/tests/cmdline/switch_tests.py

Modified: subversion/trunk/subversion/include/private/svn_wc_private.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_wc_private.h?rev=1100708&r1=1100707&r2=1100708&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_wc_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_wc_private.h Sun May  8 
09:06:31 2011
@@ -401,6 +401,19 @@ svn_wc__node_is_added(svn_boolean_t *is_
                       apr_pool_t *scratch_pool);
 
 /**
+ * Set @a *has_working to whether @a local_abspath has a working node (which
+ * might shadow BASE nodes)
+ *
+ * This is a check similar to status = added or status = deleted.
+ */
+svn_error_t *
+svn_wc__node_has_working(svn_boolean_t *has_working,
+                         svn_wc_context_t *wc_ctx,
+                         const char *local_abspath,
+                         apr_pool_t *scratch_pool);
+
+
+/**
  * Get the base revision of @a local_abspath using @a wc_ctx.  If
  * @a local_abspath is not in the working copy, return
  * @c SVN_ERR_WC_PATH_NOT_FOUND.

Modified: subversion/trunk/subversion/libsvn_client/switch.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/switch.c?rev=1100708&r1=1100707&r2=1100708&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/switch.c (original)
+++ subversion/trunk/subversion/libsvn_client/switch.c Sun May  8 09:06:31 2011
@@ -99,7 +99,7 @@ switch_internal(svn_revnum_t *result_rev
     depth_is_sticky = FALSE;
 
   /* Do not support the situation of both exclude and switch a target. */
-  if (depth_is_sticky && depth == svn_depth_exclude)
+  if (depth == svn_depth_exclude)
     return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                              _("Cannot both exclude and switch a path"));
 
@@ -115,6 +115,18 @@ switch_internal(svn_revnum_t *result_rev
                               SVN_CONFIG_SECTION_MISCELLANY,
                               SVN_CONFIG_OPTION_USE_COMMIT_TIMES, FALSE));
 
+  {
+    svn_boolean_t has_working;
+    SVN_ERR(svn_wc__node_has_working(&has_working, ctx->wc_ctx, local_abspath,
+                                     pool));
+
+    if (has_working)
+      return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                               _("Cannot switch '%s' because it is not in the "
+                                 "repository yet"),
+                               svn_dirent_local_style(local_abspath, pool));
+  }
+
   /* See which files the user wants to preserve the extension of when
      conflict files are made. */
   svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
@@ -194,6 +206,8 @@ switch_internal(svn_revnum_t *result_rev
                                    pool, pool));
       SVN_ERR(svn_wc__node_get_base_rev(&target_rev, ctx->wc_ctx,
                                         local_abspath, pool));
+      /* ### It would be nice if this function could reuse the existing
+             ra session instead of opening two for its own use. */
       SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_path, &yc_rev,
                                                        switch_rev_url, revnum,
                                                        target_url, target_rev,

Modified: subversion/trunk/subversion/libsvn_wc/node.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/node.c?rev=1100708&r1=1100707&r2=1100708&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/node.c (original)
+++ subversion/trunk/subversion/libsvn_wc/node.c Sun May  8 09:06:31 2011
@@ -818,6 +818,26 @@ svn_wc__node_is_added(svn_boolean_t *is_
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__node_has_working(svn_boolean_t *has_working,
+                         svn_wc_context_t *wc_ctx,
+                         const char *local_abspath,
+                         apr_pool_t *scratch_pool)
+{
+  svn_wc__db_status_t status;
+
+  SVN_ERR(svn_wc__db_read_info(&status,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, has_working,
+                               wc_ctx->db, local_abspath,
+                               scratch_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+
 static svn_error_t *
 get_base_rev(svn_revnum_t *base_revision,
              svn_wc__db_t *db,

Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1100708&r1=1100707&r2=1100708&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Sun May  8 09:06:31 
2011
@@ -4171,7 +4171,7 @@ close_edit(void *edit_baton,
 /* Helper for the three public editor-supplying functions. */
 static svn_error_t *
 make_editor(svn_revnum_t *target_revision,
-            svn_wc_context_t *wc_ctx,
+            svn_wc__db_t *db,
             const char *anchor_abspath,
             const char *target_basename,
             svn_boolean_t use_commit_times,
@@ -4202,27 +4202,15 @@ make_editor(svn_revnum_t *target_revisio
   svn_delta_editor_t *tree_editor = svn_delta_default_editor(edit_pool);
   const svn_delta_editor_t *inner_editor;
   const char *repos_root, *repos_uuid;
-  svn_wc__db_status_t status;
 
   /* An unknown depth can't be sticky. */
   if (depth == svn_depth_unknown)
     depth_is_sticky = FALSE;
 
-  /* Get the anchor's repository root and uuid. */
-  SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL,
-                               &repos_root, &repos_uuid,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL,
-                               wc_ctx->db, anchor_abspath,
-                               result_pool, scratch_pool));
-  
-  /* ### For adds, REPOS_ROOT and REPOS_UUID would be NULL now. */
-  if (status == svn_wc__db_status_added)
-    SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL,
-                                     &repos_root, &repos_uuid,
-                                     NULL, NULL, NULL, NULL,
-                                     wc_ctx->db, anchor_abspath,
+  /* Get the anchor's repository root and uuid. The anchor must already exist
+     in BASE. */
+  SVN_ERR(svn_wc__db_scan_base_repos(NULL, &repos_root, &repos_uuid,
+                                     db, anchor_abspath,
                                      result_pool, scratch_pool));
 
   /* With WC-NG we need a valid repository root */
@@ -4242,12 +4230,11 @@ make_editor(svn_revnum_t *target_revisio
   eb->target_revision          = target_revision;
   eb->repos_root               = repos_root;
   eb->repos_uuid               = repos_uuid;
-  eb->db                       = wc_ctx->db;
+  eb->db                       = db;
   eb->target_basename          = target_basename;
   eb->anchor_abspath           = anchor_abspath;
 
-  SVN_ERR(svn_wc__db_get_wcroot(&eb->wcroot_abspath,
-                                wc_ctx->db, anchor_abspath,
+  SVN_ERR(svn_wc__db_get_wcroot(&eb->wcroot_abspath, db, anchor_abspath,
                                 edit_pool, scratch_pool));
 
   if (switch_url)
@@ -4316,7 +4303,7 @@ make_editor(svn_revnum_t *target_revisio
       && !depth_is_sticky)
     SVN_ERR(svn_wc__ambient_depth_filter_editor(&inner_editor,
                                                 &inner_baton,
-                                                wc_ctx->db,
+                                                db,
                                                 anchor_abspath,
                                                 target_basename,
                                                 inner_editor,
@@ -4359,7 +4346,7 @@ svn_wc_get_update_editor4(const svn_delt
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
 {
-  return make_editor(target_revision, wc_ctx, anchor_abspath,
+  return make_editor(target_revision, wc_ctx->db, anchor_abspath,
                      target_basename, use_commit_times,
                      NULL, depth, depth_is_sticky, allow_unver_obstructions,
                      adds_as_modification, server_performs_filtering,
@@ -4399,7 +4386,7 @@ svn_wc_get_switch_editor4(const svn_delt
 {
   SVN_ERR_ASSERT(switch_url && svn_uri_is_canonical(switch_url, scratch_pool));
 
-  return make_editor(target_revision, wc_ctx, anchor_abspath,
+  return make_editor(target_revision, wc_ctx->db, anchor_abspath,
                      target_basename, use_commit_times,
                      switch_url,
                      depth, depth_is_sticky, allow_unver_obstructions,

Modified: subversion/trunk/subversion/tests/cmdline/switch_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/switch_tests.py?rev=1100708&r1=1100707&r2=1100708&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/switch_tests.py Sun May  8 
09:06:31 2011
@@ -1729,14 +1729,22 @@ def switch_scheduled_add(sbox):
 
   file_path = os.path.join(wc_dir, 'stub_file')
   switch_url = sbox.repo_url + '/iota'
+  nodo_path = os.path.join(wc_dir, 'nodo')
 
   svntest.main.file_append(file_path, "")
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'add', file_path)
-  svntest.actions.run_and_verify_svn(None, None, [], 'switch',
-                                     '--ignore-ancestry',
+  svntest.actions.run_and_verify_svn(None, None,
+                                     "svn: E200007: Cannot switch '.*file' " +
+                                     "because it is not in the repository yet",
+                                     'switch', '--ignore-ancestry',
                                      switch_url, file_path)
 
+  svntest.actions.run_and_verify_svn(None, None,
+                                     "svn: E155010: The node '.*nodo' was not",
+                                     'switch', '--ignore-ancestry',
+                                     switch_url, nodo_path)
+
 #----------------------------------------------------------------------
 @SkipUnless(server_has_mergeinfo)
 def mergeinfo_switch_elision(sbox):


Reply via email to