You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by mark benedetto king <bk...@inquira.com> on 2002/09/24 02:42:58 UTC

[PATCH] implement "svn switch --only-rewrite-urls"

New option for svn switch: "--only-rewrite-urls".  Useful for when the URL
by which the repository must be referred to has changed.  This happens most
frequently for mobile users.  

* subversion/include/svn_wc.h
  (svn_wc_relocate): Prototype for new function.

* subversion/include/svn_client.h
  (svn_client_relocate): Prototype for new function.

* subversion/libsvn_wc/relocate.c
  New file.  Includes implementation of svn_wc_relocate().

* subversion/libsvn_client/relocate.c
  New file.  Includes implementation of svn_client_relocate().

* subversion/clients/cmdline/cl.h
  (svn_cl__only_rewrite_urls_opt): Added enum for only-rewrite-urls option.
  (svn_cl__opt_state_t): Added boolean member for only-rewrite-urls option.

* subversion/clients/cmdline/switch-cmd.c
  (svn_cl__switch): Call rewrite_urls() when appropriate.
  (rewrite_urls): Call svn_client_relocate().

* subversion/clients/cmdline/main.c
  (svn_cl__options): Added entry for long option "--only-rewrite-urls".
  (svn_cl__cmd_table): Added option for "switch" subcommand.
  (main): Modify opt_state appropriately when only-rewrite-urls option is
  specified.
 
* subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
  Updated to reflect new option to "svn switch".



 
Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h
+++ subversion/include/svn_wc.h	Mon Sep 23 20:38:04 2002
@@ -1472,6 +1472,19 @@
                 svn_wc_adm_access_t *optional_adm_access,
                 apr_pool_t *pool);
 
+/* Recurse from PATH, changing repository references that begin with
+   FROM to begin with TO instead.  Perform necessary allocations in
+   POOL. 
+
+   ADM_ACCESS is an access baton for the directory containing
+   PATH. ADM_ACCESS can be NULL in which case the function will open and
+   close acess batons as required. */
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 apr_pool_t *pool);
 
 /* Revert changes to PATH (perhaps in a RECURSIVE fashion).  Perform
    necessary allocations in POOL.
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h
+++ subversion/include/svn_client.h	Mon Sep 23 20:38:04 2002
@@ -684,6 +684,15 @@
                     apr_pool_t *pool);
 
 
+/* Recursively modify a working copy directory DIR, changing any
+   repository URLs that begin with FROM to begin with TO instead. */
+svn_error_t *
+svn_client_relocate (const char *dir,
+                     const char *from,
+                     const char *to,
+                     apr_pool_t *pool);
+
+
 /* Restore the pristine version of a working copy PATH, effectively
    undoing any local mods.  If PATH is a directory, and RECURSIVE is
    TRUE, this will be a recursive operation.
Index: subversion/libsvn_wc/relocate.c
===================================================================
--- subversion/libsvn_wc/relocate.c
+++ subversion/libsvn_wc/relocate.c	Mon Sep 23 20:38:04 2002
@@ -0,0 +1,101 @@
+/*
+ * relocate.c: do wc repos relocation
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include "svn_wc.h"
+#include "svn_error.h"
+#include "svn_string.h"
+#include "svn_xml.h"
+#include "svn_pools.h"
+#include "svn_io.h"
+
+#include "wc.h"
+#include "entries.h"
+
+
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 apr_pool_t *pool)
+{
+  apr_hash_t *entries = NULL;
+  apr_hash_index_t *hi;
+  enum svn_node_kind kind;
+  int is_wc;
+  int from_len;
+
+  svn_boolean_t root = FALSE;
+
+
+  SVN_ERR (svn_wc_check_wc (path, &is_wc, pool));
+  if (! is_wc)
+    return svn_error_createf
+      (SVN_ERR_WC_NOT_DIRECTORY, 0, NULL, pool,
+       "svn_wc_cleanup: %s is not a working copy directory", path);
+
+  if (! adm_access)
+    {
+      SVN_ERR (svn_wc_adm_open (&adm_access, NULL, path, TRUE, TRUE, pool));
+      root = TRUE;
+    }
+
+  from_len = strlen(from);
+
+  SVN_ERR (svn_wc_entries_read (&entries, path, FALSE, pool));
+
+  for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
+    {
+      const void *key;
+      void *val;
+      svn_wc_entry_t *entry;
+
+      apr_hash_this (hi, &key, NULL, &val);
+      entry = val;
+
+      if ((entry->kind == svn_node_dir)
+          && (strcmp (key, SVN_WC_ENTRY_THIS_DIR) != 0))
+        {
+          /* Recurse */
+          const char *subdir = svn_path_join (path, key, pool);
+          SVN_ERR (svn_wc_relocate (subdir, adm_access, from, to, pool));
+        }
+     
+      if (entry->url &&
+          (strncmp(entry->url, from, from_len) == 0))
+          entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);
+    }
+
+  SVN_ERR (svn_wc__entries_write (entries, path, pool));
+
+  if (root)
+    svn_wc_adm_close(adm_access);
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end:
+ */
+
Index: subversion/libsvn_client/relocate.c
===================================================================
--- subversion/libsvn_client/relocate.c
+++ subversion/libsvn_client/relocate.c	Mon Sep 23 20:38:04 2002
@@ -0,0 +1,59 @@
+/*
+ * relocate.c:  wrapper around wc relocation functionality.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_path.h"
+#include "client.h"
+
+
+
+/*** Code. ***/
+
+svn_error_t *
+svn_client_relocate (const char *dir,
+                     const char *from,
+                     const char *to,
+                     apr_pool_t *pool)
+{
+  enum svn_node_kind kind;
+
+  SVN_ERR (svn_io_check_path (dir, &kind, pool));
+  if (kind != svn_node_dir)
+    return svn_error_createf (SVN_ERR_WC_NOT_DIRECTORY, 0, NULL, pool,
+                              "Cannot relocate '%s' -- not a directory", 
+                              dir);
+
+  return svn_wc_relocate (dir, NULL, from, to, pool);
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end: */
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h
+++ subversion/clients/cmdline/cl.h	Mon Sep 23 20:44:07 2002
@@ -53,7 +53,8 @@
   svn_cl__xml_opt,
   svn_cl__strict_opt,
   svn_cl__no_ignore_opt,
-  svn_cl__no_auth_cache_opt
+  svn_cl__no_auth_cache_opt,
+  svn_cl__only_rewrite_urls_opt
 } svn_cl__longopt_t;
 
 
@@ -93,6 +94,7 @@
   svn_boolean_t xml;             /* output in xml, e.g., "svn log --xml" */
   svn_boolean_t no_ignore;       /* disregard default ignores & svn:ignore's */
   svn_boolean_t no_auth_cache;   /* do not cache authentication information */
+  svn_boolean_t only_rewrite_urls; /* rewrite urls (svn switch) */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/switch-cmd.c
===================================================================
--- subversion/clients/cmdline/switch-cmd.c
+++ subversion/clients/cmdline/switch-cmd.c	Mon Sep 23 21:38:24 2002
@@ -21,18 +21,53 @@
 
 
 /*** Includes. ***/
-
 #include "svn_wc.h"
 #include "svn_client.h"
 #include "svn_string.h"
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_pools.h"
 #include "cl.h"
 
 
 /*** Code. ***/
 
+static svn_error_t *
+rewrite_urls(apr_array_header_t *targets,
+             apr_pool_t *pool)
+{
+  apr_pool_t *subpool;
+  const char *from;
+  const char *to;
+  int i;
+ 
+  if (targets->nelts < 2)
+    return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
+          
+  from = ((const char **) (targets->elts))[0];
+  to = ((const char **) (targets->elts))[1];
+ 
+  subpool = svn_pool_create (pool);
+
+  if (targets->nelts == 2)
+    {
+      SVN_ERR(svn_client_relocate ("", from, to, pool));
+    }
+  else
+    {
+      for (i = 2; i < targets->nelts; i++)
+        {
+          const char *target = ((const char **) (targets->elts))[i];
+          SVN_ERR (svn_client_relocate (target, from, to, subpool));
+          svn_pool_clear (subpool);
+        }
+    }
+
+  svn_pool_destroy (subpool);
+  return SVN_NO_ERROR;
+}
+
 
 svn_error_t *
 svn_cl__switch (apr_getopt_t *os,
@@ -53,6 +88,11 @@
      switch to ("switch_url"). */
   SVN_ERR (svn_cl__args_to_target_array (&targets, os, opt_state, 
                                          FALSE, pool));
+
+  /* handle only-rewrite case specially */
+  if (opt_state->only_rewrite_urls)
+    return rewrite_urls (targets, pool);
+
   if ((targets->nelts < 1) || (targets->nelts > 2))
     return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
 
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c
+++ subversion/clients/cmdline/main.c	Mon Sep 23 21:46:18 2002
@@ -77,6 +77,8 @@
                       "disregard default and svn:ignore property ignores"},
     {"no-auth-cache", svn_cl__no_auth_cache_opt, 0,
                       "do not cache authentication tokens"},
+    {"only-rewrite-urls", svn_cl__only_rewrite_urls_opt, 0,
+                      "only rewrite urls; do not contact a repository"},
     {0,               0, 0}
   };
 
@@ -400,10 +402,12 @@
   
   { "switch", svn_cl__switch, {"sw"},
     "Update working copy to mirror a new URL\n"
-    "usage: switch REPOS_URL [TARGET]\n\n"
+    "usage: switch REPOS_URL [TARGET]   or\n"
+    "       switch --only-rewrite-urls [FROM] [TO] [TARGET ...]\n\n"
     "   Note:  this is the way to move a working copy to a new branch.\n",
     { 'r', 'D', 'N', 'q', svn_cl__auth_username_opt,
-      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt} },
+      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt,
+      svn_cl__only_rewrite_urls_opt } },
  
   { "update", svn_cl__update, {"up"}, 
     "Bring changes from the repository into the working copy.\n"
@@ -1131,6 +1135,9 @@
       case svn_cl__no_auth_cache_opt:
         opt_state.no_auth_cache = TRUE;
         break;
+      case svn_cl__only_rewrite_urls_opt:
+        opt_state.only_rewrite_urls = TRUE;
+        break;
       case 'x':
         err = svn_utf_cstring_to_utf8 (&opt_state.extensions, opt_arg,
                                        NULL, pool);
Index: subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
===================================================================
--- subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout	Mon Sep 23 22:04:44 2002
@@ -39,4 +39,5 @@
   --username arg           : specify a username ARG
   --password arg           : specify a password ARG
   --no-auth-cache          : do not cache authentication tokens
+  --only-rewrite-urls arg  : only rewrite urls; do not contact a repository
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Ben Collins-Sussman <su...@collab.net>.
cmpilato@collab.net writes:

> Greg Hudson <gh...@MIT.EDU> writes:
> 
> > On Mon, 2002-09-23 at 23:19, cmpilato@collab.net wrote:
> > > Could we create an option that at least has a *hope* of being used by
> > > more than one subcommand, like ... oh, "--no-repos-access" or something?
> > 
> > Hm.  I have a different take on this.  I'm happy with the option being
> > very specific to this situation, but I think it should contact the new
> > repository, to ensure that the text bases in the working directory are
> > valid.  Otherwise it's too easy to get a corrupt working copy.  Didn't
> > this come up previously in the discussion of the command?
> 
> Oh, yeah, it did -- and for what it's worth, I agree with your
> concerns -- but the patch wasn't coded that way, for whatever reason
> (I've not been following the whole discussion).  I still am not fond
> of tacking a magical switch onto a single subcommand that is so
> obscure that it will never be used elsewhere -- I mean, just use a new
> subcommand. :-)  But whatever.  

We just had this conversation, Mike.  I think you missed it.  :-)

