You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2010/07/29 21:38:49 UTC
svn commit: r980551 [8/10] - in /subversion/branches/issue-2779-dev: ./
build/generator/ notes/tree-conflicts/
subversion/bindings/javahl/src/org/apache/subversion/javahl/
subversion/bindings/javahl/src/org/apache/subversion/javahl/callback/
subversion...
Modified: subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.c?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.c Thu Jul 29 19:38:44 2010
@@ -1,5 +1,6 @@
/*
- * dump_editor.c: The svn_delta_editor_t editor used by svnrdump
+ * dump_editor.c: The svn_delta_editor_t editor used by svnrdump to
+ * dump revisions.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -28,23 +29,54 @@
#include "svn_props.h"
#include "svn_dirent_uri.h"
-#include "svnrdump.h"
#include "dump_editor.h"
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
-/* Make a directory baton to represent the directory at path (relative
- to the edit_baton).
+/* The baton used by the dump editor. */
+struct dump_edit_baton {
+ /* The output stream we write the dumpfile to */
+ svn_stream_t *stream;
+
+ /* Pool for per-edit-session allocations */
+ apr_pool_t *pool;
+
+ /* Properties which were modified during change_file_prop
+ * or change_dir_prop. */
+ apr_hash_t *props;
+
+ /* Properties which were deleted during change_file_prop
+ * or change_dir_prop. */
+ apr_hash_t *deleted_props;
+
+ /* Temporary buffer to write property hashes to in human-readable
+ * form. ### Is this really needed? */
+ svn_stringbuf_t *propstring;
+
+ /* Temporary file to write delta to along with its checksum. */
+ char *delta_abspath;
+
+ /* The checksum of the file the delta is being applied to */
+ const char *base_checksum;
+
+ /* Flags to trigger dumping props and text */
+ svn_boolean_t dump_props;
+ svn_boolean_t dump_text;
+ svn_boolean_t dump_props_pending;
+};
- COPYFROM_PATH/COPYFROM_REV are the path/revision against which this
- directory should be compared for changes. If the copyfrom
- information is valid, the directory will be compared
- against its copy source.
-
- PARENT_DIR_BATON is the directory baton of this directory's parent,
- or NULL if this is the top-level directory of the edit. ADDED
- indicates if this directory is newly added in this revision.
- Perform all allocations in POOL. */
+/* Make a directory baton to represent the directory at path (relative
+ * to the edit_baton).
+ *
+ * COPYFROM_PATH/COPYFROM_REV are the path/revision against which this
+ * directory should be compared for changes. If the copyfrom
+ * information is valid, the directory will be compared against its
+ * copy source.
+ *
+ * PARENT_DIR_BATON is the directory baton of this directory's parent,
+ * or NULL if this is the top-level directory of the edit. ADDED
+ * indicates if this directory is newly added in this revision.
+ * Perform all allocations in POOL. */
static struct dir_baton *
make_dir_baton(const char *path,
const char *copyfrom_path,
@@ -59,23 +91,25 @@ make_dir_baton(const char *path,
struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
const char *abspath;
- /* A path relative to nothing? I don't think so. */
+ /* Disallow a path relative to nothing. */
SVN_ERR_ASSERT_NO_RETURN(!path || pb);
/* Construct the full path of this node. */
if (pb)
- abspath = svn_dirent_join_many(pool, "/", path);
+ abspath = svn_uri_join("/", path, pool);
else
- abspath = apr_pstrdup(pool, "/");
+ abspath = "/";
/* Remove leading slashes from copyfrom paths. */
if (copyfrom_path && strcmp(copyfrom_path, "/"))
- copyfrom_path = ((*copyfrom_path == '/') ? copyfrom_path + 1 : copyfrom_path);
+ copyfrom_path = ((*copyfrom_path == '/') ?
+ copyfrom_path + 1 : copyfrom_path);
new_db->eb = eb;
new_db->parent_dir_baton = pb;
new_db->abspath = abspath;
- new_db->copyfrom_path = copyfrom_path ? apr_pstrdup(pool, copyfrom_path) : NULL;
+ new_db->copyfrom_path = copyfrom_path ?
+ apr_pstrdup(pool, copyfrom_path) : NULL;
new_db->copyfrom_rev = copyfrom_rev;
new_db->added = added;
new_db->written_out = FALSE;
@@ -83,30 +117,98 @@ make_dir_baton(const char *path,
return new_db;
}
+
+/* Extract and dump properties stored in edit baton EB, using POOL for
+ * any temporary allocations. If TRIGGER_VAR is not NULL, it is set to FALSE.
+ * Unless DUMP_DATA_TOO is set, only property headers are dumped.
+ */
+static svn_error_t *
+dump_props(struct dump_edit_baton *eb,
+ svn_boolean_t *trigger_var,
+ svn_boolean_t dump_data_too,
+ apr_pool_t *pool)
+{
+ svn_stream_t *propstream;
+
+ if (trigger_var && !*trigger_var)
+ return SVN_NO_ERROR;
+
+ svn_stringbuf_setempty(eb->propstring);
+ propstream = svn_stream_from_stringbuf(eb->propstring, eb->pool);
+ SVN_ERR(svn_hash_write_incremental(eb->props, eb->deleted_props,
+ propstream, "PROPS-END", pool));
+ SVN_ERR(svn_stream_close(propstream));
+
+ /* Prop-delta: true */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_PROP_DELTA
+ ": true\n"));
+
+ /* Prop-content-length: 193 */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n", eb->propstring->len));
+
+ if (dump_data_too)
+ {
+ /* Content-length: 14 */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n\n",
+ eb->propstring->len));
+
+ /* The properties. */
+ SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
+ &(eb->propstring->len)));
+
+ /* No text is going to be dumped. Write a couple of newlines and
+ wait for the next node/ revision. */
+ SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+
+ /* Cleanup so that data is never dumped twice. */
+ svn_hash__clear(eb->props, pool);
+ svn_hash__clear(eb->deleted_props, pool);
+ if (trigger_var)
+ *trigger_var = FALSE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
/*
* Write out a node record for PATH of type KIND under EB->FS_ROOT.
- * ACTION describes what is happening to the node (see enum svn_node_action).
- * Write record to writable EB->STREAM, using EB->BUFFER to write in chunks.
+ * ACTION describes what is happening to the node (see enum
+ * svn_node_action). Write record to writable EB->STREAM, using
+ * EB->BUFFER to write in chunks.
*
* If the node was itself copied, IS_COPY is TRUE and the
- * path/revision of the copy source are in COPYFROM_PATH/COPYFROM_REV. If
- * IS_COPY is FALSE, yet COPYFROM_PATH/COPYFROM_REV are valid, this node is part
- * of a copied subtree.
+ * path/revision of the copy source are in COPYFROM_PATH/COPYFROM_REV.
+ * If IS_COPY is FALSE, yet COPYFROM_PATH/COPYFROM_REV are valid, this
+ * node is part of a copied subtree.
*/
static svn_error_t *
dump_node(struct dump_edit_baton *eb,
const char *path, /* an absolute path. */
svn_node_kind_t kind,
enum svn_node_action action,
+ svn_boolean_t is_copy,
const char *copyfrom_path,
svn_revnum_t copyfrom_rev,
apr_pool_t *pool)
{
- /* Write out metadata headers for this node. */
+ /* Remove leading slashes from path and copyfrom_path */
+ if (path && strcmp(path, "/"))
+ path = ((*path == '/') ? path + 1 : path);
+
+ if (copyfrom_path && strcmp(copyfrom_path, "/"))
+ copyfrom_path = ((*copyfrom_path == '/') ?
+ copyfrom_path + 1 : copyfrom_path);
+
+ /* Node-path: commons/STATUS */
SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
- (*path == '/') ? path + 1 : path));
+ SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n", path));
+ /* Node-kind: file */
if (kind == svn_node_file)
SVN_ERR(svn_stream_printf(eb->stream, pool,
SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
@@ -114,118 +216,109 @@ dump_node(struct dump_edit_baton *eb,
SVN_ERR(svn_stream_printf(eb->stream, pool,
SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
- /* Remove leading slashes from copyfrom paths. */
- if (copyfrom_path && strcmp(copyfrom_path, "/"))
- copyfrom_path = ((*copyfrom_path == '/') ? copyfrom_path + 1 : copyfrom_path);
- switch (action) {
+ /* Write the appropriate Node-action header */
+ switch (action)
+ {
+ case svn_node_action_change:
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_ACTION
+ ": change\n"));
+ break;
+
+ case svn_node_action_replace:
+ if (!is_copy)
+ {
+ /* Node-action: replace */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_ACTION
+ ": replace\n"));
+
+ eb->dump_props_pending = TRUE;
+ break;
+ }
+ /* More complex case: is_copy is true, and copyfrom_path/
+ copyfrom_rev are present: delete the original, and then re-add
+ it */
- case svn_node_action_change:
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_ACTION
- ": change\n"));
- break;
-
- case svn_node_action_replace:
- if (!eb->is_copy) {
- /* a simple delete+add, implied by a single 'replace' action. */
SVN_ERR(svn_stream_printf(eb->stream, pool,
SVN_REPOS_DUMPFILE_NODE_ACTION
- ": replace\n"));
+ ": delete\n\n"));
- eb->dump_props_pending = TRUE;
+ /* Recurse: Print an additional add-with-history record. */
+ SVN_ERR(dump_node(eb, path, kind, svn_node_action_add,
+ is_copy, copyfrom_path, copyfrom_rev, pool));
+
+ /* We can leave this routine quietly now, don't need to dump any
+ content; that was already done in the second record. */
+ eb->dump_props = FALSE;
break;
- }
- /* More complex case: eb->is_copy is true, and
- copyfrom_path/ copyfrom_rev are present: delete the original,
- and then re-add it */
-
- /* the path & kind headers have already been printed; just
- add a delete action, and end the current record.*/
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_ACTION
- ": delete\n\n"));
- /* recurse: print an additional add-with-history record. */
- SVN_ERR(dump_node(eb, path, kind, svn_node_action_add,
- copyfrom_path, copyfrom_rev, pool));
-
- /* we can leave this routine quietly now, don't need to dump
- any content; that was already done in the second record. */
- eb->dump_props = FALSE;
- eb->is_copy = FALSE;
- break;
+ case svn_node_action_delete:
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_ACTION
+ ": delete\n"));
- case svn_node_action_delete:
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_ACTION
- ": delete\n"));
+ /* We can leave this routine quietly now, don't need to dump
+ any content. */
+ SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+ eb->dump_props = FALSE;
+ break;
- /* we can leave this routine quietly now, don't need to dump
- any content. */
- SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
- eb->dump_props = FALSE;
- break;
+ case svn_node_action_add:
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
- case svn_node_action_add:
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+ if (!is_copy)
+ {
+ /* eb->dump_props_pending for files is handled in close_file
+ which is called immediately. However, directories are not
+ closed until all the work inside them has been done;
+ eb->dump_props_pending for directories is handled in all the
+ functions that can possibly be called after add_directory:
+ add_directory, open_directory, delete_entry, close_directory,
+ add_file, open_file. change_dir_prop is a special case. */
+
+ eb->dump_props_pending = TRUE;
+ break;
+ }
- if (!eb->is_copy) {
- /* eb->dump_props_pending for files is handled in close_file
- which is called immediately. However, directories are not
- closed until all the work inside them has been done;
- eb->dump_props_pending for directories is handled in all the
- functions that can possibly be called after add_directory:
- add_directory, open_directory, delete_entry, close_directory,
- add_file, open_file and change_dir_prop; change_dir_prop is a
- special case ofcourse */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
+ ": %ld\n"
+ SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
+ ": %s\n",
+ copyfrom_rev, copyfrom_path));
+
+ /* Ugly hack: If a directory was copied from a previous revision,
+ nothing else can be done, and close_file won't be called to
+ write two blank lines. Write them here otherwise the `svnadmin
+ load` parser will fail. */
+ if (kind == svn_node_dir)
+ SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
- eb->dump_props_pending = TRUE;
break;
}
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
- ": %ld\n"
- SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
- ": %s\n",
- copyfrom_rev, copyfrom_path));
-
- /* Dump the text only if apply_textdelta sets
- eb->dump_text */
-
- /* UGLY hack: If a directory was copied from a
- previous revision, nothing else can be done, and
- close_file won't be called to write two blank
- lines; write them here */
- if (kind == svn_node_dir)
- SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
-
- eb->is_copy = FALSE;
-
- break;
- }
-
/* Dump property headers */
SVN_ERR(dump_props(eb, &(eb->dump_props), FALSE, pool));
return SVN_NO_ERROR;
}
-static svn_error_t *open_root(void *edit_baton,
- svn_revnum_t base_revision,
- apr_pool_t *pool,
- void **root_baton)
+static svn_error_t *
+open_root(void *edit_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **root_baton)
{
+ struct dump_edit_baton *eb = edit_baton;
/* Allocate a special pool for the edit_baton to avoid pool
lifetime issues */
- struct dump_edit_baton *eb = edit_baton;
eb->pool = svn_pool_create(pool);
- eb->properties = apr_hash_make(eb->pool);
- eb->del_properties = apr_hash_make(eb->pool);
+ eb->props = apr_hash_make(eb->pool);
+ eb->deleted_props = apr_hash_make(eb->pool);
eb->propstring = svn_stringbuf_create("", eb->pool);
- eb->is_copy = FALSE;
*root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
edit_baton, NULL, FALSE, pool);
@@ -244,7 +337,8 @@ delete_entry(const char *path,
/* Some pending properties to dump? */
SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
- /* remember this path needs to be deleted */
+ /* Add this path to the deleted_entries of the parent directory
+ baton. */
apr_hash_set(pb->deleted_entries, mypath, APR_HASH_KEY_STRING, pb);
return SVN_NO_ERROR;
@@ -262,6 +356,7 @@ add_directory(const char *path,
void *val;
struct dir_baton *new_db
= make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb, TRUE, pool);
+ svn_boolean_t is_copy;
/* Some pending properties to dump? */
SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
@@ -270,14 +365,15 @@ add_directory(const char *path,
val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
/* Detect an add-with-history */
- pb->eb->is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
+ is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
/* Dump the node */
SVN_ERR(dump_node(pb->eb, path,
svn_node_dir,
val ? svn_node_action_replace : svn_node_action_add,
- pb->eb->is_copy ? copyfrom_path : NULL,
- pb->eb->is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
+ is_copy,
+ is_copy ? copyfrom_path : NULL,
+ is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
pool));
if (val)
@@ -307,13 +403,16 @@ open_directory(const char *path,
/* If the parent directory has explicit comparison path and rev,
record the same for this one. */
- if (pb && ARE_VALID_COPY_ARGS(pb->copyfrom_path, pb->copyfrom_rev)) {
- copyfrom_path = svn_dirent_join_many(pool, pb->copyfrom_path,
- svn_relpath_basename(path, pool));
- copyfrom_rev = pb->copyfrom_rev;
- }
+ if (pb && ARE_VALID_COPY_ARGS(pb->copyfrom_path, pb->copyfrom_rev))
+ {
+ copyfrom_path = svn_uri_join(pb->copyfrom_path,
+ svn_relpath_basename(path, pool),
+ pool);
+ copyfrom_rev = pb->copyfrom_rev;
+ }
- new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb, FALSE, pool);
+ new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
+ FALSE, pool);
*child_baton = new_db;
return SVN_NO_ERROR;
}
@@ -332,18 +431,18 @@ close_directory(void *dir_baton,
/* Dump the directory entries */
for (hi = apr_hash_first(pool, db->deleted_entries); hi;
- hi = apr_hash_next(hi)) {
- const void *key;
- const char *path;
- apr_hash_this(hi, &key, NULL, NULL);
- path = key;
-
- svn_pool_clear(iterpool);
-
- SVN_ERR(dump_node(db->eb, path,
- svn_node_unknown, svn_node_action_delete,
- NULL, SVN_INVALID_REVNUM, iterpool));
- }
+ hi = apr_hash_next(hi))
+ {
+ const void *key;
+ const char *path;
+ apr_hash_this(hi, &key, NULL, NULL);
+ path = key;
+
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(dump_node(db->eb, path, svn_node_unknown, svn_node_action_delete,
+ FALSE, NULL, SVN_INVALID_REVNUM, iterpool));
+ }
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
@@ -359,6 +458,7 @@ add_file(const char *path,
{
struct dir_baton *pb = parent_baton;
void *val;
+ svn_boolean_t is_copy;
/* Some pending properties to dump? */
SVN_ERR(dump_props(pb->eb, &(pb->eb->dump_props_pending), TRUE, pool));
@@ -367,21 +467,23 @@ add_file(const char *path,
val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
/* Detect add-with-history. */
- pb->eb->is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
+ is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
/* Dump the node. */
SVN_ERR(dump_node(pb->eb, path,
svn_node_file,
val ? svn_node_action_replace : svn_node_action_add,
- pb->eb->is_copy ? copyfrom_path : NULL,
- pb->eb->is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
+ is_copy,
+ is_copy ? copyfrom_path : NULL,
+ is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
pool));
if (val)
/* delete the path, it's now been dumped. */
apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
- /* Build a nice file baton to pass to change_file_prop and apply_textdelta */
+ /* Build a nice file baton to pass to change_file_prop and
+ apply_textdelta */
*file_baton = pb->eb;
return SVN_NO_ERROR;
@@ -406,19 +508,20 @@ open_file(const char *path,
/* If the parent directory has explicit copyfrom path and rev,
record the same for this one. */
- if (pb && ARE_VALID_COPY_ARGS(pb->copyfrom_path, pb->copyfrom_rev)) {
- APR_ARRAY_PUSH(compose_path, const char *) = pb->copyfrom_path;
- APR_ARRAY_PUSH(compose_path, const char *) =
- svn_relpath_basename(path, pool);
- copyfrom_path = svn_path_compose(compose_path, pool);
- copyfrom_rev = pb->copyfrom_rev;
- }
+ if (pb && ARE_VALID_COPY_ARGS(pb->copyfrom_path, pb->copyfrom_rev))
+ {
+ APR_ARRAY_PUSH(compose_path, const char *) = pb->copyfrom_path;
+ APR_ARRAY_PUSH(compose_path, const char *) =
+ svn_relpath_basename(path, pool);
+ copyfrom_path = svn_path_compose(compose_path, pool);
+ copyfrom_rev = pb->copyfrom_rev;
+ }
- SVN_ERR(dump_node(pb->eb, path,
- svn_node_file, svn_node_action_change,
- copyfrom_path, copyfrom_rev, pool));
+ SVN_ERR(dump_node(pb->eb, path, svn_node_file, svn_node_action_change,
+ FALSE, copyfrom_path, copyfrom_rev, pool));
- /* Build a nice file baton to pass to change_file_prop and apply_textdelta */
+ /* Build a nice file baton to pass to change_file_prop and
+ apply_textdelta */
*file_baton = pb->eb;
return SVN_NO_ERROR;
@@ -435,29 +538,28 @@ change_dir_prop(void *parent_baton,
if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
return SVN_NO_ERROR;
- value ? apr_hash_set(db->eb->properties, apr_pstrdup(pool, name),
- APR_HASH_KEY_STRING, svn_string_dup(value, pool)) :
- apr_hash_set(db->eb->del_properties, apr_pstrdup(pool, name),
- APR_HASH_KEY_STRING, (void *)0x1);
-
- /* This function is what distinguishes between a directory that is
- opened to merely get somewhere, vs. one that is opened because it
- actually changed by itself */
- if (! db->written_out) {
- /* If eb->dump_props_pending was set, it means that the
- node information corresponding to add_directory has already
- been written; just don't unset it and dump_node will dump
- the properties before doing anything else. If it wasn't
- set, node information hasn't been written yet: so dump the
- node itself before dumping the props */
-
- SVN_ERR(dump_node(db->eb, db->abspath,
- svn_node_dir, svn_node_action_change,
- db->copyfrom_path, db->copyfrom_rev, pool));
-
- SVN_ERR(dump_props(db->eb, NULL, TRUE, pool));
- db->written_out = TRUE;
- }
+ if (value)
+ apr_hash_set(db->eb->props, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, svn_string_dup(value, pool));
+ else
+ apr_hash_set(db->eb->deleted_props, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, "");
+
+ if (! db->written_out)
+ {
+ /* If db->written_out is set, it means that the node information
+ corresponding to this directory has already been written: don't
+ do anything; dump_props_pending will take care of dumping the
+ props. If it not, dump the node itself before dumping the
+ props. */
+
+ SVN_ERR(dump_node(db->eb, db->abspath, svn_node_dir,
+ svn_node_action_change, FALSE, db->copyfrom_path,
+ db->copyfrom_rev, pool));
+
+ SVN_ERR(dump_props(db->eb, NULL, TRUE, pool));
+ db->written_out = TRUE;
+ }
return SVN_NO_ERROR;
}
@@ -472,9 +574,13 @@ change_file_prop(void *file_baton,
if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
return SVN_NO_ERROR;
- apr_hash_set(eb->properties, apr_pstrdup(pool, name),
- APR_HASH_KEY_STRING, value ?
- svn_string_dup(value, pool): (void *)0x1);
+ if (value)
+ apr_hash_set(eb->props, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, svn_string_dup(value, pool));
+ else
+ apr_hash_set(eb->deleted_props, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, "");
+
/* Dump the property headers and wait; close_file might need
to write text headers too depending on whether
apply_textdelta is called */
@@ -498,12 +604,9 @@ window_handler(svn_txdelta_window_t *win
SVN_ERR(err);
/* Write information about the filepath to hb->eb */
- eb->delta_abspath = apr_pstrdup(eb->pool,
- hb->delta_abspath);
+ eb->delta_abspath = apr_pstrdup(eb->pool, hb->delta_abspath);
/* Cleanup */
- SVN_ERR(svn_io_file_close(hb->delta_file, hb->pool));
- SVN_ERR(svn_stream_close(hb->delta_filestream));
svn_pool_destroy(hb->pool);
return SVN_NO_ERROR;
}
@@ -515,8 +618,6 @@ apply_textdelta(void *file_baton, const
void **handler_baton)
{
struct dump_edit_baton *eb = file_baton;
- apr_status_t apr_err;
- const char *tempdir;
/* Custom handler_baton allocated in a separate pool */
apr_pool_t *handler_pool = svn_pool_create(pool);
@@ -525,24 +626,19 @@ apply_textdelta(void *file_baton, const
hb->eb = eb;
/* Use a temporary file to measure the text-content-length */
- SVN_ERR(svn_io_temp_dir(&tempdir, hb->pool));
+ SVN_ERR(svn_stream_open_unique(&(hb->delta_filestream), &hb->delta_abspath,
+ NULL, svn_io_file_del_none, hb->pool,
+ hb->pool));
- hb->delta_abspath = svn_dirent_join(tempdir, "XXXXXX", hb->pool);
- apr_err = apr_file_mktemp(&(hb->delta_file), hb->delta_abspath,
- APR_CREATE | APR_READ | APR_WRITE | APR_EXCL,
- hb->pool);
- if (apr_err != APR_SUCCESS)
- SVN_ERR(svn_error_wrap_apr(apr_err, NULL));
-
- hb->delta_filestream = svn_stream_from_aprfile2(hb->delta_file, TRUE, hb->pool);
-
- /* Prepare to write the delta to the temporary file */
+ /* Prepare to write the delta to the temporary file. */
svn_txdelta_to_svndiff2(&(hb->apply_handler), &(hb->apply_baton),
hb->delta_filestream, 0, hb->pool);
eb->dump_text = TRUE;
+ eb->base_checksum = apr_pstrdup(pool, base_checksum);
- /* The actual writing takes place when this function has finished */
- /* Set the handler and handler_baton */
+ /* The actual writing takes place when this function has
+ finished. Set handler and handler_baton now so for
+ window_handler() */
*handler = window_handler;
*handler_baton = hb;
@@ -559,75 +655,83 @@ close_file(void *file_baton,
svn_stream_t *delta_filestream;
apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
- /* We didn't write the property headers because we were
- waiting for file_prop_change; write them now */
+ /* Some pending properties to dump? */
SVN_ERR(dump_props(eb, &(eb->dump_props_pending), FALSE, pool));
- /* The prop headers have already been dumped in dump_node */
- /* Dump the text headers */
- if (eb->dump_text) {
- /* text-delta header */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_TEXT_DELTA
- ": true\n"));
+ /* The prop headers have already been dumped in dump_node; now dump
+ the text headers. */
+ if (eb->dump_text)
+ {
+ /* Text-delta: true */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_TEXT_DELTA
+ ": true\n"));
- /* Measure the length */
- SVN_ERR(svn_io_stat(info, eb->delta_abspath, APR_FINFO_SIZE, pool));
+ SVN_ERR(svn_io_stat(info, eb->delta_abspath, APR_FINFO_SIZE, pool));
- /* text-content-length header */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH
- ": %lu\n",
- (unsigned long)info->size));
- /* text-content-md5 header */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5
- ": %s\n",
- text_checksum));
- }
+ if (eb->base_checksum)
+ /* Text-delta-base-md5: */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5
+ ": %s\n",
+ eb->base_checksum));
- /* content-length header: if both text and props are absent,
- skip this block */
+ /* Text-content-length: 39 */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH
+ ": %lu\n",
+ (unsigned long)info->size));
+
+ /* Text-content-md5: 82705804337e04dcd0e586bfa2389a7f */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5
+ ": %s\n",
+ text_checksum));
+ }
+
+ /* Content-length: 1549 */
+ /* If both text and props are absent, skip this header */
if (eb->dump_props || eb->dump_props_pending)
SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %ld\n\n",
- (unsigned long)info->size + eb->propstring->len));
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %ld\n\n",
+ (unsigned long)info->size + eb->propstring->len));
else if (eb->dump_text)
SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %ld\n\n",
- (unsigned long)info->size));
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %ld\n\n",
+ (unsigned long)info->size));
/* Dump the props; the propstring should have already been
written in dump_node or above */
- if (eb->dump_props || eb->dump_props_pending) {
- SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
- &(eb->propstring->len)));
-
- /* Cleanup */
- eb->dump_props = eb->dump_props_pending = FALSE;
- svn_hash__clear(eb->properties, pool);
- svn_hash__clear(eb->del_properties, pool);
- }
+ if (eb->dump_props || eb->dump_props_pending)
+ {
+ SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
+ &(eb->propstring->len)));
+
+ /* Cleanup */
+ eb->dump_props = eb->dump_props_pending = FALSE;
+ svn_hash__clear(eb->props, pool);
+ svn_hash__clear(eb->deleted_props, pool);
+ }
/* Dump the text */
- if (eb->dump_text) {
-
- /* Open the temporary file, map it to a stream, copy
- the stream to eb->stream, close and delete the
- file */
- SVN_ERR(svn_io_file_open(&delta_file, eb->delta_abspath,APR_READ,
- 0600,pool));
- delta_filestream = svn_stream_from_aprfile2(delta_file, TRUE, pool);
- SVN_ERR(svn_stream_copy3(delta_filestream, eb->stream, NULL, NULL, pool));
-
- /* Cleanup */
- SVN_ERR(svn_io_file_close(delta_file, pool));
- SVN_ERR(svn_stream_close(delta_filestream));
- SVN_ERR(svn_io_remove_file2(eb->delta_abspath, TRUE, pool));
- eb->dump_text = FALSE;
- }
+ if (eb->dump_text)
+ {
+ /* Open the temporary file, map it to a stream, copy
+ the stream to eb->stream, close and delete the
+ file */
+ SVN_ERR(svn_io_file_open(&delta_file, eb->delta_abspath, APR_READ,
+ APR_OS_DEFAULT, pool));
+ delta_filestream = svn_stream_from_aprfile2(delta_file, TRUE, pool);
+ SVN_ERR(svn_stream_copy3(delta_filestream, eb->stream, NULL, NULL, pool));
+
+ /* Cleanup */
+ SVN_ERR(svn_io_file_close(delta_file, pool));
+ SVN_ERR(svn_stream_close(delta_filestream));
+ SVN_ERR(svn_io_remove_file2(eb->delta_abspath, TRUE, pool));
+ eb->dump_text = FALSE;
+ }
SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
@@ -646,15 +750,16 @@ close_edit(void *edit_baton, apr_pool_t
svn_error_t *
get_dump_editor(const svn_delta_editor_t **editor,
void **edit_baton,
+ svn_stream_t *stream,
apr_pool_t *pool)
{
struct dump_edit_baton *eb;
svn_delta_editor_t *de;
eb = apr_pcalloc(pool, sizeof(struct dump_edit_baton));
- SVN_ERR(svn_stream_for_stdout(&(eb->stream), pool));
- de = svn_delta_default_editor(pool);
+ eb->stream = stream;
+ de = svn_delta_default_editor(pool);
de->open_root = open_root;
de->delete_entry = delete_entry;
de->add_directory = add_directory;
@@ -668,7 +773,7 @@ get_dump_editor(const svn_delta_editor_t
de->close_file = close_file;
de->close_edit = close_edit;
- /* Set the edit_baton and editor */
+ /* Set the edit_baton and editor. */
*edit_baton = eb;
*editor = de;
Modified: subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.h
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.h?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.h (original)
+++ subversion/branches/issue-2779-dev/subversion/svnrdump/dump_editor.h Thu Jul 29 19:38:44 2010
@@ -21,46 +21,19 @@
* @endcopyright
*
* @file dump_editor.h
- * @brief The svn_delta_editor_t editor used by svnrdump
+ * @brief The svn_delta_editor_t editor used by svnrdump to dump
+ * revisions.
*/
#ifndef DUMP_EDITOR_H_
#define DUMP_EDITOR_H_
/**
- * The baton used by the dump editor.
- */
-struct dump_edit_baton {
- /* The output stream we write the dumpfile to */
- svn_stream_t *stream;
-
- /* pool is for per-edit-session allocations */
- apr_pool_t *pool;
-
- /* Store the properties that changed */
- apr_hash_t *properties;
- apr_hash_t *del_properties; /* Value is undefined */
- /* write_hash_to_stringbuf writes properties and del_properties to
- propstring so they can be printed directly to the stream */
- svn_stringbuf_t *propstring;
-
- /* Was a copy command issued? */
- svn_boolean_t is_copy;
-
- /* Temporary file to write delta to along with its checksum */
- char *delta_abspath;
-
- /* Flags to trigger dumping props and text */
- svn_boolean_t dump_props;
- svn_boolean_t dump_text;
- svn_boolean_t dump_props_pending;
-};
-
-/**
* A directory baton used by all directory-related callback functions
* in the dump editor.
*/
-struct dir_baton {
+struct dir_baton
+{
struct dump_edit_baton *eb;
struct dir_baton *parent_dir_baton;
@@ -97,8 +70,7 @@ struct handler_baton
apr_pool_t *pool;
/* Information about the path of the temporary file used */
- char *delta_abspath;
- apr_file_t *delta_file;
+ const char *delta_abspath;
svn_stream_t *delta_filestream;
/* Global edit baton */
@@ -107,11 +79,12 @@ struct handler_baton
/**
* Get a dump editor @a editor along with a @a edit_baton allocated in
- * @a pool.
+ * @a pool. The editor will write output to @a stream.
*/
svn_error_t *
get_dump_editor(const svn_delta_editor_t **editor,
void **edit_baton,
+ svn_stream_t *stream,
apr_pool_t *pool);
#endif
Modified: subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c Thu Jul 29 19:38:44 2010
@@ -25,13 +25,90 @@
#include "svn_pools.h"
#include "svn_cmdline.h"
#include "svn_client.h"
+#include "svn_hash.h"
#include "svn_ra.h"
#include "svn_repos.h"
#include "svn_path.h"
+#include "svn_utf.h"
#include "svn_private_config.h"
+#include "svn_string.h"
+#include "svn_props.h"
-#include "svnrdump.h"
#include "dump_editor.h"
+#include "load_editor.h"
+
+static svn_opt_subcommand_t dump_cmd, load_cmd;
+
+enum svn_svnrdump__longopt_t
+ {
+ opt_config_dir = SVN_OPT_FIRST_LONGOPT_ID,
+ opt_auth_username,
+ opt_auth_password,
+ opt_non_interactive,
+ opt_auth_nocache,
+ opt_version,
+ };
+
+static const svn_opt_subcommand_desc2_t svnrdump__cmd_table[] =
+ {
+ { "dump", dump_cmd, { "d" },
+ N_("usage: svnrdump dump URL [-r LOWER[:UPPER]]\n\n"
+ "Dump revisions LOWER to UPPER of repository at remote URL "
+ "to stdout in a 'dumpfile' portable format.\n"
+ "If omitted, LOWER defaults to zero and UPPER to the latest "
+ "latest revision.\n"),
+ { 0 } },
+ { "load", load_cmd, { "l" },
+ N_("usage: svnrdump load URL\n\n"
+ "Load a 'dumpfile' given on stdin to a repository "
+ "at remote URL.\n"
+ "## This feature is not yet available.\n"),
+ { 0 } },
+ { "help", 0, { "?", "h" },
+ N_("usage: svnrdump help [SUBCOMMAND...]\n\n"
+ "Describe the usage of this program or its subcommands.\n"),
+ { 0 } },
+ { NULL, NULL, { 0 }, NULL, { 0 } }
+ };
+
+static const apr_getopt_option_t svnrdump__options[] =
+ {
+ {"revision", 'r', 1, N_("REV1[:REV2] range of revisions to dump")},
+ {"quiet", 'q', 0, N_("no progress (only errors) to stderr")},
+ {"config-dir", opt_config_dir, 1, N_("read user configuration files from"
+ " directory ARG") },
+ {"username", opt_auth_username, 1, N_("specify a username ARG")},
+ {"password", opt_auth_password, 1, N_("specify a password ARG")},
+ {"non-interactive", opt_non_interactive, 0, N_("do no interactive"
+ " prompting")},
+ {"no-auth-cache", opt_auth_nocache, 0, N_("do not cache authentication"
+ " tokens")},
+
+ {"help", 'h', 0, N_("display this help")},
+ {"version", opt_version, 0, N_("show program version information")},
+
+ {0, 0, 0, 0}
+ };
+
+/* Baton for the RA replay session. */
+struct replay_baton {
+ /* The editor producing diffs. */
+ const svn_delta_editor_t *editor;
+
+ /* Baton for the editor. */
+ void *edit_baton;
+
+ /* Whether to be quiet. */
+ svn_boolean_t quiet;
+};
+
+typedef struct {
+ svn_ra_session_t *session;
+ const char *url;
+ svn_revnum_t start_revision;
+ svn_revnum_t end_revision;
+ svn_boolean_t quiet;
+} opt_baton_t;
static svn_error_t *
replay_revstart(svn_revnum_t revision,
@@ -42,39 +119,40 @@ replay_revstart(svn_revnum_t revision,
apr_pool_t *pool)
{
struct replay_baton *rb = replay_baton;
- /* Editing this revision has just started; dump the revprops
- before invoking the editor callbacks */
- svn_stringbuf_t *propstring = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *propstring;
svn_stream_t *stdout_stream;
+ svn_stream_t *revprop_stream;
- /* Create an stdout stream */
svn_stream_for_stdout(&stdout_stream, pool);
- /* Print revision number and prepare the propstring */
+ /* Revision-number: 19 */
SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_REVISION_NUMBER
- ": %ld\n", revision));
- write_hash_to_stringbuf(rev_props, FALSE, &propstring, pool);
- svn_stringbuf_appendbytes(propstring, "PROPS-END\n", 10);
+ SVN_REPOS_DUMPFILE_REVISION_NUMBER
+ ": %ld\n", revision));
+ propstring = svn_stringbuf_create_ensure(0, pool);
+ revprop_stream = svn_stream_from_stringbuf(propstring, pool);
+ SVN_ERR(svn_hash_write2(rev_props, revprop_stream, "PROPS-END", pool));
+ SVN_ERR(svn_stream_close(revprop_stream));
- /* prop-content-length header */
+ /* Prop-content-length: 13 */
SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n", propstring->len));
+ SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n", propstring->len));
- /* content-length header */
+ /* Content-length: 29 */
SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
- /* Print the revprops now */
+ /* Property data. */
SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
- &(propstring->len)));
+ &(propstring->len)));
- svn_stream_close(stdout_stream);
+ SVN_ERR(svn_stream_printf(stdout_stream, pool, "\n"));
+ SVN_ERR(svn_stream_close(stdout_stream));
/* Extract editor and editor_baton from the replay_baton and
- set them so that the editor callbacks can use them */
+ set them so that the editor callbacks can use them. */
*editor = rb->editor;
*edit_baton = rb->edit_baton;
@@ -89,121 +167,408 @@ replay_revend(svn_revnum_t revision,
apr_hash_t *rev_props,
apr_pool_t *pool)
{
- /* Editor has finished for this revision and close_edit has
- been called; do nothing: just continue to the next
- revision */
+ /* No resources left to free. */
struct replay_baton *rb = replay_baton;
- if (rb->verbose)
+ if (! rb->quiet)
svn_cmdline_fprintf(stderr, pool, "* Dumped revision %lu\n", revision);
return SVN_NO_ERROR;
}
+/* Return in *SESSION a new RA session to URL.
+ * Allocate *SESSION and related data structures in POOL.
+ * Use CONFIG_DIR and pass USERNAME, PASSWORD, CONFIG_DIR and
+ * NO_AUTH_CACHE to initialize the authorization baton.*/
static svn_error_t *
-open_connection(svn_ra_session_t *session, const char *url, apr_pool_t *pool)
+open_connection(svn_ra_session_t **session,
+ const char *url,
+ svn_boolean_t non_interactive,
+ const char *username,
+ const char *password,
+ const char *config_dir,
+ svn_boolean_t no_auth_cache,
+ apr_pool_t *pool)
{
svn_client_ctx_t *ctx = NULL;
- SVN_ERR(svn_config_ensure (NULL, pool));
- SVN_ERR(svn_client_create_context (&ctx, pool));
+ svn_config_t *cfg_config;
+
SVN_ERR(svn_ra_initialize(pool));
- SVN_ERR(svn_config_get_config(&(ctx->config), NULL, pool));
+ SVN_ERR(svn_config_ensure(config_dir, pool));
+ SVN_ERR(svn_client_create_context(&ctx, pool));
+
+ SVN_ERR(svn_config_get_config(&(ctx->config), config_dir, pool));
+
+ cfg_config = apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
+ APR_HASH_KEY_STRING);
/* Default authentication providers for non-interactive use */
- SVN_ERR(svn_cmdline_create_auth_baton(&(ctx->auth_baton), TRUE,
- NULL, NULL, NULL, FALSE,
- FALSE, NULL, NULL, NULL,
- pool));
- SVN_ERR(svn_client_open_ra_session(&session, url, ctx, pool));
+ SVN_ERR(svn_cmdline_create_auth_baton(&(ctx->auth_baton), non_interactive,
+ username, password, config_dir,
+ no_auth_cache, FALSE, cfg_config,
+ ctx->cancel_func, ctx->cancel_baton,
+ pool));
+ SVN_ERR(svn_client_open_ra_session(session, url, ctx, pool));
return SVN_NO_ERROR;
}
static svn_error_t *
-replay_range(svn_ra_session_t *session, svn_revnum_t start_revision,
- svn_revnum_t end_revision, apr_pool_t *pool,
- svn_boolean_t verbose)
+replay_revisions(svn_ra_session_t *session, const char *url,
+ svn_revnum_t start_revision, svn_revnum_t end_revision,
+ svn_boolean_t quiet, apr_pool_t *pool)
{
const svn_delta_editor_t *dump_editor;
struct replay_baton *replay_baton;
void *dump_baton;
+ const char *uuid;
+ svn_stream_t *stdout_stream;
- SVN_ERR(get_dump_editor(&dump_editor,
- &dump_baton, pool));
+ SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+
+ SVN_ERR(get_dump_editor(&dump_editor, &dump_baton, stdout_stream, pool));
replay_baton = apr_pcalloc(pool, sizeof(*replay_baton));
replay_baton->editor = dump_editor;
replay_baton->edit_baton = dump_baton;
- replay_baton->verbose = verbose;
- SVN_ERR(svn_cmdline_printf(pool, SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n",
- SVN_REPOS_DUMPFILE_FORMAT_VERSION));
+ replay_baton->quiet = quiet;
+
+ /* Write the magic header and UUID */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n",
+ SVN_REPOS_DUMPFILE_FORMAT_VERSION));
+ SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool));
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid));
+
+ /* Fake revision 0 if necessary */
+ if (start_revision == 0)
+ {
+ apr_hash_t *prophash;
+ svn_stringbuf_t *propstring;
+ svn_stream_t *propstream;
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_REVISION_NUMBER
+ ": %ld\n", start_revision));
+
+ prophash = apr_hash_make(pool);
+ propstring = svn_stringbuf_create("", pool);
+
+ SVN_ERR(svn_ra_rev_proplist(session, start_revision,
+ &prophash, pool));
+
+ propstream = svn_stream_from_stringbuf(propstring, pool);
+ SVN_ERR(svn_hash_write2(prophash, propstream, "PROPS-END", pool));
+ SVN_ERR(svn_stream_close(propstream));
+
+ /* Property-content-length: 14; Content-length: 14 */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n",
+ propstring->len));
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n\n",
+ propstring->len));
+ /* The properties */
+ SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
+ &(propstring->len)));
+ SVN_ERR(svn_stream_printf(stdout_stream, pool, "\n"));
+ if (! quiet)
+ svn_cmdline_fprintf(stderr, pool, "* Dumped revision %lu\n", start_revision);
+
+ start_revision++;
+ }
+
SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
0, TRUE, replay_revstart, replay_revend,
replay_baton, pool));
+ SVN_ERR(svn_stream_close(stdout_stream));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+load_revisions(svn_ra_session_t *session, const char *url,
+ svn_boolean_t quiet, apr_pool_t *pool)
+{
+ const svn_delta_editor_t *load_editor;
+ void *load_baton;
+ apr_file_t *stdin_file;
+ svn_stream_t *stdin_stream;
+ struct operation *root_operation;
+
+ apr_file_open_stdin(&stdin_file, pool);
+ stdin_stream = svn_stream_from_aprfile2(stdin_file, FALSE, pool);
+
+ SVN_ERR(get_load_editor(&load_editor, &load_baton, &root_operation,
+ stdin_stream, session, pool));
+ SVN_ERR(drive_load_editor(root_operation, load_editor, pool));
+
+ svn_stream_close(stdin_stream);
+
+ return SVN_NO_ERROR;
+}
+
+
+static const char *
+ensure_appname(const char *progname, apr_pool_t *pool)
+{
+ if (!progname)
+ return "svnrdump";
+
+ progname = svn_dirent_internal_style(progname, pool);
+ return svn_dirent_basename(progname, NULL);
+}
+
+static svn_error_t *
+usage(const char *progname, apr_pool_t *pool)
+{
+ progname = ensure_appname(progname, pool);
+
+ SVN_ERR(svn_cmdline_fprintf(stderr, pool,
+ _("Type '%s help' for usage.\n"),
+ progname));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+version(const char *progname, apr_pool_t *pool)
+{
+ const char *ra_desc_start
+ = _("The following repository access (RA) modules are available:\n\n");
+
+ svn_stringbuf_t *version_footer = svn_stringbuf_create(ra_desc_start,
+ pool);
+
+ SVN_ERR(svn_ra_print_modules(version_footer, pool));
+
+ progname = ensure_appname(progname, pool);
+
+ return svn_opt_print_help3(NULL, progname, TRUE, FALSE,
+ version_footer->data, NULL, NULL,
+ NULL, NULL, NULL, pool);
+}
+
+
+/** A statement macro, similar to @c SVN_ERR, but returns an integer.
+ *
+ * Evaluate @a expr. If it yields an error, handle that error and
+ * return @c EXIT_FAILURE.
+ */
+#define SVNRDUMP_ERR(expr) \
+ do \
+ { \
+ svn_error_t *svn_err__temp = (expr); \
+ if (svn_err__temp) \
+ { \
+ svn_handle_error2(svn_err__temp, stderr, FALSE, "svnrdump: "); \
+ svn_error_clear(svn_err__temp); \
+ return EXIT_FAILURE; \
+ } \
+ } \
+ while (0)
+
+static svn_error_t *
+dump_cmd(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+ opt_baton_t *opt_baton = baton;
+ SVN_ERR(replay_revisions(opt_baton->session, opt_baton->url,
+ opt_baton->start_revision, opt_baton->end_revision,
+ opt_baton->quiet, pool));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+load_cmd(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+ opt_baton_t *opt_baton = baton;
+ SVN_ERR(load_revisions(opt_baton->session, opt_baton->url,
+ opt_baton->quiet, pool));
return SVN_NO_ERROR;
}
static svn_error_t *
-usage(FILE *out_stream)
+help_cmd(apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
- fprintf(out_stream,
- _("usage: svnrdump URL [-r LOWER[:UPPER]]\n\n"
- "Dump the contents of repository at remote URL to stdout in a 'dumpfile'\n"
- "portable format. Dump revisions LOWER rev through UPPER rev.\n"
- "LOWER defaults to 1 and UPPER defaults to the highest possible revision\n"
- "if omitted.\n"));
+ const char *header =
+ _("general usage: svnrdump SUBCOMMAND URL [-r LOWER[:UPPER]]\n"
+ "Type 'svnrdump help <subcommand>' for help on a specific subcommand.\n\n"
+ "Available subcommands:\n");
+
+ SVN_ERR(svn_opt_print_help3(os, "svnrdump", FALSE, FALSE, NULL, header,
+ svnrdump__cmd_table, svnrdump__options, NULL,
+ NULL, pool));
+
return SVN_NO_ERROR;
}
int
main(int argc, const char **argv)
{
- int i;
- const char *url = NULL;
+ const svn_opt_subcommand_desc2_t *subcommand = NULL;
+ opt_baton_t *opt_baton;
char *revision_cut = NULL;
- svn_revnum_t start_revision = svn_opt_revision_unspecified;
- svn_revnum_t end_revision = svn_opt_revision_unspecified;
- svn_boolean_t verbose = FALSE;
+ svn_revnum_t latest_revision = svn_opt_revision_unspecified;
apr_pool_t *pool = NULL;
- svn_ra_session_t *session = NULL;
+ const char *config_dir = NULL;
+ const char *username = NULL;
+ const char *password = NULL;
+ svn_boolean_t no_auth_cache = FALSE;
+ svn_boolean_t non_interactive = FALSE;
+ apr_getopt_t *os;
+ const char *first_arg;
if (svn_cmdline_init ("svnrdump", stderr) != EXIT_SUCCESS)
return EXIT_FAILURE;
pool = svn_pool_create(NULL);
+ opt_baton = apr_pcalloc(pool, sizeof(*opt_baton));
+ opt_baton->start_revision = svn_opt_revision_unspecified;
+ opt_baton->end_revision = svn_opt_revision_unspecified;
+ opt_baton->url = NULL;
+
+ SVNRDUMP_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
+
+ os->interleave = TRUE; /* Options and arguments can be interleaved */
+
+ while (1)
+ {
+ int opt;
+ const char *opt_arg;
+ apr_status_t status = apr_getopt_long(os, svnrdump__options, &opt,
+ &opt_arg);
+
+ if (APR_STATUS_IS_EOF(status))
+ break;
+ if (status != APR_SUCCESS)
+ {
+ SVNRDUMP_ERR(usage(argv[0], pool));
+ exit(EXIT_FAILURE);
+ }
+
+ switch(opt)
+ {
+ case 'r':
+ {
+ revision_cut = strchr(opt_arg, ':');
+ if (revision_cut)
+ {
+ opt_baton->start_revision = (svn_revnum_t)strtoul(opt_arg,
+ &revision_cut, 10);
+ opt_baton->end_revision = (svn_revnum_t)strtoul(revision_cut + 1,
+ NULL, 10);
+ }
+ else
+ opt_baton->start_revision = (svn_revnum_t)strtoul(opt_arg, NULL, 10);
+ }
+ break;
+ case 'q':
+ opt_baton->quiet = TRUE;
+ break;
+ case opt_config_dir:
+ config_dir = opt_arg;
+ break;
+ case opt_version:
+ SVNRDUMP_ERR(version(argv[0], pool));
+ exit(EXIT_SUCCESS);
+ break;
+ case 'h':
+ SVNRDUMP_ERR(help_cmd(os, opt_baton, pool));
+ exit(EXIT_SUCCESS);
+ break;
+ case opt_auth_username:
+ SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&username, opt_arg, pool));
+ break;
+ case opt_auth_password:
+ SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
+ break;
+ case opt_auth_nocache:
+ no_auth_cache = TRUE;
+ break;
+ case opt_non_interactive:
+ non_interactive = TRUE;
+ break;
+ }
+ }
+
+ if (os->ind >= os->argc)
+ {
+ svn_error_clear
+ (svn_cmdline_fprintf(stderr, pool,
+ _("Subcommand argument required\n")));
+ SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
+ svn_pool_destroy(pool);
+ exit(EXIT_FAILURE);
+ }
+
+ first_arg = os->argv[os->ind++];
+
+ subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
+ first_arg);
+
+ if (subcommand == NULL)
+ {
+ const char *first_arg_utf8;
+ svn_error_t *err = svn_utf_cstring_to_utf8(&first_arg_utf8,
+ first_arg, pool);
+ if (err)
+ return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
+ svn_error_clear(svn_cmdline_fprintf(stderr, pool,
+ _("Unknown command: '%s'\n"),
+ first_arg_utf8));
+ SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
+ svn_pool_destroy(pool);
+ exit(EXIT_FAILURE);
+ }
+
+ if (subcommand && strcmp(subcommand->name, "help") == 0)
+ {
+ SVNRDUMP_ERR(help_cmd(os, opt_baton, pool));
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Only continue if the only not option argument is a url */
+ if ((os->ind != os->argc-1)
+ || !svn_path_is_url(os->argv[os->ind]))
+ {
+ SVNRDUMP_ERR(usage(argv[0], pool));
+ exit(EXIT_FAILURE);
+ }
+
+ SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&(opt_baton->url), os->argv[os->ind], pool));
+
+ opt_baton->url = svn_uri_canonicalize(os->argv[os->ind], pool);
+
+ SVNRDUMP_ERR(open_connection(&(opt_baton->session),
+ opt_baton->url,
+ non_interactive,
+ username,
+ password,
+ config_dir,
+ no_auth_cache,
+ pool));
+
+ /* Have sane opt_baton->start_revision and end_revision defaults if unspecified */
+ SVNRDUMP_ERR(svn_ra_get_latest_revnum(opt_baton->session, &latest_revision, pool));
+ if (opt_baton->start_revision == svn_opt_revision_unspecified)
+ opt_baton->start_revision = 0;
+ if (opt_baton->end_revision == svn_opt_revision_unspecified)
+ opt_baton->end_revision = latest_revision;
+ if (opt_baton->end_revision > latest_revision)
+ {
+ SVN_INT_ERR(svn_cmdline_fprintf(stderr, pool,
+ _("Revision %ld does not exist.\n"),
+ opt_baton->end_revision));
+ exit(EXIT_FAILURE);
+ }
+ if (opt_baton->end_revision < opt_baton->start_revision)
+ {
+ SVN_INT_ERR(svn_cmdline_fprintf(stderr, pool,
+ _("LOWER cannot be greater "
+ "than UPPER.\n")));
+ exit(EXIT_FAILURE);
+ }
- for (i = 1; i < argc; i++) {
- if (!strncmp("-r", argv[i], 2)) {
- revision_cut = strchr(argv[i] + 2, ':');
- if (revision_cut) {
- start_revision = (svn_revnum_t) strtoul(argv[i] + 2, &revision_cut, 10);
- end_revision = (svn_revnum_t) strtoul(revision_cut + 1, NULL, 10);
- }
- else
- start_revision = (svn_revnum_t) strtoul(argv[i] + 2, NULL, 10);
- } else if (!strcmp("-v", argv[i]) || !strcmp("--verbose", argv[i])) {
- verbose = TRUE;
- } else if (!strcmp("help", argv[i]) || !strcmp("--help", argv[i])) {
- SVN_INT_ERR(usage(stdout));
- return EXIT_SUCCESS;
- } else if (*argv[i] == '-' || url) {
- SVN_INT_ERR(usage(stderr));
- return EXIT_FAILURE;
- } else
- url = argv[i];
- }
-
- if (!url || !svn_path_is_url(url)) {
- usage(stderr);
- return EXIT_FAILURE;
- }
- SVN_INT_ERR(open_connection(session, url, pool));
-
- /* Have sane start_revision and end_revision defaults if unspecified */
- if (start_revision == svn_opt_revision_unspecified)
- start_revision = 1;
- if (end_revision == svn_opt_revision_unspecified)
- SVN_INT_ERR(svn_ra_get_latest_revnum(session, &end_revision, pool));
-
- SVN_INT_ERR(replay_range(session, start_revision, end_revision, pool, verbose));
+ /* Dispatch the subcommand */
+ SVNRDUMP_ERR((*subcommand->cmd_func)(os, opt_baton, pool));
svn_pool_destroy(pool);
Propchange: subversion/branches/issue-2779-dev/subversion/svnrdump/svnrdump.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/basic_tests.py Thu Jul 29 19:38:44 2010
@@ -704,8 +704,11 @@ def basic_cleanup(sbox):
svntest.actions.run_and_verify_status(wc_dir, expected_output)
- # corrupted/non-existing temporary directory should be restored
- svntest.actions.remove_admin_tmp_dir(B_path)
+ # corrupted/non-existing temporary directory should be restored while
+ # we are not at single-db (where this tmp dir will be gone)
+ tmp_path = os.path.join(B_path, svntest.main.get_admin_name(), 'tmp')
+ if os.path.exists(tmp_path):
+ svntest.main.safe_rmtree(tmp_path)
# Run cleanup (### todo: cleanup doesn't currently print anything)
svntest.actions.run_and_verify_svn("Cleanup command", None, [],
@@ -1146,9 +1149,9 @@ def basic_delete(sbox):
# check versioned dir is not removed
if not verify_dir_deleted(F_path):
- print("Removed versioned dir")
- ### we should raise a less generic error here. which?
- raise svntest.Failure
+ # If we are not running in single-db, this is an error
+ if os.path.isdir(os.path.join(F_path, '../' + svntest.main.get_admin_name())):
+ raise svntest.Failure("Removed administrative area")
# check unversioned and added dirs has been removed
if verify_dir_deleted(Q_path):
@@ -1210,8 +1213,8 @@ def basic_checkout_deleted(sbox):
#----------------------------------------------------------------------
-# Issue 846, changing a deleted file to an added directory is not
-# supported.
+# Issue 846, changing a deleted file to an added directory was not
+# supported before WC-NG. But we can handle it.
def basic_node_kind_change(sbox):
"attempt to change node kind"
@@ -1229,25 +1232,24 @@ def basic_node_kind_change(sbox):
svntest.actions.run_and_verify_status(wc_dir, expected_status)
# Try and fail to create a directory (file scheduled for deletion)
- svntest.actions.run_and_verify_svn('Cannot change node kind',
- None, svntest.verify.AnyOutput,
- 'mkdir', gamma_path)
+ svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', gamma_path)
- # Status is unchanged
+ # Status is replaced
+ expected_status.tweak('A/D/gamma', status='R ')
svntest.actions.run_and_verify_status(wc_dir, expected_status)
# Commit file deletion
expected_output = wc.State(wc_dir, {
- 'A/D/gamma' : Item(verb='Deleting'),
+ 'A/D/gamma' : Item(verb='Replacing'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.remove('A/D/gamma')
+ expected_status.tweak('A/D/gamma', status=' ', wc_rev='2')
svntest.actions.run_and_verify_commit(wc_dir,
expected_output, expected_status,
None, wc_dir)
# Try and fail to create a directory (file deleted)
- svntest.actions.run_and_verify_svn('Cannot change node kind',
+ svntest.actions.run_and_verify_svn(None,
None, svntest.verify.AnyOutput,
'mkdir', gamma_path)
@@ -1258,11 +1260,12 @@ def basic_node_kind_change(sbox):
svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
# mkdir should succeed
+ svntest.actions.run_and_verify_svn(None, None, [], 'rm', gamma_path)
svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', gamma_path)
expected_status.tweak(wc_rev=2)
expected_status.add({
- 'A/D/gamma' : Item(status='A ', wc_rev=0),
+ 'A/D/gamma' : Item(status='R ', wc_rev=2),
})
svntest.actions.run_and_verify_status(wc_dir, expected_status)
@@ -2539,7 +2542,7 @@ test_list = [ None,
basic_switch,
basic_delete,
basic_checkout_deleted,
- basic_node_kind_change,
+ Wimp('Needs single-db', basic_node_kind_change),
basic_import,
basic_cat,
basic_ls,
Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/checkout_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/checkout_tests.py?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/checkout_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/checkout_tests.py Thu Jul 29 19:38:44 2010
@@ -151,13 +151,88 @@ def make_local_tree(sbox, mod_files=Fals
#----------------------------------------------------------------------
def checkout_with_obstructions(sbox):
- """co with obstructions should fail without --force"""
+ """co with obstructions conflicts without --force"""
make_local_tree(sbox, False, False)
- svntest.actions.run_and_verify_svn("No error where some expected",
- None, svntest.verify.AnyOutput,
- "co", sbox.repo_url, sbox.wc_dir)
+ #svntest.factory.make(sbox,
+ # """# Checkout with unversioned obstructions lying around.
+ # svn co url wc_dir
+ # svn status""")
+ #svntest.factory.make(sbox,
+ # """# Now see to it that we can recover from the obstructions.
+ # rm -rf A iota
+ # svn up""")
+ #exit(0)
+
+ wc_dir = sbox.wc_dir
+ url = sbox.repo_url
+
+ # Checkout with unversioned obstructions causes tree conflicts.
+ # svn co url wc_dir
+ expected_output = svntest.wc.State(wc_dir, {
+ 'iota' : Item(status=' ', treeconflict='C'),
+ 'A' : Item(status=' ', treeconflict='C'),
+ })
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.remove('A/B', 'A/B/E', 'A/B/E/beta', 'A/B/E/alpha', 'A/B/F',
+ 'A/B/lambda', 'A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/pi', 'A/D/G/tau',
+ 'A/D/H', 'A/D/H/psi', 'A/D/H/omega', 'A/D/H/chi', 'A/D/gamma', 'A/C')
+
+ actions.run_and_verify_checkout2(False, url, wc_dir, expected_output,
+ expected_disk, None, None, None, None)
+
+ # svn status
+ expected_status = actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('A', 'iota', status='? ', wc_rev=None,
+ treeconflict='C')
+ expected_status.tweak('A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/pi', 'A/D/G/tau',
+ 'A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', 'A/D/gamma', 'A/B',
+ 'A/B/E', 'A/B/E/beta', 'A/B/E/alpha', 'A/B/F', 'A/B/lambda', 'A/C',
+ wc_rev=None)
+ expected_status.tweak('A/mu', status='? ', wc_rev=None)
+
+ actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+
+ # Now see to it that we can recover from the obstructions.
+ # rm -rf A iota
+ svntest.main.safe_rmtree( os.path.join(wc_dir, 'A') )
+ os.remove( os.path.join(wc_dir, 'iota') )
+
+ # svn up
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A' : Item(status='A '),
+ 'A/D' : Item(status='A '),
+ 'A/D/gamma' : Item(status='A '),
+ 'A/D/G' : Item(status='A '),
+ 'A/D/G/rho' : Item(status='A '),
+ 'A/D/G/pi' : Item(status='A '),
+ 'A/D/G/tau' : Item(status='A '),
+ 'A/D/H' : Item(status='A '),
+ 'A/D/H/chi' : Item(status='A '),
+ 'A/D/H/omega' : Item(status='A '),
+ 'A/D/H/psi' : Item(status='A '),
+ 'A/B' : Item(status='A '),
+ 'A/B/E' : Item(status='A '),
+ 'A/B/E/beta' : Item(status='A '),
+ 'A/B/E/alpha' : Item(status='A '),
+ 'A/B/F' : Item(status='A '),
+ 'A/B/lambda' : Item(status='A '),
+ 'A/C' : Item(status='A '),
+ 'A/mu' : Item(status='A '),
+ 'iota' : Item(status='A '),
+ })
+
+ expected_disk = svntest.main.greek_state.copy()
+
+ expected_status = actions.get_virginal_state(wc_dir, 1)
+
+ actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir)
+
+
#----------------------------------------------------------------------
@@ -209,23 +284,83 @@ def forced_checkout_of_file_with_dir_obs
#----------------------------------------------------------------------
def forced_checkout_of_dir_with_file_obstructions(sbox):
- """forced co fails if a file obstructs a dir"""
+ """forced co flags conflict if a file obstructs a dir"""
make_local_tree(sbox, False, False)
- # Make the "other" working copy
- other_wc = sbox.add_wc_path('other')
- os.mkdir(other_wc)
- svntest.main.file_append(os.path.join(other_wc, "A"), "The file A")
+ #svntest.factory.make(sbox,"""
+ # mkdir wc_dir_other
+ # echo "The file A" > wc_dir_other/A
+ # svn co --force url wc_dir_other
+ # """)
+ #svntest.factory.make(sbox,"""
+ # # Now see to it that we can recover from the obstructions.
+ # rm wc_dir_other/A
+ # svn up wc_dir_other""")
+ #exit(0)
- # Checkout the standard greek repos into a directory that has a file named
- # "A" obstructing the dir "A" in the repos. This should fail.
- exit_code, sout, serr = svntest.actions.run_and_verify_svn(
- "Expected error during co", None, svntest.verify.AnyOutput,
- "co", "--force", sbox.repo_url, other_wc)
+ url = sbox.repo_url
+ wc_dir_other = sbox.add_wc_path('other')
+
+ other_A = os.path.join(wc_dir_other, 'A')
+
+ # mkdir wc_dir_other
+ os.makedirs(wc_dir_other)
+
+ # echo "The file A" > wc_dir_other/A
+ svntest.main.file_write(other_A, 'The file A\n')
+
+ # svn co --force url wc_dir_other
+ expected_output = svntest.wc.State(wc_dir_other, {
+ 'iota' : Item(status='A '),
+ 'A' : Item(status=' ', treeconflict='C'),
+ })
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.remove('A/B', 'A/B/E', 'A/B/E/beta', 'A/B/E/alpha', 'A/B/F',
+ 'A/B/lambda', 'A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/pi', 'A/D/G/tau',
+ 'A/D/H', 'A/D/H/psi', 'A/D/H/omega', 'A/D/H/chi', 'A/D/gamma', 'A/mu',
+ 'A/C')
+ expected_disk.tweak('A', contents='The file A\n')
+
+ actions.run_and_verify_checkout(url, wc_dir_other, expected_output,
+ expected_disk, None, None, None, None, '--force')
+
+
+ # Now see to it that we can recover from the obstructions.
+ # rm wc_dir_other/A
+ os.remove(other_A)
+
+ # svn up wc_dir_other
+ expected_output = svntest.wc.State(wc_dir_other, {
+ 'A' : Item(status='A '),
+ 'A/mu' : Item(status='A '),
+ 'A/D' : Item(status='A '),
+ 'A/D/G' : Item(status='A '),
+ 'A/D/G/tau' : Item(status='A '),
+ 'A/D/G/pi' : Item(status='A '),
+ 'A/D/G/rho' : Item(status='A '),
+ 'A/D/H' : Item(status='A '),
+ 'A/D/H/psi' : Item(status='A '),
+ 'A/D/H/omega' : Item(status='A '),
+ 'A/D/H/chi' : Item(status='A '),
+ 'A/D/gamma' : Item(status='A '),
+ 'A/C' : Item(status='A '),
+ 'A/B' : Item(status='A '),
+ 'A/B/E' : Item(status='A '),
+ 'A/B/E/beta' : Item(status='A '),
+ 'A/B/E/alpha' : Item(status='A '),
+ 'A/B/F' : Item(status='A '),
+ 'A/B/lambda' : Item(status='A '),
+ })
+
+ expected_disk = svntest.main.greek_state.copy()
+
+ expected_status = actions.get_virginal_state(wc_dir_other, 1)
+
+ actions.run_and_verify_update(wc_dir_other, expected_output, expected_disk,
+ expected_status, None, None, None, None, None, False, wc_dir_other)
- test_stderr(".*Failed to add directory.*a non-directory object of the " \
- "same name already exists", serr)
#----------------------------------------------------------------------
Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/commit_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/commit_tests.py?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/commit_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/commit_tests.py Thu Jul 29 19:38:44 2010
@@ -86,11 +86,15 @@ def make_standard_slew_of_changes(wc_dir
svntest.main.run_svn(None, 'add', 'Q')
# Remove two directories
- svntest.main.run_svn(None, 'rm', os.path.join('A', 'B', 'E'))
+ A_B_E = os.path.join('A', 'B', 'E')
+ svntest.main.run_svn(None, 'rm', A_B_E)
svntest.main.run_svn(None, 'rm', os.path.join('A', 'C'))
# Replace one of the removed directories
- svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'E'))
+ # But first recreate if it doesn't exist (single-db)
+ if not os.path.exists(A_B_E):
+ os.mkdir(A_B_E)
+ svntest.main.run_svn(None, 'add', A_B_E)
# Make property mods to two directories
svntest.main.run_svn(None, 'propset', 'foo', 'bar', os.curdir)
@@ -452,16 +456,21 @@ def nested_dir_replacements(sbox):
sbox.build()
wc_dir = sbox.wc_dir
+ A_D = os.path.join(wc_dir, 'A', 'D')
+
# Delete and re-add A/D (a replacement), and A/D/H (another replace).
- svntest.main.run_svn(None, 'rm', os.path.join(wc_dir, 'A', 'D'))
- svntest.main.run_svn(None, 'add', '--depth=empty',
- os.path.join(wc_dir, 'A', 'D'))
- svntest.main.run_svn(None, 'add', '--depth=empty',
- os.path.join(wc_dir, 'A', 'D', 'H'))
+ svntest.main.run_svn(None, 'rm', A_D)
+
+ # Recreate directories for single-db
+ if not os.path.exists(A_D):
+ os.mkdir(A_D)
+ os.mkdir(os.path.join(A_D, 'H'))
+ svntest.main.run_svn(None, 'add', '--depth=empty', A_D)
+ svntest.main.run_svn(None, 'add', '--depth=empty', os.path.join(A_D, 'H'))
# For kicks, add new file A/D/bloo.
- svntest.main.file_append(os.path.join(wc_dir, 'A', 'D', 'bloo'), "hi")
- svntest.main.run_svn(None, 'add', os.path.join(wc_dir, 'A', 'D', 'bloo'))
+ svntest.main.file_append(os.path.join(A_D, 'bloo'), "hi")
+ svntest.main.run_svn(None, 'add', os.path.join(A_D, 'bloo'))
# Verify pre-commit status:
#
@@ -1497,8 +1506,10 @@ def commit_multiple_wc_multiple_repos(sb
# Commit should fail, since WCs come from different repositories.
# The exact error message depends on whether or not the tests are
- # run below a 1.7 working copy
- error_re = ".*(is not a|Are all targets part of the same) working copy.*"
+ # run below an existing working copy
+ error_re = ( ".*(is not a working copy" +
+ "|Are all targets part of the same working copy" +
+ "|was not found).*" )
svntest.actions.run_and_verify_svn("Expected output on stderr doesn't match",
[], error_re,
'commit', '-m', 'log',
@@ -1946,6 +1957,9 @@ def mods_in_schedule_delete(sbox):
C_path = os.path.join(wc_dir, 'A', 'C')
svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
'rm', C_path)
+
+ if not os.path.exists(C_path):
+ os.mkdir(C_path)
foo_path = os.path.join(C_path, 'foo')
foo_contents = 'zig\nzag\n'
svntest.main.file_append(foo_path, foo_contents)
@@ -2659,15 +2673,16 @@ def start_commit_detect_capabilities(sbo
def commit_url(sbox):
"'svn commit SOME_URL' should error"
sbox.build()
- wc_dir = sbox.wc_dir
- repos_url = sbox.repo_url
+ url = sbox.repo_url
# Commit directly to a URL
+ expected_error = ("svn: '" + url +
+ "' is a URL, but URLs cannot be commit targets")
svntest.actions.run_and_verify_commit(None,
None,
None,
- "Must give local path",
- repos_url)
+ expected_error,
+ url)
# Test for issue #3198
def commit_added_missing(sbox):
Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/copy_tests.py?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/copy_tests.py Thu Jul 29 19:38:44 2010
@@ -36,6 +36,7 @@ from svntest.main import SVN_PROP_MERGEI
Skip = svntest.testcase.Skip
SkipUnless = svntest.testcase.SkipUnless
XFail = svntest.testcase.XFail
+Wimp = svntest.testcase.Wimp
Item = svntest.wc.StateItem
@@ -2460,16 +2461,18 @@ def move_dir_back_and_forth(sbox):
# Move the moved dir: D_moved back to its starting
# location at A/D.
- exit_code, out, err = svntest.actions.run_and_verify_svn(
- None, None, svntest.verify.AnyOutput,
- 'mv', D_move_path, D_path)
- for line in err:
- if re.match('.*Cannot copy to .*as it is scheduled for deletion',
- line, ):
- return
- raise svntest.Failure("mv failed but not in the expected way")
+ if svntest.main.wc_is_singledb(wc_dir):
+ # In single-db target is gone on-disk after it was moved away, so this
+ # move works ok
+ expected_err = []
+ else:
+ # In !SINGLE_DB the target of the copy exists on-dir, so svn tries
+ # to move the file below the deleted directory
+ expected_err = '.*Cannot copy to .*as it is scheduled for deletion'
+ svntest.actions.run_and_verify_svn(None, None, expected_err,
+ 'mv', D_move_path, D_path)
def copy_move_added_paths(sbox):
"copy and move added paths without commits"
@@ -4767,6 +4770,69 @@ def move_added_nodes(sbox):
expected_status.add({'X/Z' : Item(status='A ', wc_rev='0')})
svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+def locate_wrong_origin(sbox):
+ "update editor locates invalid file source"
+
+ sbox.build()
+
+ iota = os.path.join(sbox.wc_dir, 'iota')
+ gamma = os.path.join(sbox.wc_dir, 'A/D/gamma')
+
+ D1 = os.path.join(sbox.wc_dir, 'D1')
+ D2 = os.path.join(sbox.wc_dir, 'D2')
+
+ main.run_svn(None, 'mkdir', D1, D2)
+ main.run_svn(None, 'cp', iota, os.path.join(D1, 'iota'))
+ main.run_svn(None, 'cp', gamma, os.path.join(D2, 'iota'))
+
+ main.run_svn(None, 'ci', sbox.wc_dir, '-m', 'Add 2*iotas in r2')
+ main.run_svn(None, 'rm', D1)
+
+ main.run_svn(None, 'ci', sbox.wc_dir, '-m', 'Why?')
+
+ main.run_svn(None, 'cp', D2, D1)
+ main.run_svn(None, 'ci', sbox.wc_dir, '-m', 'Replace one iota')
+
+ # <= 1.6 needs a new checkout here to reproduce, but not since r961831.
+ # so we just perform an update
+ main.run_svn(None, 'up', sbox.wc_dir)
+
+ main.run_svn(None, 'cp', sbox.repo_url + '/D1/iota@2',
+ sbox.repo_url + '/iobeta', '-m', 'Copy iota')
+
+
+ expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 4)
+ expected_status.add({
+ 'D1' : Item(status=' ', wc_rev='4'),
+ 'D1/iota' : Item(status=' ', wc_rev='4'),
+ 'D2' : Item(status=' ', wc_rev='4'),
+ 'D2/iota' : Item(status=' ', wc_rev='4'),
+ })
+ svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+
+ # The next update receives an add_file('/D1/iota', 2), which it then tries
+ # to locate in the local working copy. It finds a '/D1/iota' in the expected
+ # place, with a last-changed revision of 2 and a local revision of HEAD-1
+ #
+ # locate_copyfrom identifies this file as correct because
+ # * last-mod <= 2 and
+ # * 2 <= REV
+ #
+ # Luckily close_file() receives an expected_checksum which makes us fail, or
+ # we would have a completely broken working copy
+
+ # So this gives a Checksum mismatch error.
+ main.run_svn(None, 'up', sbox.wc_dir)
+
+# This test currently fails, but should work ok once we move to single DB
+def copy_over_deleted_dir(sbox):
+ "copy a directory over a deleted directory"
+ sbox.build(read_only = True)
+
+ main.run_svn(None, 'rm', os.path.join(sbox.wc_dir, 'A/B'))
+ main.run_svn(None, 'cp', os.path.join(sbox.wc_dir, 'A/D'),
+ os.path.join(sbox.wc_dir, 'A/B'))
+
########################################################################
# Run the tests
@@ -4842,7 +4908,7 @@ test_list = [ None,
copy_make_parents_wc_repo,
copy_make_parents_repo_repo,
URI_encoded_repos_to_wc,
- XFail(allow_unversioned_parent_for_copy_src),
+ Wimp('Needs single db', allow_unversioned_parent_for_copy_src),
replaced_local_source_for_incoming_copy,
unneeded_parents,
double_parents_with_url,
@@ -4861,7 +4927,11 @@ test_list = [ None,
copy_dir_with_space,
changed_data_should_match_checkout,
XFail(changed_dir_data_should_match_checkout),
- XFail(move_added_nodes),
+ Wimp('Needs single db', move_added_nodes),
+ # Serf needs a different testcase for this issue
+ XFail(Skip(locate_wrong_origin,
+ svntest.main.is_ra_type_dav_serf)),
+ Wimp('Needs single db', copy_over_deleted_dir),
]
if __name__ == '__main__':
Modified: subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py?rev=980551&r1=980550&r2=980551&view=diff
==============================================================================
--- subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/issue-2779-dev/subversion/tests/cmdline/diff_tests.py Thu Jul 29 19:38:44 2010
@@ -3367,6 +3367,143 @@ def diff_git_format_url_url(sbox):
'--old', repo_url + '@1', '--new',
repo_url + '@2')
+def diff_prop_missing_context(sbox):
+ "diff for property has missing context"
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ iota_path = os.path.join(wc_dir, 'iota')
+ prop_val = "".join([
+ "line 1\n",
+ "line 2\n",
+ "line 3\n",
+ "line 4\n",
+ "line 5\n",
+ "line 6\n",
+ "line 7\n",
+ ])
+ svntest.main.run_svn(None,
+ "propset", "prop", prop_val, iota_path)
+
+ expected_output = svntest.wc.State(wc_dir, {
+ 'iota' : Item(verb='Sending'),
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', wc_rev=2)
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ expected_status, None, wc_dir)
+
+ prop_val = "".join([
+ "line 3\n",
+ "line 4\n",
+ "line 5\n",
+ "line 6\n",
+ ])
+ svntest.main.run_svn(None,
+ "propset", "prop", prop_val, iota_path)
+ expected_output = [
+ "Index: iota\n",
+ "===================================================================\n",
+ "--- iota\t(revision 2)\n",
+ "+++ iota\t(working copy)\n",
+ "\n",
+ "Property changes on: iota\n",
+ "___________________________________________________________________\n",
+ "Modified: prop\n",
+ "## -1,8 +1,5 ##\n",
+ "-line 1\n",
+ "-line 2\n",
+ " line 3\n",
+ " line 4\n",
+ " line 5\n",
+ " line 6\n",
+ "-line 7\n",
+ ]
+
+ svntest.actions.run_and_verify_svn(None, expected_output, [],
+ 'diff', iota_path)
+
+def diff_prop_multiple_hunks(sbox):
+ "diff for property with multiple hunks"
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ iota_path = os.path.join(wc_dir, 'iota')
+ prop_val = "".join([
+ "line 1\n",
+ "line 2\n",
+ "line 3\n",
+ "line 4\n",
+ "line 5\n",
+ "line 6\n",
+ "line 7\n",
+ "line 8\n",
+ "line 9\n",
+ "line 10\n",
+ "line 11\n",
+ "line 12\n",
+ "line 13\n",
+ ])
+ svntest.main.run_svn(None,
+ "propset", "prop", prop_val, iota_path)
+
+ expected_output = svntest.wc.State(wc_dir, {
+ 'iota' : Item(verb='Sending'),
+ })
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', wc_rev=2)
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ expected_status, None, wc_dir)
+
+ prop_val = "".join([
+ "line 1\n",
+ "line 2\n",
+ "line 3\n",
+ "Add a line here\n",
+ "line 4\n",
+ "line 5\n",
+ "line 6\n",
+ "line 7\n",
+ "line 8\n",
+ "line 9\n",
+ "line 10\n",
+ "And add a line here\n",
+ "line 11\n",
+ "line 12\n",
+ "line 13\n",
+ ])
+ svntest.main.run_svn(None,
+ "propset", "prop", prop_val, iota_path)
+ expected_output = [
+ "Index: iota\n",
+ "===================================================================\n",
+ "--- iota\t(revision 2)\n",
+ "+++ iota\t(working copy)\n",
+ "\n",
+ "Property changes on: iota\n",
+ "___________________________________________________________________\n",
+ "Modified: prop\n",
+ "## -1,6 +1,7 ##\n",
+ " line 1\n",
+ " line 2\n",
+ " line 3\n",
+ "+Add a line here\n",
+ " line 4\n",
+ " line 5\n",
+ " line 6\n",
+ "## -8,6 +9,7 ##\n",
+ " line 8\n",
+ " line 9\n",
+ " line 10\n",
+ "+And add a line here\n",
+ " line 11\n",
+ " line 12\n",
+ " line 13\n",
+ ]
+
+ svntest.actions.run_and_verify_svn(None, expected_output, [],
+ 'diff', iota_path)
+
########################################################################
#Run the tests
@@ -3426,6 +3563,8 @@ test_list = [ None,
diff_git_format_wc_wc,
diff_git_format_url_wc,
diff_git_format_url_url,
+ XFail(diff_prop_missing_context),
+ XFail(diff_prop_multiple_hunks),
]
if __name__ == '__main__':