so given the reception of my 'svn rollback' implementation, i figured
i'd post my 'svn export' diff here before committing it ;-)
this implements a quick and dirty 'svn rollback', by simply copying
all version controlled files in a give working copy into the specified
directory or by checking out a given rev from a repository and then
going through and going through and deleting the administrative
directories.
yeah, the 'checkout and then clean' thing is an ugly hack, but i have
limited time to devote to this (i.e. the time between sessions and
when i'm bored while i hang around USENIX), and it works ;-)
anyway, i'm just curious if anyone has any problems with the
interface. if not, i'll commit this version, and later on go back and
see if it's feasable to optimize it by adding a flag to
svn_client_commit that makes it simply not write out administrative
directories in the 'export' case.
let the flame^H^H^Hheated discussions begin ;-)
-garrett
(ps, i implemented this partially because it gives you a sort of half
hearted way to do vendor branches... you can't seamlessly import a
dir of stuff from someone else's svn repo and maintain your own diffs
while still incorporating their changes, since that's really hard,
but you can at least deal with it on a similar level as someone else's
cvs repository...)
Index: ./subversion/include/svn_client.h
===================================================================
--- ./subversion/include/svn_client.h
+++ ./subversion/include/svn_client.h Thu Jun 13 17:16:05 2002
@@ -888,6 +888,35 @@
svn_boolean_t recurse,
apr_pool_t *pool);
+/* Export the contents of either a subversion repository or a subversion
+ working copy into a 'clean' directory (meaning a directory with no
+ administrative directories).
+
+ FROM is either the path the the working copy on disk, or a url to the
+ repository you wish to export.
+
+ TO is the path to the directory where you wish to create the exported
+ tree.
+
+ REVISION is the revision that should be exported, which is only used
+ when exporting from a repository.
+
+ AUTH_BATON is an authentication baton that is only used when exporting
+ from a repository.
+
+ NOTIFY_FUNC and NOTIFY_BATON are the notification functions and baton
+ which are passed to svn_client_checkout to actually retrieve the
+ data from the repository.
+
+ All allocations are done in POOL. */
+svn_error_t *
+svn_client_export (const char *from,
+ const char *to,
+ svn_client_revision_t *revision,
+ svn_client_auth_baton_t *auth_baton,
+ svn_wc_notify_func_t notify_func,
+ void *notify_baton,
+ apr_pool_t *pool);
/* Cancellation. */
Index: ./subversion/libsvn_client/export.c
===================================================================
--- ./subversion/libsvn_client/export.c
+++ ./subversion/libsvn_client/export.c Thu Jun 13 18:11:16 2002
@@ -0,0 +1,200 @@
+/*
+ * export.c: export a tree.
+ *
+ * ====================================================================
+ * 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 <apr_file_io.h>
+#include "svn_types.h"
+#include "svn_wc.h"
+#include "svn_client.h"
+#include "svn_string.h"
+#include "svn_error.h"
+#include "svn_path.h"
+#include "svn_pools.h"
+#include "client.h"
+
+
+/*** Code. ***/
+
+static svn_error_t *
+remove_admin_dirs (const char *dir, apr_pool_t *pool)
+{
+ apr_pool_t *subpool = svn_pool_create (pool);
+ apr_hash_t *dirents = apr_hash_make (subpool);
+ const enum svn_node_kind *type;
+ apr_hash_index_t *hi;
+ const char *item;
+ void *key, *val;
+
+ SVN_ERR (svn_io_get_dirents (&dirents, dir, subpool));
+
+ for (hi = apr_hash_first (subpool, dirents); hi; hi = apr_hash_next (hi))
+ {
+ apr_hash_this (hi, &key, NULL, &val);
+
+ item = key;
+ type = val;
+
+ if (*type == svn_node_dir)
+ {
+ char *dir_path = svn_path_join (dir, key, subpool);
+
+ if (strlen (item) == sizeof (SVN_WC_ADM_DIR_NAME) - 1
+ && strcmp (item, SVN_WC_ADM_DIR_NAME) == 0)
+ {
+ SVN_ERR (svn_io_remove_dir (dir_path, subpool));
+ }
+ else
+ {
+ SVN_ERR (remove_admin_dirs (dir_path, subpool));
+ }
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+copy_versioned_files (const char *from,
+ const char *to,
+ apr_pool_t *pool)
+{
+ apr_pool_t *subpool = svn_pool_create (pool);
+ apr_hash_t *dirents = apr_hash_make (subpool);
+ const enum svn_node_kind *type;
+ svn_wc_entry_t *entry;
+ apr_hash_index_t *hi;
+ apr_status_t apr_err;
+ svn_error_t *err;
+ const char *item;
+ void *key, *val;
+
+ err = svn_wc_entry (&entry, from, FALSE, subpool);
+
+ if (err && err->apr_err != SVN_ERR_WC_NOT_DIRECTORY)
+ return err;
+
+ /* we don't want to copy some random non-versioned directory. */
+ if (entry)
+ {
+ apr_finfo_t finfo;
+
+ apr_err = apr_stat (&finfo, from, APR_FINFO_PROT, subpool);
+ if (apr_err)
+ return svn_error_createf
+ (apr_err, 0, NULL, subpool, "error stating dir `%s'", to);
+
+ apr_err = apr_dir_make (to, finfo.protection, subpool);
+ if (apr_err)
+ return svn_error_createf
+ (apr_err, 0, NULL, subpool, "error creating dir `%s'", to);
+
+ SVN_ERR (svn_io_get_dirents (&dirents, from, subpool));
+
+ for (hi = apr_hash_first (subpool, dirents); hi; hi = apr_hash_next (hi))
+ {
+ apr_hash_this (hi, &key, NULL, &val);
+
+ item = key;
+ type = val;
+
+ if (*type == svn_node_dir)
+ {
+ if (strncmp (item, SVN_WC_ADM_DIR_NAME,
+ sizeof (SVN_WC_ADM_DIR_NAME) - 1) == 0)
+ {
+ ; /* skip this, it's an administrative directory. */
+ }
+ else
+ {
+ char *new_from = svn_path_join (from, key, subpool);
+ char *new_to = svn_path_join (to, key, subpool);
+
+ SVN_ERR (copy_versioned_files (new_from, new_to, subpool));
+ }
+ }
+ else if (*type == svn_node_file)
+ {
+ char *copy_from = svn_path_join (from, item, subpool);
+ char *copy_to = svn_path_join (to, item, subpool);
+
+ entry = NULL;
+
+ err = svn_wc_entry (&entry, copy_from, FALSE, subpool);
+
+ if (err && err->apr_err != SVN_ERR_WC_NOT_FILE)
+ return err;
+
+ /* don't copy it if it isn't versioned. */
+ if (entry)
+ {
+ SVN_ERR (svn_io_copy_file (copy_from, copy_to, TRUE,
+ subpool));
+ }
+ }
+ }
+ }
+
+ svn_pool_destroy (subpool);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_export (const char *from,
+ const char *to,
+ svn_client_revision_t *revision,
+ svn_client_auth_baton_t *auth_baton,
+ svn_wc_notify_func_t notify_func,
+ void *notify_baton,
+ apr_pool_t *pool)
+{
+ if (svn_path_is_url (from))
+ {
+ /* export directly from the repository by doing a checkout first. */
+ SVN_ERR (svn_client_checkout (notify_func,
+ notify_baton,
+ auth_baton,
+ from,
+ to,
+ revision,
+ TRUE,
+ NULL,
+ pool));
+
+ /* walk over the wc and remove the administrative directories. */
+ SVN_ERR (remove_admin_dirs (to, pool));
+ }
+ else
+ {
+ /* just copy the contents of the working copy into the target path. */
+ SVN_ERR (copy_versioned_files (from, to, pool));
+ }
+
+ 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 Thu Jun 13 12:41:39 2002
@@ -128,6 +128,7 @@
svn_cl__copy,
svn_cl__delete,
svn_cl__diff,
+ svn_cl__export,
svn_cl__help,
svn_cl__import,
svn_cl__info,
Index: ./subversion/clients/cmdline/export-cmd.c
===================================================================
--- ./subversion/clients/cmdline/export-cmd.c
+++ ./subversion/clients/cmdline/export-cmd.c Thu Jun 13 16:03:16 2002
@@ -0,0 +1,79 @@
+/*
+ * export-cmd.c -- Subversion export command
+ *
+ * ====================================================================
+ * 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_path.h"
+#include "svn_delta.h"
+#include "svn_error.h"
+#include "cl.h"
+
+
+/*** Code. ***/
+
+svn_error_t *
+svn_cl__export (apr_getopt_t *os,
+ svn_cl__opt_state_t *opt_state,
+ apr_pool_t *pool)
+{
+ svn_client_auth_baton_t *auth_baton;
+ svn_wc_notify_func_t notify_func = NULL;
+ void *notify_baton = NULL;
+ const char *from, *to;
+
+ SVN_ERR (svn_cl__parse_all_args (os, opt_state, "export", pool));
+
+ /* Put commandline auth info into a baton for libsvn_client. */
+ auth_baton = svn_cl__make_auth_baton (opt_state, pool);
+
+ if (opt_state->args->nelts != 2)
+ return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, 0, 0, pool, "");
+
+ from = ((const char **) (opt_state->args->elts))[0];
+ to = ((const char **) (opt_state->args->elts))[1];
+
+ auth_baton = svn_cl__make_auth_baton (opt_state, pool);
+
+ if (! opt_state->quiet)
+ svn_cl__get_checkout_notifier (¬ify_func, ¬ify_baton,
+ TRUE, FALSE, pool);
+
+ SVN_ERR (svn_client_export (from,
+ to,
+ &(opt_state->start_revision),
+ auth_baton,
+ notify_func,
+ notify_baton,
+ pool));
+ return SVN_NO_ERROR;
+}
+
+
+
+/*
+ * local variables:
+ * eval: (load-file "../../../tools/dev/svn-dev.el")
+ * end:
+ */
Index: ./subversion/clients/cmdline/main.c
===================================================================
--- ./subversion/clients/cmdline/main.c
+++ ./subversion/clients/cmdline/main.c Thu Jun 13 18:32:39 2002
@@ -187,7 +187,19 @@
" ommitted, value of HEAD is assumed.\n",
{'r', 'D', 'x', 'n',
svn_cl__auth_username_opt, svn_cl__auth_password_opt} },
-
+
+ { "export", svn_cl__export, {0},
+ "export stuff.\n"
+ "usage: 1. svn export [-r REV] URL PATH\n"
+ " 2. svn export PATH1 PATH2\n\n"
+ " 1. exports a clean directory tree from the repository specified by\n"
+ " URL, at revision REV if it is given, otherwise at HEAD, into \n"
+ " PATH\n\n"
+ " 2. exports a clean directory tree from the working copy specified by\n"
+ " PATH1 into PATH2. all local changes will be preserved, but files\n"
+ " not under revision control will not be copied.\n",
+ {'r', 'q', svn_cl__auth_username_opt, svn_cl__auth_password_opt} },
+
{ "help", svn_cl__help, {"?", "h"},
"Display this usage message.\n"
"usage: svn help [SUBCOMMAND1 [SUBCOMMAND2] ...]\n",
--
garrett rooney Remember, any design flaw you're
rooneg@electricjellyfish.net sufficiently snide about becomes
http://electricjellyfish.net/ a feature. -- Dan Sugalski
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Jun 14 03:44:48 2002