The reason mbk coded it this way was because kfogel specifically asked
him NOT to create a new subcommand.  kfogel and others all preferred
not to create a new subcommand, and I agree as well.

The issue is that we don't want to go the way of bitkeeper, creating
new subcommands for every odd edge case that comes along.  Many people
find bitkeeper confusing for this reason.

Thus, we'd like to think of this scenario as an edge-case of 'svn
switch', hence the obscure option.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by cm...@collab.net.
Greg Hudson <gh...@MIT.EDU> writes:

> On Mon, 2002-09-23 at 23:19, cmpilato@collab.net wrote:
> > Could we create an option that at least has a *hope* of being used by
> > more than one subcommand, like ... oh, "--no-repos-access" or something?
> 
> Hm.  I have a different take on this.  I'm happy with the option being
> very specific to this situation, but I think it should contact the new
> repository, to ensure that the text bases in the working directory are
> valid.  Otherwise it's too easy to get a corrupt working copy.  Didn't
> this come up previously in the discussion of the command?

Oh, yeah, it did -- and for what it's worth, I agree with your
concerns -- but the patch wasn't coded that way, for whatever reason
(I've not been following the whole discussion).  I still am not fond
of tacking a magical switch onto a single subcommand that is so
obscure that it will never be used elsewhere -- I mean, just use a new
subcommand. :-)  But whatever.  

Put me at -0 on a funky switch vs. a subcommand, and +1 on "validate
against the repos" thing.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Greg Hudson <gh...@MIT.EDU>.
On Mon, 2002-09-23 at 23:19, cmpilato@collab.net wrote:
> Could we create an option that at least has a *hope* of being used by
> more than one subcommand, like ... oh, "--no-repos-access" or something?

Hm.  I have a different take on this.  I'm happy with the option being
very specific to this situation, but I think it should contact the new
repository, to ensure that the text bases in the working directory are
valid.  Otherwise it's too easy to get a corrupt working copy.  Didn't
this come up previously in the discussion of the command?

(I'd call it --relocate, myself.)


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by cm...@collab.net.
mark benedetto king <bk...@inquira.com> writes:

> New option for svn switch: "--only-rewrite-urls".  Useful for when the URL
> by which the repository must be referred to has changed.  This happens most
> frequently for mobile users.  

Huh.  "--only-rewrite-urls", eh?

> +    {"only-rewrite-urls", svn_cl__only_rewrite_urls_opt, 0,
> +                      "only rewrite urls; do not contact a repository"},

Could we create an option that at least has a *hope* of being used by
more than one subcommand, like ... oh, "--no-repos-access" or something?

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Philip Martin <ph...@codematters.co.uk>.
Karl Fogel <kf...@newton.ch.collab.net> writes:

>    2) If we don't supply this command, people *will*, I guarantee it,
>       start writing their own scripts to modify the entries file :-).

Heh, done it myself!  I *do* worry about whether I'm going to break
something when I do it.

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Karl Fogel <kf...@newton.ch.collab.net>.
"Sander Striker" <st...@apache.org> writes:
> That's true.  But please file an issue on this the moment this code is
> committed.  Without the security checks, but with the functionality
> committed it is a showstopper for 1.0 IMO.

+1 on an issue, but it's not a 1.0 showstopper.

First of all, resolution issue #689 will protect against actual
damage; second, again, we're offering people something they would
otherwise write for themselves, in which case it would have been
entirely out of our control and unrelated to 1.0 anyway.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

RE: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Sander Striker <st...@apache.org>.
> From: Karl Fogel [mailto:kfogel@newton.ch.collab.net]
> Sent: 24 September 2002 15:17

> Philip Martin <ph...@codematters.co.uk> writes:
>> I don't really like this approach, I'd prefer a command that contacts
>> the new repository, to ensure that we don't get invalid text-bases.

Me too.

And having a simple GUID on the repos would help a great deal.  Contact
the new repos, compare GUIDs and abort if they're not equal.

> > The current patch would be the only client command that, by design,
> > will allow the user to produce a corrupt working copy.
> 
> Philip, if it makes you feel any better...
> 
>    1) When issue #689 is finished (repos<->wc checksums), such
>       corruption will at least be instantly noticed, and not spread
>       beyond that working copy.
> 
>    2) If we don't supply this command, people *will*, I guarantee it,
>       start writing their own scripts to modify the entries file :-).
>       We can either pretend it's not going to happen, or we can supply
>       the functionality ourselves and thus leave the door open to add
>       more safety checks later.

That's true.  But please file an issue on this the moment this code is
committed.  Without the security checks, but with the functionality
committed it is a showstopper for 1.0 IMO.

Sander


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Karl Fogel <kf...@newton.ch.collab.net>.
Philip Martin <ph...@codematters.co.uk> writes:
> I don't really like this approach, I'd prefer a command that contacts
> the new repository, to ensure that we don't get invalid text-bases.
> The current patch would be the only client command that, by design,
> will allow the user to produce a corrupt working copy.

Philip, if it makes you feel any better...

   1) When issue #689 is finished (repos<->wc checksums), such
      corruption will at least be instantly noticed, and not spread
      beyond that working copy.

   2) If we don't supply this command, people *will*, I guarantee it,
      start writing their own scripts to modify the entries file :-).
      We can either pretend it's not going to happen, or we can supply
      the functionality ourselves and thus leave the door open to add
      more safety checks later.

> That said, here is a short review to help get this working with the
> recent access baton changes :)

You rock :-).

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Philip Martin <ph...@codematters.co.uk>.
mark benedetto king <bk...@Inquira.Com> writes:

> New option for svn switch: "--relocate".  Useful for when the URL
> by which the repository must be referred to has changed.  This happens
> most frequently for mobile users.  These changes were greatly improved
> by feedback from Philip Martin.  Thanks to Greg Hudson for noticing that
> the log message was no longer in sync with the patch.

Well, this patch looks like it should work.  I'd prefer an
implementation that verified the correctness of the new URL, but given
that I have edited .svn/entries files in the past I wouldn't object to
this one.

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by mark benedetto king <bk...@inquira.com>.
Patch follows in-lined comments.

On Tue, Oct 01, 2002 at 06:16:25PM +0100, Philip Martin wrote:
> mark benedetto king <bk...@Inquira.Com> writes:
> 
> > So, the right thing to do is just use entry->url, and not worry about
> > it being null.
> 
> Try
> 
> $ touch foo
> $ svn add foo
> $ svn info foo
> 

Eek.  You're right (a look at take_from_entry() explains why).

> The svn_wc_entry_t for foo will contain a null URL.  Now if you
> relocate the parent directory your code just skips foo, which looks
> like the correct thing to do.  But if you try to relocate foo itself,
> your old code used to make up an URL, and your new code dumps core.
> 
> Now that you are not trying to make up an URL you don't need to get or
> check the this_dir entry for the single file case either.

Since it's not under revision control, I think we can't do anything
other than punt.

> 
> Other things to consider:
> 
> Should attempting to relocate a file without an URL generate an error?
> Looks like ordinary switch fails here :-(

Yes, see above.

> 
> If there is an URL but it doesn't match the "from" prefix, should
> there be an error?
> 

My gut says "no", but my gut is frequently wrong about interface
behaviour.

> If a single file, or subdirectory, has been switched, then its URL
> won't be simply parent directory URL + name.  If while relocating a
> directory you come across a child with an URL that doesn't match the
> "from" prefix, while the parent directory has an URL that does match,
> should there be an error?

No, I don't think so.

> 
> -- 
> Philip Martin
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
> For additional commands, e-mail: dev-help@subversion.tigris.org


--ben


New option for svn switch: "--relocate".  Useful for when the URL
by which the repository must be referred to has changed.  This happens
most frequently for mobile users.  These changes were greatly improved
by feedback from Philip Martin.  Thanks to Greg Hudson for noticing that
the log message was no longer in sync with the patch.

* subversion/include/svn_wc.h
  (svn_wc_relocate): Prototype for new function.

* subversion/include/svn_client.h
  (svn_client_relocate): Prototype for new function.

* subversion/libsvn_wc/relocate.c
  New file.  Includes implementation of svn_wc_relocate().
  Should eventually verify that new URL is valid; doesn't
  do any validation at all right now.

* subversion/libsvn_client/relocate.c
  New file.  Includes implementation of svn_client_relocate().

* subversion/clients/cmdline/cl.h
  (svn_cl__longopt_t): Added enum for new option.
  (svn_cl__opt_state_t): Added entry for new option.

* subversion/clients/cmdline/switch-cmd.c
  (rewrite_urls): New function: calls svn_client_relocate().
  (svn_cl__switch): Call rewrite_urls() instead of normal switch logic
  when appropriate.

* subversion/clients/cmdline/main.c
  (svn_cl__options): Added entry for new option.
  (svn_cl__cmd_table): Updated entry for switch to support new option.
  (main): Added support for new option.

* subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
  Adjust expected output.

Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h
+++ subversion/include/svn_wc.h	Mon Sep 30 18:24:33 2002
@@ -1481,6 +1481,19 @@
                 svn_wc_adm_access_t *optional_adm_access,
                 apr_pool_t *pool);
 
