You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ar...@apache.org on 2010/07/25 10:44:21 UTC
svn commit: r979002 - in /subversion/branches/svnrload/subversion/svnrload:
./ load_editor.c load_editor.h parse_dumpstream.c svnrload.c
Author: artagnon
Date: Sun Jul 25 08:44:21 2010
New Revision: 979002
URL: http://svn.apache.org/viewvc?rev=979002&view=rev
Log:
Add svnrload: currently a heavy WIP, with most of the code imported
from svnrdump
* subversion/svnrload
* subversion/svnrload/load_editor.c: From svnrdump/dump_editor.c
* subversion/svnrload/svnrload.c: From svnrdump/svnrdump.c
* subversion/svnrload/load_editor.h: From svnrdump/dump_editor.h
* subversion/svnrload/parse_dumpstream.c: Functionality to parse a
dumpstream
Added:
subversion/branches/svnrload/subversion/svnrload/
subversion/branches/svnrload/subversion/svnrload/load_editor.c
subversion/branches/svnrload/subversion/svnrload/load_editor.h
subversion/branches/svnrload/subversion/svnrload/parse_dumpstream.c
subversion/branches/svnrload/subversion/svnrload/svnrload.c
Added: subversion/branches/svnrload/subversion/svnrload/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/svnrload/subversion/svnrload/load_editor.c?rev=979002&view=auto
==============================================================================
--- subversion/branches/svnrload/subversion/svnrload/load_editor.c (added)
+++ subversion/branches/svnrload/subversion/svnrload/load_editor.c Sun Jul 25 08:44:21 2010
@@ -0,0 +1,780 @@
+/*
+ * dump_editor.c: The svn_delta_editor_t editor used by svnrdump
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include "svn_hash.h"
+#include "svn_pools.h"
+#include "svn_repos.h"
+#include "svn_path.h"
+#include "svn_props.h"
+#include "svn_dirent_uri.h"
+
+#include "dump_editor.h"
+
+#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
+
+/* The baton used by the dump editor. */
+struct load_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 load_props;
+ svn_boolean_t load_text;
+ svn_boolean_t load_props_pending;
+};
+
+/* 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,
+ svn_revnum_t copyfrom_rev,
+ void *edit_baton,
+ void *parent_dir_baton,
+ svn_boolean_t added,
+ apr_pool_t *pool)
+{
+ struct load_edit_baton *eb = edit_baton;
+ struct dir_baton *pb = parent_dir_baton;
+ struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
+ const char *abspath;
+
+ /* Disallow a path relative to nothing. */
+ SVN_ERR_ASSERT_NO_RETURN(!path || pb);
+
+ /* Construct the full path of this node. */
+ if (pb)
+ abspath = svn_uri_join("/", path, pool);
+ else
+ abspath = "/";
+
+ /* Remove leading slashes from copyfrom paths. */
+ if (copyfrom_path && strcmp(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_rev = copyfrom_rev;
+ new_db->added = added;
+ new_db->written_out = FALSE;
+ new_db->deleted_entries = apr_hash_make(pool);
+
+ 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 LOAD_DATA_TOO is set, only property headers are dumped.
+ */
+static svn_error_t *
+load_props(struct load_edit_baton *eb,
+ svn_boolean_t *trigger_var,
+ svn_boolean_t load_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 (load_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.
+ *
+ * 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.
+ */
+static svn_error_t *
+load_node(struct load_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)
+{
+ /* 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));
+
+ /* Node-kind: file */
+ if (kind == svn_node_file)
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
+ else if (kind == svn_node_dir)
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+
+
+ /* 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->load_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 */
+
+ 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(load_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->load_props = FALSE;
+ break;
+
+ 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->load_props = FALSE;
+ break;
+
+ case svn_node_action_add:
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+
+ if (!is_copy)
+ {
+ /* eb->load_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->load_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->load_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));
+
+ /* 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"));
+
+ break;
+ }
+
+ /* Dump property headers */
+ SVN_ERR(load_props(eb, &(eb->load_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)
+{
+ struct load_edit_baton *eb = edit_baton;
+ /* Allocate a special pool for the edit_baton to avoid pool
+ lifetime issues */
+ eb->pool = svn_pool_create(pool);
+ eb->props = apr_hash_make(eb->pool);
+ eb->deleted_props = apr_hash_make(eb->pool);
+ eb->propstring = svn_stringbuf_create("", eb->pool);
+
+ *root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
+ edit_baton, NULL, FALSE, pool);
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+delete_entry(const char *path,
+ svn_revnum_t revision,
+ void *parent_baton,
+ apr_pool_t *pool)
+{
+ struct dir_baton *pb = parent_baton;
+ const char *mypath = apr_pstrdup(pool, path);
+
+ /* Some pending properties to dump? */
+ SVN_ERR(load_props(pb->eb, &(pb->eb->load_props_pending), TRUE, pool));
+
+ /* 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;
+}
+
+static svn_error_t *
+add_directory(const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_rev,
+ apr_pool_t *pool,
+ void **child_baton)
+{
+ struct dir_baton *pb = parent_baton;
+ 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(load_props(pb->eb, &(pb->eb->load_props_pending), TRUE, pool));
+
+ /* This might be a replacement -- is the path already deleted? */
+ val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
+
+ /* Detect an add-with-history */
+ is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
+
+ /* Dump the node */
+ SVN_ERR(load_node(pb->eb, path,
+ svn_node_dir,
+ val ? svn_node_action_replace : svn_node_action_add,
+ 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);
+
+ new_db->written_out = TRUE;
+
+ *child_baton = new_db;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+open_directory(const char *path,
+ void *parent_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **child_baton)
+{
+ struct dir_baton *pb = parent_baton;
+ struct dir_baton *new_db;
+ const char *copyfrom_path = NULL;
+ svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
+
+ /* Some pending properties to dump? */
+ SVN_ERR(load_props(pb->eb, &(pb->eb->load_props_pending), TRUE, pool));
+
+ /* 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_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);
+ *child_baton = new_db;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_directory(void *dir_baton,
+ apr_pool_t *pool)
+{
+ struct dir_baton *db = dir_baton;
+ struct load_edit_baton *eb = db->eb;
+ apr_hash_index_t *hi;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+
+ /* Some pending properties to dump? */
+ SVN_ERR(load_props(eb, &(eb->load_props_pending), TRUE, pool));
+
+ /* 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(load_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;
+}
+
+static svn_error_t *
+add_file(const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_rev,
+ apr_pool_t *pool,
+ void **file_baton)
+{
+ struct dir_baton *pb = parent_baton;
+ void *val;
+ svn_boolean_t is_copy;
+
+ /* Some pending properties to dump? */
+ SVN_ERR(load_props(pb->eb, &(pb->eb->load_props_pending), TRUE, pool));
+
+ /* This might be a replacement -- is the path already deleted? */
+ val = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);
+
+ /* Detect add-with-history. */
+ is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
+
+ /* Dump the node. */
+ SVN_ERR(load_node(pb->eb, path,
+ svn_node_file,
+ val ? svn_node_action_replace : svn_node_action_add,
+ 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 */
+ *file_baton = pb->eb;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+open_file(const char *path,
+ void *parent_baton,
+ svn_revnum_t ancestor_revision,
+ apr_pool_t *pool,
+ void **file_baton)
+{
+ struct dir_baton *pb = parent_baton;
+ const char *copyfrom_path = NULL;
+ svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
+ apr_array_header_t *compose_path;
+
+ /* Some pending properties to dump? */
+ SVN_ERR(load_props(pb->eb, &(pb->eb->load_props_pending), TRUE, pool));
+
+ compose_path = apr_array_make(pool, 2, sizeof(const char *));
+
+ /* 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;
+ }
+
+ SVN_ERR(load_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 */
+ *file_baton = pb->eb;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+change_dir_prop(void *parent_baton,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ struct dir_baton *db = parent_baton;
+
+ if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+ return SVN_NO_ERROR;
+
+ 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; load_props_pending will take care of dumping the
+ props. If it not, dump the node itself before dumping the
+ props. */
+
+ SVN_ERR(load_node(db->eb, db->abspath, svn_node_dir,
+ svn_node_action_change, FALSE, db->copyfrom_path,
+ db->copyfrom_rev, pool));
+
+ SVN_ERR(load_props(db->eb, NULL, TRUE, pool));
+ db->written_out = TRUE;
+ }
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+change_file_prop(void *file_baton,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ struct load_edit_baton *eb = file_baton;
+
+ if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+ return SVN_NO_ERROR;
+
+ 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 */
+ eb->load_props_pending = TRUE;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+window_handler(svn_txdelta_window_t *window, void *baton)
+{
+ struct handler_baton *hb = baton;
+ struct load_edit_baton *eb = hb->eb;
+ static svn_error_t *err;
+
+ err = hb->apply_handler(window, hb->apply_baton);
+ if (window != NULL && !err)
+ return SVN_NO_ERROR;
+
+ if (err)
+ SVN_ERR(err);
+
+ /* Write information about the filepath to hb->eb */
+ eb->delta_abspath = apr_pstrdup(eb->pool, hb->delta_abspath);
+
+ /* Cleanup */
+ svn_pool_destroy(hb->pool);
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+apply_textdelta(void *file_baton, const char *base_checksum,
+ apr_pool_t *pool,
+ svn_txdelta_window_handler_t *handler,
+ void **handler_baton)
+{
+ struct load_edit_baton *eb = file_baton;
+
+ /* Custom handler_baton allocated in a separate pool */
+ apr_pool_t *handler_pool = svn_pool_create(pool);
+ struct handler_baton *hb = apr_pcalloc(handler_pool, sizeof(*hb));
+ hb->pool = handler_pool;
+ hb->eb = eb;
+
+ /* Use a temporary file to measure the text-content-length */
+ SVN_ERR(svn_stream_open_unique(&(hb->delta_filestream), &hb->delta_abspath,
+ NULL, svn_io_file_del_none, hb->pool,
+ hb->pool));
+
+ /* 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->load_text = TRUE;
+ eb->base_checksum = apr_pstrdup(pool, base_checksum);
+
+ /* 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;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_file(void *file_baton,
+ const char *text_checksum,
+ apr_pool_t *pool)
+{
+ struct load_edit_baton *eb = file_baton;
+ apr_file_t *delta_file;
+ svn_stream_t *delta_filestream;
+ apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
+
+ /* Some pending properties to dump? */
+ SVN_ERR(load_props(eb, &(eb->load_props_pending), FALSE, pool));
+
+ /* The prop headers have already been dumped in load_node; now dump
+ the text headers. */
+ if (eb->load_text)
+ {
+ /* Text-delta: true */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_TEXT_DELTA
+ ": true\n"));
+
+ SVN_ERR(svn_io_stat(info, eb->delta_abspath, APR_FINFO_SIZE, pool));
+
+ 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));
+
+ /* 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->load_props || eb->load_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));
+ else if (eb->load_text)
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %ld\n\n",
+ (unsigned long)info->size));
+
+ /* Dump the props; the propstring should have already been
+ written in load_node or above */
+ if (eb->load_props || eb->load_props_pending)
+ {
+ SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data,
+ &(eb->propstring->len)));
+
+ /* Cleanup */
+ eb->load_props = eb->load_props_pending = FALSE;
+ svn_hash__clear(eb->props, pool);
+ svn_hash__clear(eb->deleted_props, pool);
+ }
+
+ /* Dump the text */
+ if (eb->load_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->load_text = FALSE;
+ }
+
+ SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n"));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_edit(void *edit_baton, apr_pool_t *pool)
+{
+ struct load_edit_baton *eb = edit_baton;
+ svn_pool_destroy(eb->pool);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+get_load_editor(const svn_delta_editor_t **editor,
+ void **edit_baton,
+ svn_stream_t *stream,
+ apr_pool_t *pool)
+{
+ struct load_edit_baton *eb;
+ svn_delta_editor_t *de;
+
+ eb = apr_pcalloc(pool, sizeof(struct load_edit_baton));
+ eb->stream = stream;
+
+ de = svn_delta_default_editor(pool);
+ de->open_root = open_root;
+ de->delete_entry = delete_entry;
+ de->add_directory = add_directory;
+ de->open_directory = open_directory;
+ de->close_directory = close_directory;
+ de->change_dir_prop = change_dir_prop;
+ de->change_file_prop = change_file_prop;
+ de->apply_textdelta = apply_textdelta;
+ de->add_file = add_file;
+ de->open_file = open_file;
+ de->close_file = close_file;
+ de->close_edit = close_edit;
+
+ /* Set the edit_baton and editor. */
+ *edit_baton = eb;
+ *editor = de;
+
+ return SVN_NO_ERROR;
+}
Added: subversion/branches/svnrload/subversion/svnrload/load_editor.h
URL: http://svn.apache.org/viewvc/subversion/branches/svnrload/subversion/svnrload/load_editor.h?rev=979002&view=auto
==============================================================================
--- subversion/branches/svnrload/subversion/svnrload/load_editor.h (added)
+++ subversion/branches/svnrload/subversion/svnrload/load_editor.h Sun Jul 25 08:44:21 2010
@@ -0,0 +1,89 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file load_editor.h
+ * @brief The svn_delta_editor_t editor used by svnrdump
+ */
+
+#ifndef LOAD_EDITOR_H_
+#define LOAD_EDITOR_H_
+
+/**
+ * A directory baton used by all directory-related callback functions
+ * in the dump editor.
+ */
+struct dir_baton
+{
+ struct load_edit_baton *eb;
+ struct dir_baton *parent_dir_baton;
+
+ /* is this directory a new addition to this revision? */
+ svn_boolean_t added;
+
+ /* has this directory been written to the output stream? */
+ svn_boolean_t written_out;
+
+ /* the absolute path to this directory */
+ const char *abspath;
+
+ /* Copyfrom info for the node, if any */
+ const char *copyfrom_path;
+ svn_revnum_t copyfrom_rev;
+
+ /* Hash of paths that need to be deleted, though some -might- be
+ replaced. Maps const char * paths to this dir_baton. Note that
+ they're full paths, because that's what the editor driver gives
+ us, although they're all really within this directory. */
+ apr_hash_t *deleted_entries;
+};
+
+/**
+ * A handler baton to be used in window_handler().
+ */
+struct handler_baton
+{
+ svn_txdelta_window_handler_t apply_handler;
+ void *apply_baton;
+
+ /* Pool used for temporary allocations during delta application in
+ window_handler() */
+ apr_pool_t *pool;
+
+ /* Information about the path of the temporary file used */
+ const char *delta_abspath;
+ svn_stream_t *delta_filestream;
+
+ /* Global edit baton */
+ struct load_edit_baton *eb;
+};
+
+/**
+ * Get a dump editor @a editor along with a @a edit_baton allocated in
+ * @a pool. The editor will write output to @a stream.
+ */
+svn_error_t *
+get_load_editor(const svn_delta_editor_t **editor,
+ void **edit_baton,
+ svn_stream_t *stream,
+ apr_pool_t *pool);
+
+#endif
Added: subversion/branches/svnrload/subversion/svnrload/parse_dumpstream.c
URL: http://svn.apache.org/viewvc/subversion/branches/svnrload/subversion/svnrload/parse_dumpstream.c?rev=979002&view=auto
==============================================================================
--- subversion/branches/svnrload/subversion/svnrload/parse_dumpstream.c (added)
+++ subversion/branches/svnrload/subversion/svnrload/parse_dumpstream.c Sun Jul 25 08:44:21 2010
@@ -0,0 +1,129 @@
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_repos.h"
+#include "svn_io.h"
+
+static svn_error_t *
+new_revision_record(void **revision_baton,
+ apr_hash_t *headers,
+ void *parse_baton,
+ apr_pool_t *pool)
+{
+ printf("new_revision_record called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+new_node_record(void **node_baton,
+ apr_hash_t *headers,
+ void *revision_baton,
+ apr_pool_t *pool)
+{
+ printf("new_node_record called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+uuid_record(const char *uuid,
+ void *parse_baton,
+ apr_pool_t *pool)
+{
+ printf("uuid_record called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+set_revision_property(void *baton,
+ const char *name,
+ const svn_string_t *value)
+{
+ printf("set_revision_property called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+set_node_property(void *baton,
+ const char *name,
+ const svn_string_t *value)
+{
+ printf("set_node_property called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+remove_node_props(void *baton)
+{
+ printf("remove_node_props called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+set_fulltext(svn_stream_t **stream,
+ void *node_baton)
+{
+ printf("set_fulltext called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_node(void *baton)
+{
+ printf("close_node called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_revision(void *baton)
+{
+ printf("close_revision called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+delete_node_property(void *baton,
+ const char *name)
+{
+ printf("delete_node_property called");
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+apply_textdelta(svn_txdelta_window_handler_t *handler,
+ void **handler_baton,
+ void *node_baton)
+{
+ printf("apply_textdelta called");
+ return SVN_NO_ERROR;
+}
+
+int main()
+{
+ apr_pool_t *pool;
+ apr_file_t *dumpfile;
+ svn_stream_t *dumpstream;
+ svn_repos_parse_fns2_t *parser;
+
+ if (svn_cmdline_init ("parse_dumpstream", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ pool = svn_pool_create(NULL);
+
+ parser = apr_pcalloc(pool, sizeof(*parser));
+
+ parser->new_revision_record = new_revision_record;
+ parser->new_node_record = new_node_record;
+ parser->uuid_record = uuid_record;
+ parser->set_revision_property = set_revision_property;
+ parser->set_node_property = set_node_property;
+ parser->remove_node_props = remove_node_props;
+ parser->set_fulltext = set_fulltext;
+ parser->close_node = close_node;
+ parser->close_revision = close_revision;
+ parser->delete_node_property = delete_node_property;
+ parser->apply_textdelta = apply_textdelta;
+
+ apr_file_open_stdin(&dumpfile, pool);
+ dumpstream = svn_stream_from_aprfile2(dumpfile, FALSE, pool);
+ svn_repos_parse_dumpstream2(dumpstream, parser, NULL, NULL, NULL, pool);
+ svn_pool_destroy(pool);
+ return 0;
+}
Added: subversion/branches/svnrload/subversion/svnrload/svnrload.c
URL: http://svn.apache.org/viewvc/subversion/branches/svnrload/subversion/svnrload/svnrload.c?rev=979002&view=auto
==============================================================================
--- subversion/branches/svnrload/subversion/svnrload/svnrload.c (added)
+++ subversion/branches/svnrload/subversion/svnrload/svnrload.c Sun Jul 25 08:44:21 2010
@@ -0,0 +1,468 @@
+/*
+ * svnrload.c: Load a dumpfile to a remote repository.
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#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_string.h"
+#include "svn_props.h"
+
+#include "load_editor.h"
+
+enum svn_svnrload__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 apr_getopt_option_t svnrload__options[] =
+ {
+ {"revision", 'r', 1, "REV1[:REV2] range of revisions to dump"},
+ {"quiet", 'q', 0, "no progress (only errors to stderr"},
+ {"config-dir", opt_config_dir, 1, "read user configuration files from"
+ " directory ARG" },
+ {"username", opt_auth_username, 1, "specify a username ARG"},
+ {"password", opt_auth_password, 1, "specify a password ARG"},
+ {"non-interactive", opt_non_interactive, 0, "do no interactive"
+ " prompting"},
+ {"no-auth-cache", opt_auth_nocache, 0, "do not cache authentication"
+ " tokens"},
+
+ {"help", 'h', 0, "display this help"},
+ {"version", opt_version, 0, "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;
+};
+
+static svn_error_t *
+replay_revstart(svn_revnum_t revision,
+ void *replay_baton,
+ const svn_delta_editor_t **editor,
+ void **edit_baton,
+ apr_hash_t *rev_props,
+ apr_pool_t *pool)
+{
+ struct replay_baton *rb = replay_baton;
+ svn_stringbuf_t *propstring;
+ svn_stream_t *stdout_stream;
+ svn_stream_t *revprop_stream;
+
+ svn_stream_for_stdout(&stdout_stream, pool);
+
+ /* Revision-number: 19 */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ 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: 13 */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n", propstring->len));
+
+ /* Content-length: 29 */
+ SVN_ERR(svn_stream_printf(stdout_stream, pool,
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
+
+ /* Property data. */
+ SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
+ &(propstring->len)));
+
+ 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. */
+ *editor = rb->editor;
+ *edit_baton = rb->edit_baton;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+replay_revend(svn_revnum_t revision,
+ void *replay_baton,
+ const svn_delta_editor_t *editor,
+ void *edit_baton,
+ apr_hash_t *rev_props,
+ apr_pool_t *pool)
+{
+ /* No resources left to free. */
+ struct replay_baton *rb = replay_baton;
+ 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,
+ 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_config_t *cfg_config;
+
+ SVN_ERR(svn_ra_initialize(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), 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, 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 *load_editor;
+ struct replay_baton *replay_baton;
+ void *load_baton;
+ const char *uuid;
+ svn_stream_t *stdout_stream;
+
+ SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+
+ SVN_ERR(get_load_editor(&load_editor, &load_baton, stdout_stream, pool));
+
+ replay_baton = apr_pcalloc(pool, sizeof(*replay_baton));
+ replay_baton->editor = load_editor;
+ replay_baton->edit_baton = load_baton;
+ 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 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 *
+help(const char *progname, apr_pool_t *pool)
+{
+ apr_size_t i;
+
+ progname = ensure_appname(progname, pool);
+
+ SVN_ERR(svn_cmdline_printf(
+ pool,
+ "usage: %s URL [-r LOWER[:UPPER]]\n\n"
+ "Dump the contents of repository at remote URL "
+ "to stdout in a 'dumpfile' portable format.\n"
+ "Dump revisions LOWER rev through UPPER rev.\n"
+ "LOWER defaults to 0 and UPPER defaults to the "
+ "highest possible revision if omitted.\n\n"
+ "Valid options:\n",
+ progname));
+
+ for (i = 0; svnrload__options[i].name && svnrload__options[i].optch; i++)
+ {
+ const char *optstr;
+ svn_opt_format_option(&optstr, svnrload__options + i, TRUE, pool);
+ SVN_ERR(svn_cmdline_fprintf(stdout, pool, " %s\n", optstr));
+ }
+ return svn_cmdline_fprintf(stdout, pool, "\n");
+}
+
+static svn_error_t *
+version(const char *progname, apr_pool_t *pool)
+{
+ progname = ensure_appname(progname, pool);
+
+ return svn_opt_print_help3(NULL, progname, TRUE, FALSE, NULL,
+ 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 SVNRLOAD_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)
+
+
+int
+main(int argc, const char **argv)
+{
+ const char *url = NULL;
+ char *revision_cut = NULL;
+ svn_revnum_t start_revision = svn_opt_revision_unspecified;
+ svn_revnum_t end_revision = svn_opt_revision_unspecified;
+ svn_revnum_t latest_revision = svn_opt_revision_unspecified;
+ svn_boolean_t quiet = FALSE;
+ 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;
+
+ if (svn_cmdline_init ("svnrdump", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ pool = svn_pool_create(NULL);
+
+ SVNRLOAD_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, svnrload__options, &opt,
+ &opt_arg);
+
+ if (APR_STATUS_IS_EOF(status))
+ break;
+ if (status != APR_SUCCESS)
+ {
+ SVNRLOAD_ERR(usage(argv[0], pool));
+ exit(EXIT_FAILURE);
+ }
+
+ switch(opt)
+ {
+ case 'r':
+ {
+ revision_cut = strchr(opt_arg, ':');
+ if (revision_cut)
+ {
+ start_revision = (svn_revnum_t)strtoul(opt_arg,
+ &revision_cut, 10);
+ end_revision = (svn_revnum_t)strtoul(revision_cut + 1,
+ NULL, 10);
+ }
+ else
+ start_revision = (svn_revnum_t)strtoul(opt_arg, NULL, 10);
+ }
+ break;
+ case 'q':
+ quiet = TRUE;
+ break;
+ case opt_config_dir:
+ config_dir = opt_arg;
+ break;
+ case opt_version:
+ SVNRLOAD_ERR(version(argv[0], pool));
+ exit(EXIT_SUCCESS);
+ break;
+ case 'h':
+ SVNRLOAD_ERR(help(argv[0], pool));
+ exit(EXIT_SUCCESS);
+ break;
+ case opt_auth_username:
+ SVNRLOAD_ERR(svn_utf_cstring_to_utf8(&username, opt_arg, pool));
+ break;
+ case opt_auth_password:
+ SVNRLOAD_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;
+ }
+ }
+
+ /* Only continue if the only not option argument is a url, to allow
+ implementing 'svnrdump dump URL' like handling later without breaking
+ backward compatibility */
+ if ((os->ind != os->argc-1)
+ || !svn_path_is_url(os->argv[os->ind]))
+ {
+ SVNRLOAD_ERR(usage(argv[0], pool));
+ exit(EXIT_FAILURE);
+ }
+
+ SVNRLOAD_ERR(svn_utf_cstring_to_utf8(&url, os->argv[os->ind], pool));
+
+ url = svn_uri_canonicalize(os->argv[os->ind], pool);
+
+
+ SVNRLOAD_ERR(open_connection(&session,
+ url,
+ non_interactive,
+ username,
+ password,
+ config_dir,
+ no_auth_cache,
+ pool));
+
+ /* Have sane start_revision and end_revision defaults if unspecified */
+ SVNRLOAD_ERR(svn_ra_get_latest_revnum(session, &latest_revision, pool));
+ if (start_revision == svn_opt_revision_unspecified)
+ start_revision = 0;
+ if (end_revision == svn_opt_revision_unspecified)
+ end_revision = latest_revision;
+ if (end_revision > latest_revision)
+ {
+ SVN_INT_ERR(svn_cmdline_fprintf(stderr, pool,
+ "Revision %ld does not exist.\n",
+ end_revision));
+ exit(EXIT_FAILURE);
+ }
+ if (end_revision < start_revision)
+ {
+ SVN_INT_ERR(svn_cmdline_fprintf(stderr, pool,
+ "LOWER cannot be greater "
+ "than UPPER.\n"));
+ exit(EXIT_FAILURE);
+ }
+
+ SVNRLOAD_ERR(replay_range(session, url, start_revision, end_revision,
+ quiet, pool));
+
+ svn_pool_destroy(pool);
+
+ return 0;
+}
Re: svn commit: r979002 - in
/subversion/branches/svnrload/subversion/svnrload: ./ load_editor.c
load_editor.h parse_dumpstream.c svnrload.c
Posted by Ramkumar Ramachandra <ar...@gmail.com>.
Hi Daniel,
Daniel Shahaf writes:
> Doing the work on trunk or on a branch is orthogonal to my point.
Yeah, I understand. I'm just pointing out that I forgot to mark the
commits as "Don't review". I'll get some reviewable changes into trunk
in a few minutes.
-- Ram
Re: svn commit: r979002 - in
/subversion/branches/svnrload/subversion/svnrload: ./ load_editor.c
load_editor.h parse_dumpstream.c svnrload.c
Posted by Ramkumar Ramachandra <ar...@gmail.com>.
Hi Daniel,
Daniel Shahaf writes:
> Doing the work on trunk or on a branch is orthogonal to my point.
Yeah, I understand. I'm just pointing out that I forgot to mark the
commits as "Don't review". I'll get some reviewable changes into trunk
in a few minutes.
-- Ram
Re: svn commit: r979002 - in /subversion/branches/svnrload/subversion/svnrload:
./ load_editor.c load_editor.h parse_dumpstream.c svnrload.c
Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Doing the work on trunk or on a branch is orthogonal to my point.
Ramkumar Ramachandra wrote on Sun, 25 Jul 2010 at 16:02 -0000:
> Hi Daniel,
>
> Daniel Shahaf writes:
> > i.e., you could have done 'svn cp ../svnrdump/svnrdump.c svnrload.c',
> > and similarly for the other files. The benefits of this would be
> > reviewability (the diff would be far shorter than the current 1533
> > lines) and historical linkage (future 'svn log', and other, commands
> > would trace through the copy).
>
> I'm sorry, I should have explicitly mentioned that these files aren't
> for review. I'm deleting the branch and commiting everything to trunk
> in a few minutes (thanks to Bert for suggesting this) -- you can
> review the changes then.
>
> Thanks.
>
> -- Ram
>
Re: svn commit: r979002 - in /subversion/branches/svnrload/subversion/svnrload:
./ load_editor.c load_editor.h parse_dumpstream.c svnrload.c
Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
Doing the work on trunk or on a branch is orthogonal to my point.
Ramkumar Ramachandra wrote on Sun, 25 Jul 2010 at 16:02 -0000:
> Hi Daniel,
>
> Daniel Shahaf writes:
> > i.e., you could have done 'svn cp ../svnrdump/svnrdump.c svnrload.c',
> > and similarly for the other files. The benefits of this would be
> > reviewability (the diff would be far shorter than the current 1533
> > lines) and historical linkage (future 'svn log', and other, commands
> > would trace through the copy).
>
> I'm sorry, I should have explicitly mentioned that these files aren't
> for review. I'm deleting the branch and commiting everything to trunk
> in a few minutes (thanks to Bert for suggesting this) -- you can
> review the changes then.
>
> Thanks.
>
> -- Ram
>
Re: svn commit: r979002 - in
/subversion/branches/svnrload/subversion/svnrload: ./ load_editor.c
load_editor.h parse_dumpstream.c svnrload.c
Posted by Ramkumar Ramachandra <ar...@gmail.com>.
Hi Daniel,
Daniel Shahaf writes:
> i.e., you could have done 'svn cp ../svnrdump/svnrdump.c svnrload.c',
> and similarly for the other files. The benefits of this would be
> reviewability (the diff would be far shorter than the current 1533
> lines) and historical linkage (future 'svn log', and other, commands
> would trace through the copy).
I'm sorry, I should have explicitly mentioned that these files aren't
for review. I'm deleting the branch and commiting everything to trunk
in a few minutes (thanks to Bert for suggesting this) -- you can
review the changes then.
Thanks.
-- Ram
Re: svn commit: r979002 - in
/subversion/branches/svnrload/subversion/svnrload: ./ load_editor.c
load_editor.h parse_dumpstream.c svnrload.c
Posted by Ramkumar Ramachandra <ar...@gmail.com>.
Hi Daniel,
Daniel Shahaf writes:
> i.e., you could have done 'svn cp ../svnrdump/svnrdump.c svnrload.c',
> and similarly for the other files. The benefits of this would be
> reviewability (the diff would be far shorter than the current 1533
> lines) and historical linkage (future 'svn log', and other, commands
> would trace through the copy).
I'm sorry, I should have explicitly mentioned that these files aren't
for review. I'm deleting the branch and commiting everything to trunk
in a few minutes (thanks to Bert for suggesting this) -- you can
review the changes then.
Thanks.
-- Ram
Re: svn commit: r979002 - in /subversion/branches/svnrload/subversion/svnrload:
./ load_editor.c load_editor.h parse_dumpstream.c svnrload.c
Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
artagnon@apache.org wrote on Sun, 25 Jul 2010 at 11:44 -0000:
> Author: artagnon
> Date: Sun Jul 25 08:44:21 2010
> New Revision: 979002
>
> URL: http://svn.apache.org/viewvc?rev=979002&view=rev
> Log:
> Add svnrload: currently a heavy WIP, with most of the code imported
> from svnrdump
>
> * subversion/svnrload
> * subversion/svnrload/load_editor.c: From svnrdump/dump_editor.c
> * subversion/svnrload/svnrload.c: From svnrdump/svnrdump.c
> * subversion/svnrload/load_editor.h: From svnrdump/dump_editor.h
> * subversion/svnrload/parse_dumpstream.c: Functionality to parse a
> dumpstream
>
> Added:
> subversion/branches/svnrload/subversion/svnrload/
> subversion/branches/svnrload/subversion/svnrload/load_editor.c
> subversion/branches/svnrload/subversion/svnrload/load_editor.h
> subversion/branches/svnrload/subversion/svnrload/parse_dumpstream.c
> subversion/branches/svnrload/subversion/svnrload/svnrload.c
>
> Added: subversion/branches/svnrload/subversion/svnrload/load_editor.c
> URL: http://svn.apache.org/viewvc/subversion/branches/svnrload/subversion/svnrload/load_editor.c?rev=979002&view=auto
> ==============================================================================
> --- subversion/branches/svnrload/subversion/svnrload/load_editor.c (added)
> +++ subversion/branches/svnrload/subversion/svnrload/load_editor.c Sun Jul 25 08:44:21 2010
> @@ -0,0 +1,780 @@
> +/*
> + * dump_editor.c: The svn_delta_editor_t editor used by svnrdump
> + *
Wrong header.
And, by the way, the new files you added were added "without history";
was that a concious decision, or were you not aware of the option to add
them with copyfrom information?
i.e., you could have done 'svn cp ../svnrdump/svnrdump.c svnrload.c',
and similarly for the other files. The benefits of this would be
reviewability (the diff would be far shorter than the current 1533
lines) and historical linkage (future 'svn log', and other, commands
would trace through the copy).
Daniel
(not reviewing the rest of this; 1533 lines is too much)
Re: svn commit: r979002 - in /subversion/branches/svnrload/subversion/svnrload:
./ load_editor.c load_editor.h parse_dumpstream.c svnrload.c
Posted by Daniel Shahaf <d....@daniel.shahaf.name>.
artagnon@apache.org wrote on Sun, 25 Jul 2010 at 11:44 -0000:
> Author: artagnon
> Date: Sun Jul 25 08:44:21 2010
> New Revision: 979002
>
> URL: http://svn.apache.org/viewvc?rev=979002&view=rev
> Log:
> Add svnrload: currently a heavy WIP, with most of the code imported
> from svnrdump
>
> * subversion/svnrload
> * subversion/svnrload/load_editor.c: From svnrdump/dump_editor.c
> * subversion/svnrload/svnrload.c: From svnrdump/svnrdump.c
> * subversion/svnrload/load_editor.h: From svnrdump/dump_editor.h
> * subversion/svnrload/parse_dumpstream.c: Functionality to parse a
> dumpstream
>
> Added:
> subversion/branches/svnrload/subversion/svnrload/
> subversion/branches/svnrload/subversion/svnrload/load_editor.c
> subversion/branches/svnrload/subversion/svnrload/load_editor.h
> subversion/branches/svnrload/subversion/svnrload/parse_dumpstream.c
> subversion/branches/svnrload/subversion/svnrload/svnrload.c
>
> Added: subversion/branches/svnrload/subversion/svnrload/load_editor.c
> URL: http://svn.apache.org/viewvc/subversion/branches/svnrload/subversion/svnrload/load_editor.c?rev=979002&view=auto
> ==============================================================================
> --- subversion/branches/svnrload/subversion/svnrload/load_editor.c (added)
> +++ subversion/branches/svnrload/subversion/svnrload/load_editor.c Sun Jul 25 08:44:21 2010
> @@ -0,0 +1,780 @@
> +/*
> + * dump_editor.c: The svn_delta_editor_t editor used by svnrdump
> + *
Wrong header.
And, by the way, the new files you added were added "without history";
was that a concious decision, or were you not aware of the option to add
them with copyfrom information?
i.e., you could have done 'svn cp ../svnrdump/svnrdump.c svnrload.c',
and similarly for the other files. The benefits of this would be
reviewability (the diff would be far shorter than the current 1533
lines) and historical linkage (future 'svn log', and other, commands
would trace through the copy).
Daniel
(not reviewing the rest of this; 1533 lines is too much)