Author: philip
Date: Thu Jun 3 10:46:10 2010
New Revision: 950947
URL: http://svn.apache.org/viewvc?rev=950947&view=rev
Log:
A non-recursive SVN_EXPERIMENTAL_COPY implementation for directories.
It works for a few simple cases but not enough to pass the regression
tests.
* subversion/libsvn_wc/copy.c
(copy_to_tmpdir): Add kind and recursive parameters.
(copy_versioned_dir): New.
(svn_wc_copy3): Call copy_versioned_dir.
* subversion/libsvn_wc/wc_db.c
(temp_cross_db_copy): Allow directories.
(svn_wc__db_op_copy): For directories choose the source parent stub if
the destination directory does not yet exist.
Modified:
subversion/trunk/subversion/libsvn_wc/copy.c
subversion/trunk/subversion/libsvn_wc/wc_db.c
Modified: subversion/trunk/subversion/libsvn_wc/copy.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/copy.c?rev=950947&r1=950946&r2=950947&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/copy.c (original)
+++ subversion/trunk/subversion/libsvn_wc/copy.c Thu Jun 3 10:46:10 2010
@@ -48,6 +48,8 @@
/*** Code. ***/
+#ifndef SVN_EXPERIMENTAL_COPY
+
/* Copy all properties of SRC_PATH to DST_PATH. */
static svn_error_t *
copy_props(svn_wc__db_t *db,
@@ -270,7 +272,6 @@ copy_added_dir_administratively(svn_wc_c
return SVN_NO_ERROR;
}
-#ifndef SVN_EXPERIMENTAL_COPY
/* This function effectively creates and schedules a file for
addition, but does extra administrative things to allow it to
function as a 'copy'.
@@ -488,7 +489,6 @@ copy_file_administratively(svn_wc_contex
return SVN_NO_ERROR;
}
-#endif
/* Recursively crawl over a directory PATH and do a number of things:
@@ -730,53 +730,67 @@ copy_dir_administratively(svn_wc_context
scratch_pool));
}
}
+#endif
+#ifdef SVN_EXPERIMENTAL_COPY
/* Make a copy SRC_ABSPATH under a temporary name in the directory
TMPDIR_ABSPATH and return the absolute path of the copy in
- *DST_ABSPATH. If SRC_ABSPATH doesn't exist then set *DST_ABSPATH
- to NULL to indicate that no copy was made. */
+ *DST_ABSPATH. Return the node kind of SRC_ABSPATH in *KIND. If
+ SRC_ABSPATH doesn't exist then set *DST_ABSPATH to NULL to indicate
+ that no copy was made. */
static svn_error_t *
copy_to_tmpdir(const char **dst_abspath,
+ svn_node_kind_t *kind,
const char *src_abspath,
const char *tmpdir_abspath,
+ svn_boolean_t recursive,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- svn_node_kind_t kind;
svn_boolean_t is_special;
svn_io_file_del_t delete_when;
- SVN_ERR(svn_io_check_special_path(src_abspath, &kind, &is_special,
+ SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special,
scratch_pool));
- if (kind == svn_node_none)
+ if (*kind == svn_node_none)
{
*dst_abspath = NULL;
return SVN_NO_ERROR;
}
- else if (kind == svn_node_unknown)
+ else if (*kind == svn_node_unknown)
{
return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
_("Source '%s' is unexpected kind"),
svn_dirent_local_style(src_abspath,
scratch_pool));
}
- else if (kind == svn_node_dir || is_special)
+ else if (*kind == svn_node_dir || is_special)
delete_when = svn_io_file_del_on_close;
- else if (kind == svn_node_file)
+ else if (*kind == svn_node_file)
delete_when = svn_io_file_del_none;
+ /* ### Do we need a pool cleanup to remove the copy? We can't use
+ ### svn_io_file_del_on_pool_cleanup above because a) it won't
+ ### handle the directory case and b) we need to be able to remove
+ ### the cleanup before queueing the move work item. */
+
SVN_ERR(svn_io_open_unique_file3(NULL, dst_abspath, tmpdir_abspath,
delete_when, scratch_pool, scratch_pool));
- if (kind == svn_node_dir)
- SVN_ERR(svn_io_copy_dir_recursively(src_abspath,
- tmpdir_abspath,
- svn_dirent_basename(*dst_abspath,
- scratch_pool),
- TRUE, /* copy_perms */
- cancel_func, cancel_baton,
- scratch_pool));
+ if (*kind == svn_node_dir)
+ {
+ if (recursive)
+ SVN_ERR(svn_io_copy_dir_recursively(src_abspath,
+ tmpdir_abspath,
+ svn_dirent_basename(*dst_abspath,
+ scratch_pool),
+ TRUE, /* copy_perms */
+ cancel_func, cancel_baton,
+ scratch_pool));
+ else
+ SVN_ERR(svn_io_dir_make(*dst_abspath, APR_OS_DEFAULT, scratch_pool));
+ }
else if (!is_special)
SVN_ERR(svn_io_copy_file(src_abspath, *dst_abspath, TRUE, /* copy_perms */
scratch_pool));
@@ -788,7 +802,6 @@ copy_to_tmpdir(const char **dst_abspath,
}
-#ifdef SVN_EXPERIMENTAL_COPY
/* A replacement for both copy_file_administratively and
copy_added_file_administratively. Not yet fully working. Relies
on in-db-props. SRC_ABSPATH is a versioned file but the filesystem
@@ -810,6 +823,7 @@ copy_versioned_file(svn_wc_context_t *wc
svn_stream_t *src_pristine;
#endif
const char *tmp_dst_abspath;
+ svn_node_kind_t kind;
SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, wc_ctx->db,
dst_abspath,
@@ -842,7 +856,8 @@ copy_versioned_file(svn_wc_context_t *wc
}
#endif
- SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, src_abspath, tmpdir_abspath,
+ SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &kind, src_abspath, tmpdir_abspath,
+ TRUE, /* recursive */
cancel_func, cancel_baton, scratch_pool));
if (tmp_dst_abspath)
{
@@ -869,6 +884,118 @@ copy_versioned_file(svn_wc_context_t *wc
}
return SVN_NO_ERROR;
}
+
+static svn_error_t *
+copy_versioned_dir(svn_wc_context_t *wc_ctx,
+ const char *src_abspath,
+ const char *dst_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_skel_t *work_items = NULL;
+ const char *dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
+ const char *tmpdir_abspath;
+ const char *tmp_dst_abspath;
+ svn_node_kind_t kind;
+
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, wc_ctx->db,
+ dst_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &kind, src_abspath, tmpdir_abspath,
+ FALSE, /* recursive */
+ cancel_func, cancel_baton, scratch_pool));
+ if (tmp_dst_abspath)
+ {
+ svn_skel_t *work_item;
+
+ SVN_ERR(svn_wc__loggy_move(&work_item, wc_ctx->db, dir_abspath,
+ tmp_dst_abspath, dst_abspath,
+ scratch_pool));
+ work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+
+ if (kind == svn_node_dir)
+ {
+ /* Create the per-directory db in the copied directory. The
+ copy is not yet connected to the parent so we don't need
+ to use a workqueue. This will be removed when we
+ centralise. */
+ const char *dst_parent_abspath, *name, *parent_url, *url;
+ const char *repos_root_url, *repos_uuid;
+ svn_revnum_t revision;
+ svn_depth_t depth;
+
+ svn_dirent_split(dst_abspath, &dst_parent_abspath, &name,
+ scratch_pool);
+ SVN_ERR(svn_wc__node_get_url(&parent_url, wc_ctx, dst_parent_abspath,
+ scratch_pool, scratch_pool));
+ url = svn_uri_join(parent_url, name, scratch_pool);
+ SVN_ERR(svn_wc__db_read_info(NULL, /* status */
+ NULL, /* kind */
+ &revision,
+ NULL, /* repos_relpath */
+ &repos_root_url,
+ &repos_uuid,
+ NULL, /* changed_rev */
+ NULL, /* changed_date */
+ NULL, /* changed_author */
+ NULL, /* last_mod_time */
+ &depth,
+ NULL, /* checksum */
+ NULL, /* translated_size */
+ NULL, /* target */
+ NULL, /* changelist */
+ NULL, /* original_repos_relpath */
+ NULL, /* original_root_url */
+ NULL, /* original_uuid */
+ NULL, /* original_revision */
+ NULL, /* text_mod */
+ NULL, /* props_mod */
+ NULL, /* base_shadowed */
+ NULL, /* conflicted */
+ NULL, /* lock */
+ wc_ctx->db, src_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__internal_ensure_adm(wc_ctx->db, tmp_dst_abspath,
+ url, repos_root_url, repos_uuid,
+ revision, depth, scratch_pool));
+
+ /* That creates a base node which we do not want so delete it. */
+ SVN_ERR(svn_wc__db_base_remove(wc_ctx->db, tmp_dst_abspath,
+ scratch_pool));
+ }
+ }
+
+ SVN_ERR(svn_wc__db_op_copy(wc_ctx->db, src_abspath, dst_abspath,
+ work_items, scratch_pool));
+ SVN_ERR(svn_wc__wq_run(wc_ctx->db, dir_abspath,
+ cancel_func, cancel_baton, scratch_pool));
+
+ if (kind == svn_node_dir)
+ {
+ /* The first copy only does the parent stub, this second copy
+ does the full node but can only happen after the workqueue
+ has move the destination into place. */
+ SVN_ERR(svn_wc__db_op_copy(wc_ctx->db, src_abspath, dst_abspath,
+ NULL, scratch_pool));
+ }
+
+ if (notify_func)
+ {
+ svn_wc_notify_t *notify
+ = svn_wc_create_notify(dst_abspath, svn_wc_notify_add,
+ scratch_pool);
+ notify->kind = svn_node_dir;
+ (*notify_func)(notify_baton, notify, scratch_pool);
+ }
+
+ /* Iterate over versioned children and unversioned nodes */
+
+ return SVN_NO_ERROR;
+}
#endif
@@ -1016,6 +1143,7 @@ svn_wc_copy3(svn_wc_context_t *wc_ctx,
}
else if (src_kind == svn_node_dir)
{
+#ifndef SVN_EXPERIMENTAL_COPY
/* Check if we are copying a directory scheduled for addition,
these require special handling. */
if (src_entry->schedule == svn_wc_schedule_add
@@ -1037,6 +1165,12 @@ svn_wc_copy3(svn_wc_context_t *wc_ctx,
notify_func, notify_baton,
scratch_pool));
}
+#else
+ SVN_ERR(copy_versioned_dir(wc_ctx, src_abspath, dst_abspath,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool));
+#endif
}
return SVN_NO_ERROR;
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=950947&r1=950946&r2=950947&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Thu Jun 3 10:46:10 2010
@@ -2203,7 +2203,7 @@ temp_cross_db_copy(svn_wc__db_t *db,
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- SVN_ERR_ASSERT(kind == svn_wc__db_kind_file);
+ SVN_ERR_ASSERT(kind == svn_wc__db_kind_file || kind == svn_wc__db_kind_dir);
SVN_ERR(svn_wc__db_read_info(NULL, /* status */
NULL, /* kind */
@@ -2247,6 +2247,7 @@ temp_cross_db_copy(svn_wc__db_t *db,
iwb.moved_here = FALSE;
iwb.checksum = checksum;
+ iwb.children = NULL;
iwb.work_items = NULL;
@@ -2342,7 +2343,7 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
NULL, /* lock */
db, src_abspath, scratch_pool, scratch_pool));
- SVN_ERR_ASSERT(kind == svn_wc__db_kind_file);
+ SVN_ERR_ASSERT(kind == svn_wc__db_kind_file || kind == svn_wc__db_kind_dir);
if (status != svn_wc__db_status_added)
{
@@ -2388,7 +2389,14 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
}
}
-
+ /* When copying a directory we only copy the parent stub if the
+ destination directory does not exist. */
+ if (kind == svn_wc__db_kind_dir && !*src_relpath && *dst_relpath)
+ {
+ SVN_ERR(navigate_to_parent(&src_pdh, db, src_pdh,
+ svn_sqlite__mode_readwrite, scratch_pool));
+ src_relpath = svn_dirent_basename(src_abspath, NULL);
+ }
if (!strcmp(src_pdh->local_abspath, dst_pdh->local_abspath))
{
@@ -2426,6 +2434,11 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
src_pdh->wcroot->wc_id, src_relpath,
dst_relpath, dst_parent_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
+
+ if (kind == svn_wc__db_kind_dir)
+ {
+ /* Add incomplete children if copying a directory */
+ }
}
else
{