+/* Changing repository references at PATH that begin with
+   FROM to begin with TO instead.  Perform necessary allocations in
+   POOL.  If RECURSE is true, do so.
+
+   ADM_ACCESS is an access baton for the directory containing
+   PATH. ADM_ACCESS must not be NULL.  */
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool);
 
 /* Revert changes to PATH (perhaps in a RECURSIVE fashion).  Perform
    necessary allocations in POOL.
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h
+++ subversion/include/svn_client.h	Mon Sep 30 18:24:33 2002
@@ -652,6 +652,17 @@
                     apr_pool_t *pool);
 
 
+/* Modify a working copy directory DIR, changing any
+   repository URLs that begin with FROM to begin with TO instead,
+   recursing into subdirectories if RECURSE is true. */
+svn_error_t *
+svn_client_relocate (const char *dir,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool);
+
+
 /* Restore the pristine version of a working copy PATH, effectively
    undoing any local mods.  If PATH is a directory, and RECURSIVE is
    TRUE, this will be a recursive operation.
Index: subversion/libsvn_wc/relocate.c
===================================================================
--- subversion/libsvn_wc/relocate.c
+++ subversion/libsvn_wc/relocate.c	Wed Oct  2 00:55:30 2002
@@ -0,0 +1,120 @@
+/*
+ * relocate.c: do wc repos relocation
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include "svn_wc.h"
+#include "svn_error.h"
+#include "svn_string.h"
+#include "svn_xml.h"
+#include "svn_pools.h"
+#include "svn_io.h"
+
+#include "wc.h"
+#include "entries.h"
+
+
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool)
+{
+  enum svn_node_kind kind;
+  apr_hash_t *entries = NULL;
+  apr_hash_index_t *hi;
+  svn_boolean_t is_file = FALSE;
+  char *base;
+  int from_len;
+
+  SVN_ERR(svn_io_check_path(path, &kind, pool));
+
+  if (kind == svn_node_file)
+    {
+      base = svn_path_basename(path, pool);
+      is_file = TRUE;
+    }
+
+  from_len = strlen(from);
+
+  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool));
+
+  if (is_file)
+    {
+      svn_wc_entry_t *entry = apr_hash_get(entries, base, APR_HASH_KEY_STRING);
+      if (!entry)
+        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
+                                "missing entry");
+
+      if (!entry->url)
+        return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, 0, NULL, pool,
+                                 "entry '%s' has no URL", path);
+
+      if (!strncmp(entry->url, from, from_len))
+        {
+          entry->url = apr_psprintf(svn_wc_adm_access_pool(adm_access),
+                                    "%s%s", to, entry->url + from_len);
+          SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+        }
+
+      return SVN_NO_ERROR;
+    }
+
+  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      svn_wc_entry_t *entry;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      entry = val;
+
+ 
+      if (recurse
+          && (entry->kind == svn_node_dir)
+          && (strcmp(key, SVN_WC_ENTRY_THIS_DIR) != 0))
+        {
+          svn_wc_adm_access_t *subdir_access;
+          const char *subdir = svn_path_join (path, key, pool);
+          SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, subdir,
+                                      pool));
+          SVN_ERR(svn_wc_relocate(subdir, subdir_access, from,
+                                   to, recurse, pool));
+        }
+
+      if (entry->url &&
+          (strncmp(entry->url, from, from_len) == 0))
+        entry->url = apr_psprintf(svn_wc_adm_access_pool(adm_access),
+                                  "%s%s", to, entry->url + from_len);
+    }
+
+  SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end:
+ */
+
Index: subversion/libsvn_client/relocate.c
===================================================================
--- subversion/libsvn_client/relocate.c
+++ subversion/libsvn_client/relocate.c	Mon Sep 30 18:48:33 2002
@@ -0,0 +1,61 @@
+/*
+ * relocate.c:  wrapper around wc relocation functionality.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_path.h"
+#include "client.h"
+
+
+
+/*** Code. ***/
+
+svn_error_t *
+svn_client_relocate (const char *path,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool)
+{
+  svn_wc_adm_access_t *adm_access;
+
+  SVN_ERR (svn_wc_adm_probe_open(&adm_access, NULL, path,
+                                 TRUE, recurse, pool));
+
+  SVN_ERR(svn_wc_relocate(path, adm_access, from, to, recurse, pool));
+
+  SVN_ERR(svn_wc_adm_close(adm_access));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end: */
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h
+++ subversion/clients/cmdline/cl.h	Wed Oct  2 16:37:23 2002
@@ -54,7 +54,8 @@
   svn_cl__xml_opt,
   svn_cl__strict_opt,
   svn_cl__no_ignore_opt,
-  svn_cl__no_auth_cache_opt
+  svn_cl__no_auth_cache_opt,
+  svn_cl__relocate_opt
 } svn_cl__longopt_t;
 
 
@@ -94,6 +95,7 @@
   svn_boolean_t xml;             /* output in xml, e.g., "svn log --xml" */
   svn_boolean_t no_ignore;       /* disregard default ignores & svn:ignore's */
   svn_boolean_t no_auth_cache;   /* do not cache authentication information */
+  svn_boolean_t relocate;        /* rewrite urls (svn switch) */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/switch-cmd.c
===================================================================
--- subversion/clients/cmdline/switch-cmd.c
+++ subversion/clients/cmdline/switch-cmd.c	Wed Oct  2 16:37:47 2002
@@ -21,18 +21,54 @@
 
 
 /*** Includes. ***/
-
 #include "svn_wc.h"
 #include "svn_client.h"
 #include "svn_string.h"
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_pools.h"
 #include "cl.h"
 
 
 /*** Code. ***/
 
+static svn_error_t *
+rewrite_urls(apr_array_header_t *targets,
+             svn_boolean_t recurse,
+             apr_pool_t *pool)
+{
+  apr_pool_t *subpool;
+  const char *from;
+  const char *to;
+  int i;
+ 
+  if (targets->nelts < 2)
+    return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
+          
+  from = ((const char **) (targets->elts))[0];
+  to = ((const char **) (targets->elts))[1];
+ 
+  subpool = svn_pool_create (pool);
+
+  if (targets->nelts == 2)
+    {
+      SVN_ERR(svn_client_relocate ("", from, to, recurse, pool));
+    }
+  else
+    {
+      for (i = 2; i < targets->nelts; i++)
+        {
+          const char *target = ((const char **) (targets->elts))[i];
+          SVN_ERR (svn_client_relocate (target, from, to, recurse, subpool));
+          svn_pool_clear (subpool);
+        }
+    }
+
+  svn_pool_destroy (subpool);
+  return SVN_NO_ERROR;
+}
+
 
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
@@ -59,6 +95,10 @@
                                          &(opt_state->end_revision),
                                          FALSE, pool));
 
+  /* handle only-rewrite case specially */
+  if (opt_state->relocate)
+    return rewrite_urls (targets, !opt_state->nonrecursive, pool);
+
   if ((targets->nelts < 1) || (targets->nelts > 2))
     return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
 
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c
+++ subversion/clients/cmdline/main.c	Wed Oct  2 16:36:58 2002
@@ -85,6 +85,8 @@
                       "disregard default and svn:ignore property ignores"},
     {"no-auth-cache", svn_cl__no_auth_cache_opt, 0,
                       "do not cache authentication tokens"},
+    {"relocate",      svn_cl__relocate_opt, 0,
+                      "relocate via url-rewriting"},
     {0,               0, 0, 0}
   };
 
@@ -378,10 +380,12 @@
   
   { "switch", svn_cl__switch, {"sw"},
     "Update working copy to mirror a new URL\n"
-    "usage: switch REPOS_URL [TARGET]\n\n"
+    "usage: switch REPOS_URL [TARGET]   or\n"
+    "       switch --relocate [FROM] [TO] [TARGET ...]\n\n"
     "   Note:  this is the way to move a working copy to a new branch.\n",
     { 'r', 'D', 'N', 'q', svn_cl__auth_username_opt,
-      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt} },
+      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt,
+      svn_cl__relocate_opt } },
  
   { "update", svn_cl__update, {"up"}, 
     "Bring changes from the repository into the working copy.\n"
@@ -404,7 +408,6 @@
   { NULL, NULL, {0}, NULL, {0} }
 };
 
-
 
 /*** Main. ***/
 
@@ -667,6 +670,9 @@
       case svn_cl__no_auth_cache_opt:
         opt_state.no_auth_cache = TRUE;
         break;
+      case svn_cl__relocate_opt:
+        opt_state.relocate = TRUE;
+        break;
       case 'x':
         err = svn_utf_cstring_to_utf8 (&opt_state.extensions, opt_arg,
                                        NULL, pool);
Index: subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
===================================================================
--- subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout	Wed Oct  2 16:42:22 2002
@@ -27,7 +27,8 @@
   --xml                    : output in xml
 
 switch (sw): Update working copy to mirror a new URL
-usage: switch REPOS_URL [TARGET]
+usage: switch REPOS_URL [TARGET]   or
+       switch --relocate [FROM] [TO] [TARGET ...]
 
    Note:  this is the way to move a working copy to a new branch.
 
@@ -39,4 +40,5 @@
   --username arg           : specify a username ARG
   --password arg           : specify a password ARG
   --no-auth-cache          : do not cache authentication tokens
+  --relocate               : relocate via url-rewriting
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Philip Martin <ph...@codematters.co.uk>.
mark benedetto king <bk...@Inquira.Com> writes:

> So, the right thing to do is just use entry->url, and not worry about
> it being null.

Try

$ touch foo
$ svn add foo
$ svn info foo

The svn_wc_entry_t for foo will contain a null URL.  Now if you
relocate the parent directory your code just skips foo, which looks
like the correct thing to do.  But if you try to relocate foo itself,
your old code used to make up an URL, and your new code dumps core.

Now that you are not trying to make up an URL you don't need to get or
check the this_dir entry for the single file case either.

Other things to consider:

Should attempting to relocate a file without an URL generate an error?
Looks like ordinary switch fails here :-(

If there is an URL but it doesn't match the "from" prefix, should
there be an error?

If a single file, or subdirectory, has been switched, then its URL
won't be simply parent directory URL + name.  If while relocating a
directory you come across a child with an URL that doesn't match the
"from" prefix, while the parent directory has an URL that does match,
should there be an error?

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Karl Fogel <kf...@newton.ch.collab.net>.
Greg Hudson <gh...@MIT.EDU> writes:
> I still believe --relocate is a better option name, since
> "--only-rewrite-urls" isn't really descriptive of the desired behavior
> (which is to verify that the text-bases you have are valid for the new
> URL).

Agree.

> I am -0 on having this option available before it is implemented safely.

I would agree with that, if people weren't already writing scripts to
do the relocation edits in .svn/entries anyway.  Since they are, +1 on
bowing to reality :-).

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Greg Hudson <gh...@MIT.EDU>.
On Tue, 2002-10-01 at 12:39, mark benedetto king wrote:
> New subcommand: "relocate".

Needs to be changed to reflect the new world order.

> * subversion/clients/cmdline/main.c
>   (svn_cl__cmd_table): Added entry for "relocate".

Same here.

I still believe --relocate is a better option name, since
"--only-rewrite-urls" isn't really descriptive of the desired behavior
(which is to verify that the text-bases you have are valid for the new
URL).

I am -0 on having this option available before it is implemented safely.


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by mark benedetto king <bk...@inquira.com>.
Patch follows in-line comments.

On Tue, Oct 01, 2002 at 05:02:21PM +0100, Philip Martin wrote:
> > +      url = entry->url;
> > +      if (!url) 
> > +        url = svn_path_join(this_dir->url, base, pool);
> 
> This still doesn't look right.  If the entry didn't originally have an
> URL why are you creating one?  Why is this logic different from the
> logic in the the loop below?  If the file doesn't have an URL then I
> don't think relocate should create one.  Trying to relocate a file
> without an URL might perhaps produce an error or it might not, I could
> argue either way.
> 

Oh, I thought you were just pointing out that I forgot to join in
the basename. :-)

This code is there because I missed the call to resolve_to_defaults()
in svn_entries_read(), so I didn't think that a file entry's URL would
necessarily be populated.  Now that I see that entry->url should already
have the correct value, I understand why you were confused. :-)

So, the right thing to do is just use entry->url, and not worry about
it being null.

> > +
> > +      if (!strncmp(url, from, from_len))
> > +        {
> > +          entry->url = apr_psprintf (pool, "%s%s", to, url + from_len);
> 
> Didn't spot this yesterday, but this is not right, see below.
> 

Seeing.

> > +      if (entry->url &&
> > +          (strncmp(entry->url, from, from_len) == 0))
> > +        entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);
> 
> This has the same problem as the single file apr_psprintf above, it
> modifies the access baton's entry cache, but doesn't use the right
> pool.  Memory used to modify the access baton entry cache must come
> from the access baton pool.  There are two solutions, either a) use
> svn_wc__entry_modify which does its own allocation, or b) use
> svn_wc_adm_access_pool to get the access baton pool for use in
> apr_psprintf.  Solution a) is perhaps simpler for someone reading the
> code to understand, but b) is more efficient (at the moment) since it
> doesn't rewrite the entries file for each entry modified.
> 

(b) sounds good to me. :-)

--ben


New subcommand: "relocate".  Useful for when the URL by which the
repository must be referred to has changed.  This happens most
frequently for mobile users.  These changes were greatly improved
by feedback from Philip Martin.

* subversion/include/svn_wc.h
  (svn_wc_relocate): Prototype for new function.

* subversion/include/svn_client.h
  (svn_client_relocate): Prototype for new function.

* subversion/libsvn_wc/relocate.c
  New file.  Includes implementation of svn_wc_relocate().
  Should eventually verify that new URL is valid; doesn't
  do any validation at all right now.

* subversion/libsvn_client/relocate.c
  New file.  Includes implementation of svn_client_relocate().

* subversion/clients/cmdline/cl.h
  (svn_cl__relocate): Added subcommand prototype.  Fixed
  alphabetical-order of resolve/revert.

* subversion/clients/cmdline/relocate-cmd.c
  New file.  Includes implementation of svn_cl__relocate().

* subversion/clients/cmdline/main.c
  (svn_cl__cmd_table): Added entry for "relocate".

* subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
  Adjust expected output.

Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h
+++ subversion/include/svn_wc.h	Mon Sep 30 18:24:33 2002
@@ -1481,6 +1481,19 @@
                 svn_wc_adm_access_t *optional_adm_access,
                 apr_pool_t *pool);
 
+/* Changing repository references at PATH that begin with
+   FROM to begin with TO instead.  Perform necessary allocations in
+   POOL.  If RECURSE is true, do so.
+
+   ADM_ACCESS is an access baton for the directory containing
+   PATH. ADM_ACCESS must not be NULL.  */
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool);
 
 /* Revert changes to PATH (perhaps in a RECURSIVE fashion).  Perform
    necessary allocations in POOL.
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h
+++ subversion/include/svn_client.h	Mon Sep 30 18:24:33 2002
@@ -652,6 +652,17 @@
                     apr_pool_t *pool);
 
 
+/* Modify a working copy directory DIR, changing any
+   repository URLs that begin with FROM to begin with TO instead,
+   recursing into subdirectories if RECURSE is true. */
+svn_error_t *
+svn_client_relocate (const char *dir,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool);
+
+
 /* Restore the pristine version of a working copy PATH, effectively
    undoing any local mods.  If PATH is a directory, and RECURSIVE is
    TRUE, this will be a recursive operation.
Index: subversion/libsvn_wc/relocate.c
===================================================================
--- subversion/libsvn_wc/relocate.c
+++ subversion/libsvn_wc/relocate.c	Tue Oct  1 12:31:42 2002
@@ -0,0 +1,122 @@
+/*
+ * relocate.c: do wc repos relocation
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include "svn_wc.h"
+#include "svn_error.h"
+#include "svn_string.h"
+#include "svn_xml.h"
+#include "svn_pools.h"
+#include "svn_io.h"
+
+#include "wc.h"
+#include "entries.h"
+
+
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool)
+{
+  enum svn_node_kind kind;
+  apr_hash_t *entries = NULL;
+  apr_hash_index_t *hi;
+  svn_boolean_t is_file = FALSE;
+  char *base;
+  int from_len;
+
+  SVN_ERR(svn_io_check_path(path, &kind, pool));
+
+  if (kind == svn_node_file)
+    {
+      base = svn_path_basename(path, pool);
+      is_file = TRUE;
+    }
+
+  from_len = strlen(from);
+
+  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool));
+
+  if (is_file)
+    {
+      svn_wc_entry_t *this_dir = apr_hash_get(entries,
+                                              SVN_WC_ENTRY_THIS_DIR,
+                                              APR_HASH_KEY_STRING);
+      svn_wc_entry_t *entry = apr_hash_get(entries, base, APR_HASH_KEY_STRING);
+      if (!this_dir)
+        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
+                                "missing default entry");
+      if (!entry)
+        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
+                                "missing entry");
+
+      if (!strncmp(entry->url, from, from_len))
+        {
+          entry->url = apr_psprintf(svn_wc_adm_access_pool(adm_access),
+                                    "%s%s", to, entry->url + from_len);
+          SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+        }
+
+      return SVN_NO_ERROR;
+    }
+
+  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      svn_wc_entry_t *entry;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      entry = val;
+
+ 
+      if (recurse
+          && (entry->kind == svn_node_dir)
+          && (strcmp(key, SVN_WC_ENTRY_THIS_DIR) != 0))
+        {
+          svn_wc_adm_access_t *subdir_access;
+          const char *subdir = svn_path_join (path, key, pool);
+          SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, subdir,
+                                      pool));
+          SVN_ERR(svn_wc_relocate(subdir, subdir_access, from,
+                                   to, recurse, pool));
+        }
+
+      if (entry->url &&
+          (strncmp(entry->url, from, from_len) == 0))
+        entry->url = apr_psprintf(svn_wc_adm_access_pool(adm_access),
+                                  "%s%s", to, entry->url + from_len);
+    }
+
+  SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end:
+ */
+
Index: subversion/libsvn_client/relocate.c
===================================================================
--- subversion/libsvn_client/relocate.c
+++ subversion/libsvn_client/relocate.c	Mon Sep 30 18:48:33 2002
@@ -0,0 +1,61 @@
+/*
+ * relocate.c:  wrapper around wc relocation functionality.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_path.h"
+#include "client.h"
+
+
+
+/*** Code. ***/
+
+svn_error_t *
+svn_client_relocate (const char *path,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool)
+{
+  svn_wc_adm_access_t *adm_access;
+
+  SVN_ERR (svn_wc_adm_probe_open(&adm_access, NULL, path,
+                                 TRUE, recurse, pool));
+
+  SVN_ERR(svn_wc_relocate(path, adm_access, from, to, recurse, pool));
+
+  SVN_ERR(svn_wc_adm_close(adm_access));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end: */
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h
+++ subversion/clients/cmdline/cl.h	Mon Sep 30 18:24:33 2002
@@ -54,7 +54,8 @@
   svn_cl__xml_opt,
   svn_cl__strict_opt,
   svn_cl__no_ignore_opt,
-  svn_cl__no_auth_cache_opt
+  svn_cl__no_auth_cache_opt,
+  svn_cl__only_rewrite_urls_opt
 } svn_cl__longopt_t;
 
 
@@ -94,6 +95,7 @@
   svn_boolean_t xml;             /* output in xml, e.g., "svn log --xml" */
   svn_boolean_t no_ignore;       /* disregard default ignores & svn:ignore's */
   svn_boolean_t no_auth_cache;   /* do not cache authentication information */
+  svn_boolean_t only_rewrite_urls; /* rewrite urls (svn switch) */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/switch-cmd.c
===================================================================
--- subversion/clients/cmdline/switch-cmd.c
+++ subversion/clients/cmdline/switch-cmd.c	Mon Sep 30 18:24:33 2002
@@ -21,18 +21,54 @@
 
 
 /*** Includes. ***/
-
 #include "svn_wc.h"
 #include "svn_client.h"
 #include "svn_string.h"
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_pools.h"
 #include "cl.h"
 
 
 /*** Code. ***/
 
+static svn_error_t *
+rewrite_urls(apr_array_header_t *targets,
+             svn_boolean_t recurse,
+             apr_pool_t *pool)
+{
+  apr_pool_t *subpool;
+  const char *from;
+  const char *to;
+  int i;
+ 
+  if (targets->nelts < 2)
+    return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
+          
+  from = ((const char **) (targets->elts))[0];
+  to = ((const char **) (targets->elts))[1];
+ 
+  subpool = svn_pool_create (pool);
+
+  if (targets->nelts == 2)
+    {
+      SVN_ERR(svn_client_relocate ("", from, to, recurse, pool));
+    }
+  else
+    {
+      for (i = 2; i < targets->nelts; i++)
+        {
+          const char *target = ((const char **) (targets->elts))[i];
+          SVN_ERR (svn_client_relocate (target, from, to, recurse, subpool));
+          svn_pool_clear (subpool);
+        }
+    }
+
+  svn_pool_destroy (subpool);
+  return SVN_NO_ERROR;
+}
+
 
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
@@ -59,6 +95,10 @@
                                          &(opt_state->end_revision),
                                          FALSE, pool));
 
+  /* handle only-rewrite case specially */
+  if (opt_state->only_rewrite_urls)
+    return rewrite_urls (targets, !opt_state->nonrecursive, pool);
+
   if ((targets->nelts < 1) || (targets->nelts > 2))
     return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
 
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c
+++ subversion/clients/cmdline/main.c	Mon Sep 30 18:24:33 2002
@@ -85,6 +85,8 @@
                       "disregard default and svn:ignore property ignores"},
     {"no-auth-cache", svn_cl__no_auth_cache_opt, 0,
                       "do not cache authentication tokens"},
+    {"only-rewrite-urls", svn_cl__only_rewrite_urls_opt, 0,
+                      "only rewrite urls; do not contact a repository"},
     {0,               0, 0, 0}
   };
 
@@ -378,10 +380,12 @@
   
   { "switch", svn_cl__switch, {"sw"},
     "Update working copy to mirror a new URL\n"
-    "usage: switch REPOS_URL [TARGET]\n\n"
+    "usage: switch REPOS_URL [TARGET]   or\n"
+    "       switch --only-rewrite-urls [FROM] [TO] [TARGET ...]\n\n"
     "   Note:  this is the way to move a working copy to a new branch.\n",
     { 'r', 'D', 'N', 'q', svn_cl__auth_username_opt,
-      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt} },
+      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt,
+      svn_cl__only_rewrite_urls_opt } },
  
   { "update", svn_cl__update, {"up"}, 
     "Bring changes from the repository into the working copy.\n"
@@ -404,7 +408,6 @@
   { NULL, NULL, {0}, NULL, {0} }
 };
 
-
 
 /*** Main. ***/
 
@@ -667,6 +670,9 @@
       case svn_cl__no_auth_cache_opt:
         opt_state.no_auth_cache = TRUE;
         break;
+      case svn_cl__only_rewrite_urls_opt:
+        opt_state.only_rewrite_urls = TRUE;
+        break;
       case 'x':
         err = svn_utf_cstring_to_utf8 (&opt_state.extensions, opt_arg,
                                        NULL, pool);
Index: subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
===================================================================
--- subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout	Mon Sep 30 18:24:33 2002
@@ -27,7 +27,8 @@
   --xml                    : output in xml
 
 switch (sw): Update working copy to mirror a new URL
-usage: switch REPOS_URL [TARGET]
+usage: switch REPOS_URL [TARGET]   or
+       switch --only-rewrite-urls [FROM] [TO] [TARGET ...]
 
    Note:  this is the way to move a working copy to a new branch.
 
@@ -39,4 +40,5 @@
   --username arg           : specify a username ARG
   --password arg           : specify a password ARG
   --no-auth-cache          : do not cache authentication tokens
+  --only-rewrite-urls      : only rewrite urls; do not contact a repository
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Philip Martin <ph...@codematters.co.uk>.
mark benedetto king <bk...@Inquira.Com> writes:

> Index: subversion/libsvn_wc/relocate.c
> ===================================================================
> --- subversion/libsvn_wc/relocate.c
> +++ subversion/libsvn_wc/relocate.c	Mon Sep 30 18:46:07 2002
> @@ -0,0 +1,125 @@
[snip]
> +
> +svn_error_t *
> +svn_wc_relocate (const char *path,
> +                 svn_wc_adm_access_t *adm_access,
> +                 const char *from,
> +                 const char *to,
> +                 svn_boolean_t recurse,
> +                 apr_pool_t *pool)
> +{
> +  enum svn_node_kind kind;
> +  apr_hash_t *entries = NULL;
> +  apr_hash_index_t *hi;
> +  svn_boolean_t is_file = FALSE;
> +  char *base;
> +  int from_len;
> +
> +  SVN_ERR(svn_io_check_path(path, &kind, pool));
> +
> +  if (kind == svn_node_file)
> +    {
> +      base = svn_path_basename(path, pool);
> +      is_file = TRUE;
> +    }
> +
> +  from_len = strlen(from);
> +
> +  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool));
> +
> +  if (is_file)
> +    {
> +      const char *url;
> +      svn_wc_entry_t *this_dir = apr_hash_get(entries,
> +                                              SVN_WC_ENTRY_THIS_DIR,
> +                                              APR_HASH_KEY_STRING);
> +      svn_wc_entry_t *entry = apr_hash_get(entries, base, APR_HASH_KEY_STRING);
> +      if (!this_dir)
> +        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
> +                                "missing default entry");
> +      if (!entry)
> +        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
> +                                "missing entry");
> +
> +      url = entry->url;
> +      if (!url) 
> +        url = svn_path_join(this_dir->url, base, pool);

This still doesn't look right.  If the entry didn't originally have an
URL why are you creating one?  Why is this logic different from the
logic in the the loop below?  If the file doesn't have an URL then I
don't think relocate should create one.  Trying to relocate a file
without an URL might perhaps produce an error or it might not, I could
argue either way.

> +
> +      if (!strncmp(url, from, from_len))
> +        {
> +          entry->url = apr_psprintf (pool, "%s%s", to, url + from_len);

Didn't spot this yesterday, but this is not right, see below.

> +          SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
> +        }
> +
> +      return SVN_NO_ERROR;
> +    }
> +
> +  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
> +    {
> +      const void *key;
> +      void *val;
> +      svn_wc_entry_t *entry;
> +
> +      apr_hash_this(hi, &key, NULL, &val);
> +      entry = val;
> +
> + 
> +      if (recurse
> +          && (entry->kind == svn_node_dir)
> +          && (strcmp(key, SVN_WC_ENTRY_THIS_DIR) != 0))
> +        {
> +          svn_wc_adm_access_t *subdir_access;
> +          const char *subdir = svn_path_join (path, key, pool);
> +          SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, subdir,
> +                                      pool));
> +          SVN_ERR(svn_wc_relocate(subdir, subdir_access, from,
> +                                   to, recurse, pool));
> +        }
> +
> +      if (entry->url &&
> +          (strncmp(entry->url, from, from_len) == 0))
> +        entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);

This has the same problem as the single file apr_psprintf above, it
modifies the access baton's entry cache, but doesn't use the right
pool.  Memory used to modify the access baton entry cache must come
from the access baton pool.  There are two solutions, either a) use
svn_wc__entry_modify which does its own allocation, or b) use
svn_wc_adm_access_pool to get the access baton pool for use in
apr_psprintf.  Solution a) is perhaps simpler for someone reading the
code to understand, but b) is more efficient (at the moment) since it
doesn't rewrite the entries file for each entry modified.

In rev 3232, in most of the places that use svn_wc_entries_read, I
changed the svn_wc_entry_t pointers so that they were const, to avoid
any accidental cache modifications.

Having said that, as you haven't used any subpools the memory
allocation happens to be correct :)  However, svn_wc_relocate should
not rely on its POOL argument being suitable for caching in
ADM_ACCESS, it's not guaranteed to work.

> +    }
> +
> +  SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
> +
> +  return SVN_NO_ERROR;
> +}
> +

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by mark benedetto king <bk...@inquira.com>.
Updated patch follows in-line comments.

On Mon, Sep 30, 2002 at 10:48:41PM +0100, Philip Martin wrote:
> > +      base = svn_path_basename(path, pool);
> > +      path = svn_path_remove_component_nts(path, pool);
> 
> svn_path_split_nts does both these, but I don't see why you are
> changing path here, it doesn't get used for files.
> 

Right.  Useless code.  Removed.

> > +      url = entry->url? entry->url : this_dir->url;
> 
> I don't understand this bit, if the file doesn't have an URL you are
> using the parent directory's URL as the file URL.  Does this work?

No, it doesn't.  Fixed.

> 
> Here files don't fallback on the parent directory's URL, which I think
> is correct but is different to the behaviour above.
> 

Right.

> > +  err = svn_wc_relocate(path, adm_access, from, to, recurse, pool);
> > +
> > +  err2 = svn_wc_adm_close(adm_access);
> 
> You don't need err/err2, you can use SVN_ERR here.  If an error occurs
> a pool cleanup handler will close the access baton.

Sweet.


--ben



New subcommand: "relocate".  Useful for when the URL by which the
repository must be referred to has changed.  This happens most
frequently for mobile users.  These changes were greatly improved
by feedback from Philip Martin.

* subversion/include/svn_wc.h
  (svn_wc_relocate): Prototype for new function.

* subversion/include/svn_client.h
  (svn_client_relocate): Prototype for new function.

* subversion/libsvn_wc/relocate.c
  New file.  Includes implementation of svn_wc_relocate().
  Should eventually verify that new URL is valid; doesn't
  do any validation at all right now.

* subversion/libsvn_client/relocate.c
  New file.  Includes implementation of svn_client_relocate().

* subversion/clients/cmdline/cl.h
  (svn_cl__relocate): Added subcommand prototype.  Fixed
  alphabetical-order of resolve/revert.

* subversion/clients/cmdline/relocate-cmd.c
  New file.  Includes implementation of svn_cl__relocate().

* subversion/clients/cmdline/main.c
  (svn_cl__cmd_table): Added entry for "relocate".

* subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
  Adjust expected output.


Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h
+++ subversion/include/svn_wc.h	Mon Sep 30 18:24:33 2002
@@ -1481,6 +1481,19 @@
                 svn_wc_adm_access_t *optional_adm_access,
                 apr_pool_t *pool);
 
+/* Changing repository references at PATH that begin with
+   FROM to begin with TO instead.  Perform necessary allocations in
+   POOL.  If RECURSE is true, do so.
+
+   ADM_ACCESS is an access baton for the directory containing
+   PATH. ADM_ACCESS must not be NULL.  */
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool);
 
 /* Revert changes to PATH (perhaps in a RECURSIVE fashion).  Perform
    necessary allocations in POOL.
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h
+++ subversion/include/svn_client.h	Mon Sep 30 18:24:33 2002
@@ -652,6 +652,17 @@
                     apr_pool_t *pool);
 
 
+/* Modify a working copy directory DIR, changing any
+   repository URLs that begin with FROM to begin with TO instead,
+   recursing into subdirectories if RECURSE is true. */
+svn_error_t *
+svn_client_relocate (const char *dir,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool);
+
+
 /* Restore the pristine version of a working copy PATH, effectively
    undoing any local mods.  If PATH is a directory, and RECURSIVE is
    TRUE, this will be a recursive operation.
Index: subversion/libsvn_wc/relocate.c
===================================================================
--- subversion/libsvn_wc/relocate.c
+++ subversion/libsvn_wc/relocate.c	Mon Sep 30 18:46:07 2002
@@ -0,0 +1,125 @@
+/*
+ * relocate.c: do wc repos relocation
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include "svn_wc.h"
+#include "svn_error.h"
+#include "svn_string.h"
+#include "svn_xml.h"
+#include "svn_pools.h"
+#include "svn_io.h"
+
+#include "wc.h"
+#include "entries.h"
+
+
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool)
+{
+  enum svn_node_kind kind;
+  apr_hash_t *entries = NULL;
+  apr_hash_index_t *hi;
+  svn_boolean_t is_file = FALSE;
+  char *base;
+  int from_len;
+
+  SVN_ERR(svn_io_check_path(path, &kind, pool));
+
+  if (kind == svn_node_file)
+    {
+      base = svn_path_basename(path, pool);
+      is_file = TRUE;
+    }
+
+  from_len = strlen(from);
+
+  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool));
+
+  if (is_file)
+    {
+      const char *url;
+      svn_wc_entry_t *this_dir = apr_hash_get(entries,
+                                              SVN_WC_ENTRY_THIS_DIR,
+                                              APR_HASH_KEY_STRING);
+      svn_wc_entry_t *entry = apr_hash_get(entries, base, APR_HASH_KEY_STRING);
+      if (!this_dir)
+        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
+                                "missing default entry");
+      if (!entry)
+        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
+                                "missing entry");
+
+      url = entry->url;
+      if (!url) 
+        url = svn_path_join(this_dir->url, base, pool);
+
+      if (!strncmp(url, from, from_len))
+        {
+          entry->url = apr_psprintf (pool, "%s%s", to, url + from_len);
+          SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+        }
+
+      return SVN_NO_ERROR;
+    }
+
+  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      svn_wc_entry_t *entry;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      entry = val;
+
+ 
+      if (recurse
+          && (entry->kind == svn_node_dir)
+          && (strcmp(key, SVN_WC_ENTRY_THIS_DIR) != 0))
+        {
+          svn_wc_adm_access_t *subdir_access;
+          const char *subdir = svn_path_join (path, key, pool);
+          SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, subdir,
+                                      pool));
+          SVN_ERR(svn_wc_relocate(subdir, subdir_access, from,
+                                   to, recurse, pool));
+        }
+
+      if (entry->url &&
+          (strncmp(entry->url, from, from_len) == 0))
+        entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);
+    }
+
+  SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end:
+ */
+
Index: subversion/libsvn_client/relocate.c
===================================================================
--- subversion/libsvn_client/relocate.c
+++ subversion/libsvn_client/relocate.c	Mon Sep 30 18:48:33 2002
@@ -0,0 +1,61 @@
+/*
+ * relocate.c:  wrapper around wc relocation functionality.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_path.h"
+#include "client.h"
+
+
+
+/*** Code. ***/
+
+svn_error_t *
+svn_client_relocate (const char *path,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool)
+{
+  svn_wc_adm_access_t *adm_access;
+
+  SVN_ERR (svn_wc_adm_probe_open(&adm_access, NULL, path,
+                                 TRUE, recurse, pool));
+
+  SVN_ERR(svn_wc_relocate(path, adm_access, from, to, recurse, pool));
+
+  SVN_ERR(svn_wc_adm_close(adm_access));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end: */
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h
+++ subversion/clients/cmdline/cl.h	Mon Sep 30 18:24:33 2002
@@ -54,7 +54,8 @@
   svn_cl__xml_opt,
   svn_cl__strict_opt,
   svn_cl__no_ignore_opt,
-  svn_cl__no_auth_cache_opt
+  svn_cl__no_auth_cache_opt,
+  svn_cl__only_rewrite_urls_opt
 } svn_cl__longopt_t;
 
 
@@ -94,6 +95,7 @@
   svn_boolean_t xml;             /* output in xml, e.g., "svn log --xml" */
   svn_boolean_t no_ignore;       /* disregard default ignores & svn:ignore's */
   svn_boolean_t no_auth_cache;   /* do not cache authentication information */
+  svn_boolean_t only_rewrite_urls; /* rewrite urls (svn switch) */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/switch-cmd.c
===================================================================
--- subversion/clients/cmdline/switch-cmd.c
+++ subversion/clients/cmdline/switch-cmd.c	Mon Sep 30 18:24:33 2002
@@ -21,18 +21,54 @@
 
 
 /*** Includes. ***/
-
 #include "svn_wc.h"
 #include "svn_client.h"
 #include "svn_string.h"
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_pools.h"
 #include "cl.h"
 
 
 /*** Code. ***/
 
+static svn_error_t *
+rewrite_urls(apr_array_header_t *targets,
+             svn_boolean_t recurse,
+             apr_pool_t *pool)
+{
+  apr_pool_t *subpool;
+  const char *from;
+  const char *to;
+  int i;
+ 
+  if (targets->nelts < 2)
+    return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
+          
+  from = ((const char **) (targets->elts))[0];
+  to = ((const char **) (targets->elts))[1];
+ 
+  subpool = svn_pool_create (pool);
+
+  if (targets->nelts == 2)
+    {
+      SVN_ERR(svn_client_relocate ("", from, to, recurse, pool));
+    }
+  else
+    {
+      for (i = 2; i < targets->nelts; i++)
+        {
+          const char *target = ((const char **) (targets->elts))[i];
+          SVN_ERR (svn_client_relocate (target, from, to, recurse, subpool));
+          svn_pool_clear (subpool);
+        }
+    }
+
+  svn_pool_destroy (subpool);
+  return SVN_NO_ERROR;
+}
+
 
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
@@ -59,6 +95,10 @@
                                          &(opt_state->end_revision),
                                          FALSE, pool));
 
+  /* handle only-rewrite case specially */
+  if (opt_state->only_rewrite_urls)
+    return rewrite_urls (targets, !opt_state->nonrecursive, pool);
+
   if ((targets->nelts < 1) || (targets->nelts > 2))
     return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
 
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c
+++ subversion/clients/cmdline/main.c	Mon Sep 30 18:24:33 2002
@@ -85,6 +85,8 @@
                       "disregard default and svn:ignore property ignores"},
     {"no-auth-cache", svn_cl__no_auth_cache_opt, 0,
                       "do not cache authentication tokens"},
+    {"only-rewrite-urls", svn_cl__only_rewrite_urls_opt, 0,
+                      "only rewrite urls; do not contact a repository"},
     {0,               0, 0, 0}
   };
 
@@ -378,10 +380,12 @@
   
   { "switch", svn_cl__switch, {"sw"},
     "Update working copy to mirror a new URL\n"
-    "usage: switch REPOS_URL [TARGET]\n\n"
+    "usage: switch REPOS_URL [TARGET]   or\n"
+    "       switch --only-rewrite-urls [FROM] [TO] [TARGET ...]\n\n"
     "   Note:  this is the way to move a working copy to a new branch.\n",
     { 'r', 'D', 'N', 'q', svn_cl__auth_username_opt,
-      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt} },
+      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt,
+      svn_cl__only_rewrite_urls_opt } },
  
   { "update", svn_cl__update, {"up"}, 
     "Bring changes from the repository into the working copy.\n"
@@ -404,7 +408,6 @@
   { NULL, NULL, {0}, NULL, {0} }
 };
 
-
 
 /*** Main. ***/
 
@@ -667,6 +670,9 @@
       case svn_cl__no_auth_cache_opt:
         opt_state.no_auth_cache = TRUE;
         break;
+      case svn_cl__only_rewrite_urls_opt:
+        opt_state.only_rewrite_urls = TRUE;
+        break;
       case 'x':
         err = svn_utf_cstring_to_utf8 (&opt_state.extensions, opt_arg,
                                        NULL, pool);
Index: subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
===================================================================
--- subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout	Mon Sep 30 18:24:33 2002
@@ -27,7 +27,8 @@
   --xml                    : output in xml
 
 switch (sw): Update working copy to mirror a new URL
-usage: switch REPOS_URL [TARGET]
+usage: switch REPOS_URL [TARGET]   or
+       switch --only-rewrite-urls [FROM] [TO] [TARGET ...]
 
    Note:  this is the way to move a working copy to a new branch.
 
@@ -39,4 +40,5 @@
   --username arg           : specify a username ARG
   --password arg           : specify a password ARG
   --no-auth-cache          : do not cache authentication tokens
+  --only-rewrite-urls      : only rewrite urls; do not contact a repository
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Philip Martin <ph...@codematters.co.uk>.
mark benedetto king <bk...@Inquira.Com> writes:

> Index: subversion/libsvn_wc/relocate.c
> ===================================================================
> --- subversion/libsvn_wc/relocate.c
> +++ subversion/libsvn_wc/relocate.c	Mon Sep 30 16:26:04 2002
> @@ -0,0 +1,123 @@
[snip]
> +svn_error_t *
> +svn_wc_relocate (const char *path,
> +                 svn_wc_adm_access_t *adm_access,
> +                 const char *from,
> +                 const char *to,
> +                 svn_boolean_t recurse,
> +                 apr_pool_t *pool)
> +{
> +  enum svn_node_kind kind;
> +  apr_hash_t *entries = NULL;
> +  apr_hash_index_t *hi;
> +  svn_boolean_t is_file = FALSE;
> +  char *base;
> +  int from_len;
> +
> +  SVN_ERR(svn_io_check_path(path, &kind, pool));
> +
> +  if (kind == svn_node_file)
> +    {
> +      base = svn_path_basename(path, pool);
> +      path = svn_path_remove_component_nts(path, pool);

svn_path_split_nts does both these, but I don't see why you are
changing path here, it doesn't get used for files.

> +      is_file = TRUE;
> +    }
> +
> +  from_len = strlen(from);
> +
> +  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool));
> +
> +  if (is_file)
> +    {
> +      const char *url;
> +      svn_wc_entry_t *this_dir = apr_hash_get(entries,
> +                                              SVN_WC_ENTRY_THIS_DIR,
> +                                              APR_HASH_KEY_STRING);
> +      svn_wc_entry_t *entry = apr_hash_get(entries, base, APR_HASH_KEY_STRING);
> +      if (!this_dir)
> +        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
> +                                "missing default entry");
> +      if (!entry)
> +        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
> +                                "missing entry");
> +
> +      url = entry->url? entry->url : this_dir->url;

I don't understand this bit, if the file doesn't have an URL you are
using the parent directory's URL as the file URL.  Does this work?

> +      if (url &&
> +          (strncmp(url, from, from_len) == 0))
> +        entry->url = apr_psprintf (pool, "%s%s", to, url + from_len);
> +  
> +      SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
> +
> +      return SVN_NO_ERROR;
> +    }
> +
> +  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
> +    {
> +      const void *key;
> +      void *val;
> +      svn_wc_entry_t *entry;
> +
> +      apr_hash_this(hi, &key, NULL, &val);
> +      entry = val;
> +
> + 
> +      if (recurse
> +          && (entry->kind == svn_node_dir)
> +          && (strcmp(key, SVN_WC_ENTRY_THIS_DIR) != 0))
> +        {
> +          svn_wc_adm_access_t *subdir_access;
> +          const char *subdir = svn_path_join (path, key, pool);
> +          SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, subdir,
> +                                      pool));
> +          SVN_ERR(svn_wc_relocate(subdir, subdir_access, from,
> +                                   to, recurse, pool));
> +        }
> +
> +      if (entry->url &&
> +          (strncmp(entry->url, from, from_len) == 0))
> +        entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);

Here files don't fallback on the parent directory's URL, which I think
is correct but is different to the behaviour above.

> +    }
> +
> +  SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
> +
> +  return SVN_NO_ERROR;
> +}
> +
> Index: subversion/libsvn_client/relocate.c
> ===================================================================
> --- subversion/libsvn_client/relocate.c
> +++ subversion/libsvn_client/relocate.c	Tue Sep 24 17:27:07 2002
> @@ -0,0 +1,63 @@
[snip]
> +
> +/*** Code. ***/
> +
> +svn_error_t *
> +svn_client_relocate (const char *path,
> +                     const char *from,
> +                     const char *to,
> +                     svn_boolean_t recurse,
> +                     apr_pool_t *pool)
> +{
> +  svn_wc_adm_access_t *adm_access;
> +  svn_error_t *err;
> +  svn_error_t *err2;
> +
> +  SVN_ERR (svn_wc_adm_probe_open(&adm_access, NULL, path,
> +                                 TRUE, recurse, pool));
> +
> +  err = svn_wc_relocate(path, adm_access, from, to, recurse, pool);
> +
> +  err2 = svn_wc_adm_close(adm_access);

You don't need err/err2, you can use SVN_ERR here.  If an error occurs
a pool cleanup handler will close the access baton.

> +
> +  return err ? err : err2;
> +}

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by mark benedetto king <bk...@inquira.com>.
Comments inline, updated patch below.  Sorry it took me so long
to respond.


On Tue, Sep 24, 2002 at 12:14:01PM +0100, Philip Martin wrote:
> mark benedetto king <bk...@inquira.com> writes:
> 
> I don't really like this approach, I'd prefer a command that contacts
> the new repository, to ensure that we don't get invalid text-bases.
> The current patch would be the only client command that, by design,
> will allow the user to produce a corrupt working copy.
> 

Neither do I, but one step at a time...  I need to get these changes
out of my WC.

> That said, here is a short review to help get this working with the
> recent access baton changes :)
> 

Thanks once again for your (always constructive) criticism.

> I don't like the optional access baton, just make it required.  Yes,
> there are already some optional ones (I put them in) but I'd like to
> remove those and I don't think we should add more of them.
> 

Done.

> > +svn_error_t *
> > +svn_wc_relocate (const char *path,
> > +                 svn_wc_adm_access_t *adm_access,
> > +                 const char *from,
> > +                 const char *to,
> > +                 apr_pool_t *pool);
> 
> Do we need to support the --nonrecursive option?
> 

Done.

> >  
> > +/* Recursively modify a working copy directory DIR, changing any
> > +   repository URLs that begin with FROM to begin with TO instead. */
> > +svn_error_t *
> > +svn_client_relocate (const char *dir,
> > +                     const char *from,
> > +                     const char *to,
> > +                     apr_pool_t *pool);
> 
> Support --nonrecursive here as well?


Done.

> > +
> > +  SVN_ERR (svn_wc_check_wc (path, &is_wc, pool));
> > +  if (! is_wc)
> > +    return svn_error_createf
> > +      (SVN_ERR_WC_NOT_DIRECTORY, 0, NULL, pool,
> > +       "svn_wc_cleanup: %s is not a working copy directory", path);
> 
> Need to support PATH being a file.
> 

Done.

> > +
> > +  if (! adm_access)
> > +    {
> > +      SVN_ERR (svn_wc_adm_open (&adm_access, NULL, path, TRUE, TRUE, pool));
> 
> Put this bit into svn_client_relocate.

Done.

> 
> > +      root = TRUE;
> > +    }
> > +
> > +  from_len = strlen(from);
> > +
> > +  SVN_ERR (svn_wc_entries_read (&entries, path, FALSE, pool));
> 
> Need to pass ADM_ACCESS.

Done.

> > +      if ((entry->kind == svn_node_dir)
> > +          && (strcmp (key, SVN_WC_ENTRY_THIS_DIR) != 0))
> > +        {
> > +          /* Recurse */
> > +          const char *subdir = svn_path_join (path, key, pool);
> 
> You will need to add something like
> 
>             svn_wc_adm_access_t *subdir_access;
>             SVN_ERR (svn_wc_adm_retrieve (&subdir_access, adm_access, subdir,
>                                           pool));
> 
> > +          SVN_ERR (svn_wc_relocate (subdir, adm_access, from, to, pool));
> 
> and pass subdir_access instead of adm_access.

Done.

> 
> > +        }
> > +     
> > +      if (entry->url &&
> > +          (strncmp(entry->url, from, from_len) == 0))
> > +          entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);
> 
> You will be modifying the cache, but I think it's OK since you are
> about to write it out again.

Right.

> 
> > +    }
> > +
> > +  SVN_ERR (svn_wc__entries_write (entries, path, pool));
> 
> Need to pass ADM_ACCESS.

Done.
> 
> > +
> > +  if (root)
> > +    svn_wc_adm_close(adm_access);
> 
> Put this bit into svn_client_relocate.

Done.


> > +  SVN_ERR (svn_io_check_path (dir, &kind, pool));
> > +  if (kind != svn_node_dir)
> > +    return svn_error_createf (SVN_ERR_WC_NOT_DIRECTORY, 0, NULL, pool,
> > +                              "Cannot relocate '%s' -- not a directory", 
> > +                              dir);
> > +
> 
> We need to support files, so don't bother with the above check.  Just
> do something like
> 
>      svn_wc_adm_access_t *adm_access;
>      SVN_ERR (svn_wc_adm_probe_open (&adm_access, NULL, path, TRUE, recurse,
>               pool));
> 
> > +  return svn_wc_relocate (dir, NULL, from, to, pool);
> 
> Pass adm_access to svn_wc_relocate, and then close it.
> 
>      SVN_ERR (svn_wc_adm_close (adm_access));
> 

Done.


--ben


Patch:

New subcommand: "relocate".  Useful for when the URL by which the
repository must be referred to has changed.  This happens most
frequently for mobile users.

* subversion/include/svn_wc.h
  (svn_wc_relocate): Prototype for new function.

* subversion/include/svn_client.h
  (svn_client_relocate): Prototype for new function.

* subversion/libsvn_wc/relocate.c
  New file.  Includes implementation of svn_wc_relocate().
  Should eventually verify that new URL is valid; doesn't
  do any validation at all right now.

* subversion/libsvn_client/relocate.c
  New file.  Includes implementation of svn_client_relocate().

* subversion/clients/cmdline/cl.h
  (svn_cl__relocate): Added subcommand prototype.  Fixed
  alphabetical-order of resolve/revert.

* subversion/clients/cmdline/relocate-cmd.c
  New file.  Includes implementation of svn_cl__relocate().

* subversion/clients/cmdline/main.c
  (svn_cl__cmd_table): Added entry for "relocate".

* subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
  Adjust expected output.

Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h
+++ subversion/include/svn_wc.h	Fri Sep 27 18:55:43 2002
@@ -1481,6 +1481,19 @@
                 svn_wc_adm_access_t *optional_adm_access,
                 apr_pool_t *pool);
 
+/* Changing repository references at PATH that begin with
+   FROM to begin with TO instead.  Perform necessary allocations in
+   POOL.  If RECURSE is true, do so.
+
+   ADM_ACCESS is an access baton for the directory containing
+   PATH. ADM_ACCESS must not be NULL.  */
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool);
 
 /* Revert changes to PATH (perhaps in a RECURSIVE fashion).  Perform
    necessary allocations in POOL.
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h
+++ subversion/include/svn_client.h	Fri Sep 27 18:55:44 2002
@@ -652,6 +652,17 @@
                     apr_pool_t *pool);
 
 
+/* Modify a working copy directory DIR, changing any
+   repository URLs that begin with FROM to begin with TO instead,
+   recursing into subdirectories if RECURSE is true. */
+svn_error_t *
+svn_client_relocate (const char *dir,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool);
+
+
 /* Restore the pristine version of a working copy PATH, effectively
    undoing any local mods.  If PATH is a directory, and RECURSIVE is
    TRUE, this will be a recursive operation.
Index: subversion/libsvn_wc/relocate.c
===================================================================
--- subversion/libsvn_wc/relocate.c
+++ subversion/libsvn_wc/relocate.c	Mon Sep 30 16:26:04 2002
@@ -0,0 +1,123 @@
+/*
+ * relocate.c: do wc repos relocation
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include "svn_wc.h"
+#include "svn_error.h"
+#include "svn_string.h"
+#include "svn_xml.h"
+#include "svn_pools.h"
+#include "svn_io.h"
+
+#include "wc.h"
+#include "entries.h"
+
+
+svn_error_t *
+svn_wc_relocate (const char *path,
+                 svn_wc_adm_access_t *adm_access,
+                 const char *from,
+                 const char *to,
+                 svn_boolean_t recurse,
+                 apr_pool_t *pool)
+{
+  enum svn_node_kind kind;
+  apr_hash_t *entries = NULL;
+  apr_hash_index_t *hi;
+  svn_boolean_t is_file = FALSE;
+  char *base;
+  int from_len;
+
+  SVN_ERR(svn_io_check_path(path, &kind, pool));
+
+  if (kind == svn_node_file)
+    {
+      base = svn_path_basename(path, pool);
+      path = svn_path_remove_component_nts(path, pool);
+      is_file = TRUE;
+    }
+
+  from_len = strlen(from);
+
+  SVN_ERR(svn_wc_entries_read(&entries, adm_access, FALSE, pool));
+
+  if (is_file)
+    {
+      const char *url;
+      svn_wc_entry_t *this_dir = apr_hash_get(entries,
+                                              SVN_WC_ENTRY_THIS_DIR,
+                                              APR_HASH_KEY_STRING);
+      svn_wc_entry_t *entry = apr_hash_get(entries, base, APR_HASH_KEY_STRING);
+      if (!this_dir)
+        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
+                                "missing default entry");
+      if (!entry)
+        return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, 0, NULL, pool,
+                                "missing entry");
+
+      url = entry->url? entry->url : this_dir->url;
+      if (url &&
+          (strncmp(url, from, from_len) == 0))
+        entry->url = apr_psprintf (pool, "%s%s", to, url + from_len);
+  
+      SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+
+      return SVN_NO_ERROR;
+    }
+
+  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      svn_wc_entry_t *entry;
+
+      apr_hash_this(hi, &key, NULL, &val);
+      entry = val;
+
+ 
+      if (recurse
+          && (entry->kind == svn_node_dir)
+          && (strcmp(key, SVN_WC_ENTRY_THIS_DIR) != 0))
+        {
+          svn_wc_adm_access_t *subdir_access;
+          const char *subdir = svn_path_join (path, key, pool);
+          SVN_ERR(svn_wc_adm_retrieve(&subdir_access, adm_access, subdir,
+                                      pool));
+          SVN_ERR(svn_wc_relocate(subdir, subdir_access, from,
+                                   to, recurse, pool));
+        }
+
+      if (entry->url &&
+          (strncmp(entry->url, from, from_len) == 0))
+        entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);
+    }
+
+  SVN_ERR(svn_wc__entries_write (entries, adm_access, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end:
+ */
+
Index: subversion/libsvn_client/relocate.c
===================================================================
--- subversion/libsvn_client/relocate.c
+++ subversion/libsvn_client/relocate.c	Tue Sep 24 17:27:07 2002
@@ -0,0 +1,63 @@
+/*
+ * relocate.c:  wrapper around wc relocation functionality.
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_path.h"
+#include "client.h"
+
+
+
+/*** Code. ***/
+
+svn_error_t *
+svn_client_relocate (const char *path,
+                     const char *from,
+                     const char *to,
+                     svn_boolean_t recurse,
+                     apr_pool_t *pool)
+{
+  svn_wc_adm_access_t *adm_access;
+  svn_error_t *err;
+  svn_error_t *err2;
+
+  SVN_ERR (svn_wc_adm_probe_open(&adm_access, NULL, path,
+                                 TRUE, recurse, pool));
+
+  err = svn_wc_relocate(path, adm_access, from, to, recurse, pool);
+
+  err2 = svn_wc_adm_close(adm_access);
+
+  return err ? err : err2;
+}
+
+
+
+/* 
+ * local variables:
+ * eval: (load-file "../../tools/dev/svn-dev.el")
+ * end: */
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h
+++ subversion/clients/cmdline/cl.h	Mon Sep 30 15:19:59 2002
@@ -54,7 +54,8 @@
   svn_cl__xml_opt,
   svn_cl__strict_opt,
   svn_cl__no_ignore_opt,
-  svn_cl__no_auth_cache_opt
+  svn_cl__no_auth_cache_opt,
+  svn_cl__only_rewrite_urls_opt
 } svn_cl__longopt_t;
 
 
@@ -94,6 +95,7 @@
   svn_boolean_t xml;             /* output in xml, e.g., "svn log --xml" */
   svn_boolean_t no_ignore;       /* disregard default ignores & svn:ignore's */
   svn_boolean_t no_auth_cache;   /* do not cache authentication information */
+  svn_boolean_t only_rewrite_urls; /* rewrite urls (svn switch) */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/switch-cmd.c
===================================================================
--- subversion/clients/cmdline/switch-cmd.c
+++ subversion/clients/cmdline/switch-cmd.c	Mon Sep 30 15:25:31 2002
@@ -21,18 +21,54 @@
 
 
 /*** Includes. ***/
-
 #include "svn_wc.h"
 #include "svn_client.h"
 #include "svn_string.h"
 #include "svn_path.h"
 #include "svn_delta.h"
 #include "svn_error.h"
+#include "svn_pools.h"
 #include "cl.h"
 
 
 /*** Code. ***/
 
+static svn_error_t *
+rewrite_urls(apr_array_header_t *targets,
+             svn_boolean_t recurse,
+             apr_pool_t *pool)
+{
+  apr_pool_t *subpool;
+  const char *from;
+  const char *to;
+  int i;
+ 
+  if (targets->nelts < 2)
+    return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
+          
+  from = ((const char **) (targets->elts))[0];
+  to = ((const char **) (targets->elts))[1];
+ 
+  subpool = svn_pool_create (pool);
+
+  if (targets->nelts == 2)
+    {
+      SVN_ERR(svn_client_relocate ("", from, to, recurse, pool));
+    }
+  else
+    {
+      for (i = 2; i < targets->nelts; i++)
+        {
+          const char *target = ((const char **) (targets->elts))[i];
+          SVN_ERR (svn_client_relocate (target, from, to, recurse, subpool));
+          svn_pool_clear (subpool);
+        }
+    }
+
+  svn_pool_destroy (subpool);
+  return SVN_NO_ERROR;
+}
+
 
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
@@ -59,6 +95,10 @@
                                          &(opt_state->end_revision),
                                          FALSE, pool));
 
+  /* handle only-rewrite case specially */
+  if (opt_state->only_rewrite_urls)
+    return rewrite_urls (targets, !opt_state->nonrecursive, pool);
+
   if ((targets->nelts < 1) || (targets->nelts > 2))
     return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
 
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c
+++ subversion/clients/cmdline/main.c	Fri Sep 27 20:07:19 2002
@@ -85,6 +85,8 @@
                       "disregard default and svn:ignore property ignores"},
     {"no-auth-cache", svn_cl__no_auth_cache_opt, 0,
                       "do not cache authentication tokens"},
+    {"only-rewrite-urls", svn_cl__only_rewrite_urls_opt, 0,
+                      "only rewrite urls; do not contact a repository"},
     {0,               0, 0, 0}
   };
 
@@ -378,10 +380,12 @@
   
   { "switch", svn_cl__switch, {"sw"},
     "Update working copy to mirror a new URL\n"
-    "usage: switch REPOS_URL [TARGET]\n\n"
+    "usage: switch REPOS_URL [TARGET]   or\n"
+    "       switch --only-rewrite-urls [FROM] [TO] [TARGET ...]\n\n"
     "   Note:  this is the way to move a working copy to a new branch.\n",
     { 'r', 'D', 'N', 'q', svn_cl__auth_username_opt,
-      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt} },
+      svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt,
+      svn_cl__only_rewrite_urls_opt } },
  
   { "update", svn_cl__update, {"up"}, 
     "Bring changes from the repository into the working copy.\n"
@@ -404,7 +408,6 @@
   { NULL, NULL, {0}, NULL, {0} }
 };
 
-
 
 /*** Main. ***/
 
@@ -667,6 +670,9 @@
       case svn_cl__no_auth_cache_opt:
         opt_state.no_auth_cache = TRUE;
         break;
+      case svn_cl__only_rewrite_urls_opt:
+        opt_state.only_rewrite_urls = TRUE;
+        break;
       case 'x':
         err = svn_utf_cstring_to_utf8 (&opt_state.extensions, opt_arg,
                                        NULL, pool);
Index: subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
===================================================================
--- subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout	Thu Sep 26 17:44:42 2002
@@ -27,7 +27,8 @@
   --xml                    : output in xml
 
 switch (sw): Update working copy to mirror a new URL
-usage: switch REPOS_URL [TARGET]
+usage: switch REPOS_URL [TARGET]   or
+       switch --only-rewrite-urls [FROM] [TO] [TARGET ...]
 
    Note:  this is the way to move a working copy to a new branch.
 
@@ -39,4 +40,5 @@
   --username arg           : specify a username ARG
   --password arg           : specify a password ARG
   --no-auth-cache          : do not cache authentication tokens
+  --only-rewrite-urls      : only rewrite urls; do not contact a repository
 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

Re: [PATCH] implement "svn switch --only-rewrite-urls"

Posted by Philip Martin <ph...@codematters.co.uk>.
mark benedetto king <bk...@inquira.com> writes:

I don't really like this approach, I'd prefer a command that contacts
the new repository, to ensure that we don't get invalid text-bases.
The current patch would be the only client command that, by design,
will allow the user to produce a corrupt working copy.

That said, here is a short review to help get this working with the
recent access baton changes :)

> Index: subversion/include/svn_wc.h
> ===================================================================
> --- subversion/include/svn_wc.h
> +++ subversion/include/svn_wc.h	Mon Sep 23 20:38:04 2002
> @@ -1472,6 +1472,19 @@
>                  svn_wc_adm_access_t *optional_adm_access,
>                  apr_pool_t *pool);
>  
> +/* Recurse from PATH, changing repository references that begin with
> +   FROM to begin with TO instead.  Perform necessary allocations in
> +   POOL. 
> +
> +   ADM_ACCESS is an access baton for the directory containing
> +   PATH. ADM_ACCESS can be NULL in which case the function will open and
> +   close acess batons as required. */

I don't like the optional access baton, just make it required.  Yes,
there are already some optional ones (I put them in) but I'd like to
remove those and I don't think we should add more of them.

> +svn_error_t *
> +svn_wc_relocate (const char *path,
> +                 svn_wc_adm_access_t *adm_access,
> +                 const char *from,
> +                 const char *to,
> +                 apr_pool_t *pool);

Do we need to support the --nonrecursive option?

>  
>  /* Revert changes to PATH (perhaps in a RECURSIVE fashion).  Perform
>     necessary allocations in POOL.
> Index: subversion/include/svn_client.h
> ===================================================================
> --- subversion/include/svn_client.h
> +++ subversion/include/svn_client.h	Mon Sep 23 20:38:04 2002
> @@ -684,6 +684,15 @@
>                      apr_pool_t *pool);
>  
>  
> +/* Recursively modify a working copy directory DIR, changing any
> +   repository URLs that begin with FROM to begin with TO instead. */
> +svn_error_t *
> +svn_client_relocate (const char *dir,
> +                     const char *from,
> +                     const char *to,
> +                     apr_pool_t *pool);

Support --nonrecursive here as well?

> +
> +
>  /* Restore the pristine version of a working copy PATH, effectively
>     undoing any local mods.  If PATH is a directory, and RECURSIVE is
>     TRUE, this will be a recursive operation.
> Index: subversion/libsvn_wc/relocate.c
> ===================================================================
> --- subversion/libsvn_wc/relocate.c
> +++ subversion/libsvn_wc/relocate.c	Mon Sep 23 20:38:04 2002
> @@ -0,0 +1,101 @@
> +/*
> + * relocate.c: do wc repos relocation
> + *
> + * ====================================================================
> + * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
> + *
> + * This software is licensed as described in the file COPYING, which
> + * you should have received as part of this distribution.  The terms
> + * are also available at http://subversion.tigris.org/license-1.html.
> + * If newer versions of this license are posted there, you may use a
> + * newer version instead, at your option.
> + *
> + * This software consists of voluntary contributions made by many
> + * individuals.  For exact contribution history, see the revision
> + * history and logs, available at http://subversion.tigris.org/.
> + * ====================================================================
> + */
> +
> +
> +
> +#include "svn_wc.h"
> +#include "svn_error.h"
> +#include "svn_string.h"
> +#include "svn_xml.h"
> +#include "svn_pools.h"
> +#include "svn_io.h"
> +
> +#include "wc.h"
> +#include "entries.h"
> +
> +
> +svn_error_t *
> +svn_wc_relocate (const char *path,
> +                 svn_wc_adm_access_t *adm_access,
> +                 const char *from,
> +                 const char *to,
> +                 apr_pool_t *pool)
> +{
> +  apr_hash_t *entries = NULL;
> +  apr_hash_index_t *hi;
> +  enum svn_node_kind kind;
> +  int is_wc;
> +  int from_len;
> +
> +  svn_boolean_t root = FALSE;
> +
> +
> +  SVN_ERR (svn_wc_check_wc (path, &is_wc, pool));
> +  if (! is_wc)
> +    return svn_error_createf
> +      (SVN_ERR_WC_NOT_DIRECTORY, 0, NULL, pool,
> +       "svn_wc_cleanup: %s is not a working copy directory", path);

Need to support PATH being a file.

> +
> +  if (! adm_access)
> +    {
> +      SVN_ERR (svn_wc_adm_open (&adm_access, NULL, path, TRUE, TRUE, pool));

Put this bit into svn_client_relocate.

> +      root = TRUE;
> +    }
> +
> +  from_len = strlen(from);
> +
> +  SVN_ERR (svn_wc_entries_read (&entries, path, FALSE, pool));

Need to pass ADM_ACCESS.

> +
> +  for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
> +    {
> +      const void *key;
> +      void *val;
> +      svn_wc_entry_t *entry;
> +
> +      apr_hash_this (hi, &key, NULL, &val);
> +      entry = val;
> +
> +      if ((entry->kind == svn_node_dir)
> +          && (strcmp (key, SVN_WC_ENTRY_THIS_DIR) != 0))
> +        {
> +          /* Recurse */
> +          const char *subdir = svn_path_join (path, key, pool);

You will need to add something like

            svn_wc_adm_access_t *subdir_access;
            SVN_ERR (svn_wc_adm_retrieve (&subdir_access, adm_access, subdir,
                                          pool));

> +          SVN_ERR (svn_wc_relocate (subdir, adm_access, from, to, pool));

and pass subdir_access instead of adm_access.

> +        }
> +     
> +      if (entry->url &&
> +          (strncmp(entry->url, from, from_len) == 0))
> +          entry->url = apr_psprintf (pool, "%s%s", to, entry->url + from_len);

You will be modifying the cache, but I think it's OK since you are
about to write it out again.

> +    }
> +
> +  SVN_ERR (svn_wc__entries_write (entries, path, pool));

Need to pass ADM_ACCESS.

> +
> +  if (root)
> +    svn_wc_adm_close(adm_access);

Put this bit into svn_client_relocate.

> +
> +  return SVN_NO_ERROR;
> +}
> +
> +
> +
> +/* 
> + * local variables:
> + * eval: (load-file "../../tools/dev/svn-dev.el")
> + * end:
> + */
> +
> Index: subversion/libsvn_client/relocate.c
> ===================================================================
> --- subversion/libsvn_client/relocate.c
> +++ subversion/libsvn_client/relocate.c	Mon Sep 23 20:38:04 2002
> @@ -0,0 +1,59 @@
> +/*
> + * relocate.c:  wrapper around wc relocation functionality.
> + *
> + * ====================================================================
> + * Copyright (c) 2000-2002 CollabNet.  All rights reserved.
> + *
> + * This software is licensed as described in the file COPYING, which
> + * you should have received as part of this distribution.  The terms
> + * are also available at http://subversion.tigris.org/license-1.html.
> + * If newer versions of this license are posted there, you may use a
> + * newer version instead, at your option.
> + *
> + * This software consists of voluntary contributions made by many
> + * individuals.  For exact contribution history, see the revision
> + * history and logs, available at http://subversion.tigris.org/.
> + * ====================================================================
> + */
> +
> +/* ==================================================================== */
> +
> +
> +
> +/*** Includes. ***/
> +
> +#include "svn_wc.h"
> +#include "svn_client.h"
> +#include "svn_string.h"
> +#include "svn_pools.h"
> +#include "svn_error.h"
> +#include "svn_path.h"
> +#include "client.h"
> +
> +
> +
> +/*** Code. ***/
> +
> +svn_error_t *
> +svn_client_relocate (const char *dir,
> +                     const char *from,
> +                     const char *to,
> +                     apr_pool_t *pool)
> +{
> +  enum svn_node_kind kind;
> +
> +  SVN_ERR (svn_io_check_path (dir, &kind, pool));
> +  if (kind != svn_node_dir)
> +    return svn_error_createf (SVN_ERR_WC_NOT_DIRECTORY, 0, NULL, pool,
> +                              "Cannot relocate '%s' -- not a directory", 
> +                              dir);
> +

We need to support files, so don't bother with the above check.  Just
do something like

     svn_wc_adm_access_t *adm_access;
     SVN_ERR (svn_wc_adm_probe_open (&adm_access, NULL, path, TRUE, recurse,
              pool));

> +  return svn_wc_relocate (dir, NULL, from, to, pool);

Pass adm_access to svn_wc_relocate, and then close it.

     SVN_ERR (svn_wc_adm_close (adm_access));

> +}
> +
> +
> +
> +/* 
> + * local variables:
> + * eval: (load-file "../../tools/dev/svn-dev.el")
> + * end: */

-- 
Philip Martin

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org