* [WIP PATCH 1/7] Add skeleton RA svnclient
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
@ 2010-06-23 16:22 ` Ramkumar Ramachandra
2010-06-25 0:14 ` Jonathan Nieder
2010-06-23 16:22 ` [WIP PATCH 2/7] Add stripped dump editor Ramkumar Ramachandra
` (6 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 16:22 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
The SVN client uses the RA API to connect to a remote server and
replay revisions. Currently, it wraps a debug editor to print out some
tree information. In future, it will dump the data in every revision
to stdout in dumpfile format (hopefully) without resorting to the FS
API.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
Makefile | 4 +
debug_editor.c | 413 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
debug_editor.h | 6 +
svnclient_ra.c | 131 ++++++++++++++++++
4 files changed, 554 insertions(+), 0 deletions(-)
create mode 100644 Makefile
create mode 100644 debug_editor.c
create mode 100644 debug_editor.h
create mode 100644 svnclient_ra.c
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c3c695c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,4 @@
+svnclient_ra: *.c *.h
+ $(CC) -Wall -Werror -ggdb3 -O0 -o $@ svnclient_ra.c debug_editor.c -lsvn_client-1 -I. -I/usr/local/include/subversion-1 -I/usr/include/apr-1.0
+clean:
+ $(RM) svnclient_ra
diff --git a/debug_editor.c b/debug_editor.c
new file mode 100644
index 0000000..ef77e44
--- /dev/null
+++ b/debug_editor.c
@@ -0,0 +1,413 @@
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_client.h"
+#include "svn_ra.h"
+
+struct edit_baton
+{
+ const svn_delta_editor_t *wrapped_editor;
+ void *wrapped_edit_baton;
+
+ int indent_level;
+
+ svn_stream_t *out;
+};
+
+struct dir_baton
+{
+ void *edit_baton;
+ void *wrapped_dir_baton;
+};
+
+struct file_baton
+{
+ void *edit_baton;
+ void *wrapped_file_baton;
+};
+
+static svn_error_t *
+write_indent(struct edit_baton *eb, apr_pool_t *pool)
+{
+ int i;
+
+ for (i = 0; i < eb->indent_level; ++i)
+ SVN_ERR(svn_stream_printf(eb->out, pool, " "));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+set_target_revision(void *edit_baton,
+ svn_revnum_t target_revision,
+ apr_pool_t *pool)
+{
+ struct edit_baton *eb = edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "set_target_revision : %ld\n",
+ target_revision));
+
+ return eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
+ target_revision,
+ pool);
+}
+
+static svn_error_t *
+open_root(void *edit_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **root_baton)
+{
+ struct edit_baton *eb = edit_baton;
+ struct dir_baton *dir_baton = apr_palloc(pool, sizeof(*dir_baton));
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "open_root : %ld\n",
+ base_revision));
+ eb->indent_level++;
+
+ SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
+ base_revision,
+ pool,
+ &dir_baton->wrapped_dir_baton));
+
+ dir_baton->edit_baton = edit_baton;
+
+ *root_baton = dir_baton;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+delete_entry(const char *path,
+ svn_revnum_t base_revision,
+ void *parent_baton,
+ apr_pool_t *pool)
+{
+ struct dir_baton *pb = parent_baton;
+ struct edit_baton *eb = pb->edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "delete_entry : %s:%ld\n",
+ path, base_revision));
+
+ return eb->wrapped_editor->delete_entry(path,
+ base_revision,
+ pb->wrapped_dir_baton,
+ pool);
+}
+
+static svn_error_t *
+add_directory(const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ apr_pool_t *pool,
+ void **child_baton)
+{
+ struct dir_baton *pb = parent_baton;
+ struct edit_baton *eb = pb->edit_baton;
+ struct dir_baton *b = apr_palloc(pool, sizeof(*b));
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool,
+ "add_directory : '%s' [from '%s':%ld]\n",
+ path, copyfrom_path, copyfrom_revision));
+ eb->indent_level++;
+
+ SVN_ERR(eb->wrapped_editor->add_directory(path,
+ pb->wrapped_dir_baton,
+ copyfrom_path,
+ copyfrom_revision,
+ pool,
+ &b->wrapped_dir_baton));
+
+ b->edit_baton = eb;
+ *child_baton = b;
+
+ 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 edit_baton *eb = pb->edit_baton;
+ struct dir_baton *db = apr_palloc(pool, sizeof(*db));
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "open_directory : '%s':%ld\n",
+ path, base_revision));
+ eb->indent_level++;
+
+ SVN_ERR(eb->wrapped_editor->open_directory(path,
+ pb->wrapped_dir_baton,
+ base_revision,
+ pool,
+ &db->wrapped_dir_baton));
+
+ db->edit_baton = eb;
+ *child_baton = db;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+add_file(const char *path,
+ void *parent_baton,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ apr_pool_t *pool,
+ void **file_baton)
+{
+ struct dir_baton *pb = parent_baton;
+ struct edit_baton *eb = pb->edit_baton;
+ struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool,
+ "add_file : '%s' [from '%s':%ld]\n",
+ path, copyfrom_path, copyfrom_revision));
+
+ eb->indent_level++;
+
+ SVN_ERR(eb->wrapped_editor->add_file(path,
+ pb->wrapped_dir_baton,
+ copyfrom_path,
+ copyfrom_revision,
+ pool,
+ &fb->wrapped_file_baton));
+
+ fb->edit_baton = eb;
+ *file_baton = fb;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+open_file(const char *path,
+ void *parent_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **file_baton)
+{
+ struct dir_baton *pb = parent_baton;
+ struct edit_baton *eb = pb->edit_baton;
+ struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "open_file : '%s':%ld\n",
+ path, base_revision));
+
+ eb->indent_level++;
+
+ SVN_ERR(eb->wrapped_editor->open_file(path,
+ pb->wrapped_dir_baton,
+ base_revision,
+ pool,
+ &fb->wrapped_file_baton));
+
+ fb->edit_baton = eb;
+ *file_baton = fb;
+
+ 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 file_baton *fb = file_baton;
+ struct edit_baton *eb = fb->edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "apply_textdelta : %s\n",
+ base_checksum));
+
+ SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,
+ base_checksum,
+ pool,
+ handler,
+ handler_baton));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_file(void *file_baton,
+ const char *text_checksum,
+ apr_pool_t *pool)
+{
+ struct file_baton *fb = file_baton;
+ struct edit_baton *eb = fb->edit_baton;
+
+ eb->indent_level--;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "close_file : %s\n",
+ text_checksum));
+
+ SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,
+ text_checksum, pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+absent_file(const char *path,
+ void *file_baton,
+ apr_pool_t *pool)
+{
+ struct file_baton *fb = file_baton;
+ struct edit_baton *eb = fb->edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "absent_file : %s\n", path));
+
+ SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,
+ pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_directory(void *dir_baton,
+ apr_pool_t *pool)
+{
+ struct dir_baton *db = dir_baton;
+ struct edit_baton *eb = db->edit_baton;
+
+ eb->indent_level--;
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "close_directory\n"));
+
+ SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,
+ pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+absent_directory(const char *path,
+ void *dir_baton,
+ apr_pool_t *pool)
+{
+ struct dir_baton *db = dir_baton;
+ struct edit_baton *eb = db->edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "absent_directory : %s\n",
+ path));
+
+ SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,
+ pool));
+
+ 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 file_baton *fb = file_baton;
+ struct edit_baton *eb = fb->edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "change_file_prop : %s\n",
+ name));
+
+ SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,
+ name,
+ value,
+ pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+change_dir_prop(void *dir_baton,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ struct dir_baton *db = dir_baton;
+ struct edit_baton *eb = db->edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "change_dir_prop : %s\n", name));
+
+ SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
+ name,
+ value,
+ pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_edit(void *edit_baton,
+ apr_pool_t *pool)
+{
+ struct edit_baton *eb = edit_baton;
+
+ SVN_ERR(write_indent(eb, pool));
+ SVN_ERR(svn_stream_printf(eb->out, pool, "close_edit\n"));
+
+ SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
+ void **edit_baton,
+ const svn_delta_editor_t *wrapped_editor,
+ void *wrapped_edit_baton,
+ apr_pool_t *pool)
+{
+ svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
+ struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
+ apr_file_t *errfp;
+ svn_stream_t *out;
+
+ apr_status_t apr_err = apr_file_open_stderr(&errfp, pool);
+ if (apr_err)
+ return svn_error_wrap_apr(apr_err, "Problem opening stderr");
+
+ out = svn_stream_from_aprfile2(errfp, TRUE, pool);
+
+ tree_editor->set_target_revision = set_target_revision;
+ tree_editor->open_root = open_root;
+ tree_editor->delete_entry = delete_entry;
+ tree_editor->add_directory = add_directory;
+ tree_editor->open_directory = open_directory;
+ tree_editor->change_dir_prop = change_dir_prop;
+ tree_editor->close_directory = close_directory;
+ tree_editor->absent_directory = absent_directory;
+ tree_editor->add_file = add_file;
+ tree_editor->open_file = open_file;
+ tree_editor->apply_textdelta = apply_textdelta;
+ tree_editor->change_file_prop = change_file_prop;
+ tree_editor->close_file = close_file;
+ tree_editor->absent_file = absent_file;
+ tree_editor->close_edit = close_edit;
+
+ eb->wrapped_editor = wrapped_editor;
+ eb->wrapped_edit_baton = wrapped_edit_baton;
+ eb->out = out;
+ eb->indent_level = 0;
+
+ *editor = tree_editor;
+ *edit_baton = eb;
+
+ return SVN_NO_ERROR;
+}
diff --git a/debug_editor.h b/debug_editor.h
new file mode 100644
index 0000000..ae87c36
--- /dev/null
+++ b/debug_editor.h
@@ -0,0 +1,6 @@
+svn_error_t *
+svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
+ void **edit_baton,
+ const svn_delta_editor_t *wrapped_editor,
+ void *wrapped_edit_baton,
+ apr_pool_t *pool);
diff --git a/svnclient_ra.c b/svnclient_ra.c
new file mode 100644
index 0000000..2ed04af
--- /dev/null
+++ b/svnclient_ra.c
@@ -0,0 +1,131 @@
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_client.h"
+#include "svn_ra.h"
+
+#include "debug_editor.h"
+
+static apr_pool_t *pool = NULL;
+static svn_client_ctx_t *ctx = NULL;
+static svn_ra_session_t *session = NULL;
+
+typedef struct {
+ void *editor, *baton;
+} replay_baton_t;
+
+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)
+{
+ *editor = ((replay_baton_t *) replay_baton)->editor;
+ *edit_baton = ((replay_baton_t *) replay_baton)->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)
+{
+ SVN_ERR(editor->close_edit(edit_baton, pool));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *build_auth_baton()
+{
+ svn_auth_provider_object_t *provider;
+ apr_array_header_t *providers
+ = apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));
+
+ svn_auth_get_simple_prompt_provider (&provider,
+ NULL,
+ NULL,
+ 2,
+ pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+ svn_auth_get_username_prompt_provider (&provider,
+ NULL,
+ NULL,
+ 2,
+ pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+ svn_auth_open (&ctx->auth_baton, providers, pool);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *populate_context()
+{
+ const char *http_library;
+
+ SVN_ERR(svn_config_get_config(&(ctx->config), NULL, pool));
+
+ http_library = getenv("SVN_HTTP_LIBRARY");
+ if (http_library)
+ svn_config_set(apr_hash_get(ctx->config, "servers", APR_HASH_KEY_STRING),
+ "global", "http-library", http_library);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *open_connection(const char *url)
+{
+ SVN_ERR(svn_config_ensure (NULL, pool));
+ SVN_ERR(svn_client_create_context (&ctx, pool));
+ SVN_ERR(svn_ra_initialize(pool));
+
+#if defined(WIN32) || defined(__CYGWIN__)
+ if (getenv("SVN_ASP_DOT_NET_HACK"))
+ SVN_ERR(svn_wc_set_adm_dir("_svn", pool));
+#endif
+
+ SVN_ERR(populate_context());
+ SVN_ERR(build_auth_baton());
+ SVN_ERR(svn_client_open_ra_session(&session, url, ctx, pool));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_revision)
+{
+ svn_revnum_t latest_revision;
+ svn_delta_editor_t *editor, *debug_editor;
+ replay_baton_t *replay_baton = apr_palloc(pool, sizeof(replay_baton_t));
+ void *debug_baton;
+ SVN_ERR(svn_ra_get_latest_revnum(session, &latest_revision, pool));
+ printf("%ld\n", latest_revision);
+ editor = svn_delta_default_editor(pool);
+ SVN_ERR(svn_delta__get_debug_editor((const svn_delta_editor_t **)&debug_editor,
+ &debug_baton, editor,
+ NULL, pool));
+ replay_baton->editor = debug_editor;
+ replay_baton->baton = debug_baton;
+ SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
+ 0, TRUE, replay_revstart, replay_revend,
+ replay_baton, pool));
+ return SVN_NO_ERROR;
+}
+
+void close_connection()
+{
+ svn_pool_destroy(pool);
+}
+
+int main()
+{
+ const char url[] = "http://svn.apache.org/repos/asf";
+ svn_revnum_t start_revision = 1, end_revision = 5;
+ if (svn_cmdline_init ("svnclient_ra", stderr) != EXIT_SUCCESS)
+ return 1;
+ pool = svn_pool_create(NULL);
+
+ SVN_INT_ERR(open_connection(url));
+ SVN_INT_ERR(replay_range(start_revision, end_revision));
+
+ close_connection();
+ return 0;
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [WIP PATCH 1/7] Add skeleton RA svnclient
2010-06-23 16:22 ` [WIP PATCH 1/7] Add skeleton RA svnclient Ramkumar Ramachandra
@ 2010-06-25 0:14 ` Jonathan Nieder
2010-06-25 9:07 ` Daniel Shahaf
0 siblings, 1 reply; 18+ messages in thread
From: Jonathan Nieder @ 2010-06-25 0:14 UTC (permalink / raw)
To: Ramkumar Ramachandra
Cc: Git Mailing List, David Michael Barr, Sverre Rabbelier,
Daniel Shahaf
Ramkumar Ramachandra wrote:
> In future, it will dump the data in every revision
> to stdout in dumpfile format (hopefully) without resorting to the FS
> API.
For now, just some naïve questions. Warning: I know nothing about
svn internals.
I assume this corresponds to the ra-svn branch of
<http://github.com/artagnon/svn-dump-fast-export.git>. Has the
relevant code changed much since you sent it?
> --- /dev/null
> +++ b/debug_editor.c
> @@ -0,0 +1,413 @@
> +#include "svn_pools.h"
> +#include "svn_cmdline.h"
> +#include "svn_client.h"
> +#include "svn_ra.h"
> +
> +struct edit_baton
What is a baton?
[...]
> + void *wrapped_edit_baton;
[...]
> + void *edit_baton;
> + void *wrapped_dir_baton;
[...]
> + void *edit_baton;
> + void *wrapped_file_baton;
Are these opaque types necessary?
> +
> +static svn_error_t *
> +write_indent(struct edit_baton *eb, apr_pool_t *pool)
> +{
> + int i;
> +
> + for (i = 0; i < eb->indent_level; ++i)
> + SVN_ERR(svn_stream_printf(eb->out, pool, " "));
> +
> + return SVN_NO_ERROR;
> +}
What does this do? Is SVN_ERR for debugging? Where does the output go?
> +static svn_error_t *
> +set_target_revision(void *edit_baton,
> + svn_revnum_t target_revision,
> + apr_pool_t *pool)
[...]
> +static svn_error_t *
> +open_root(void *edit_baton,
[...]
> +static svn_error_t *
> +close_edit(void *edit_baton,
[...]
I take it these are callbacks? Is there overview documentation for
them somewhere?
> +svn_error_t *
> +svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
> + void **edit_baton,
> + const svn_delta_editor_t *wrapped_editor,
> + void *wrapped_edit_baton,
> + apr_pool_t *pool)
> +{
> + svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
> + struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
> + apr_file_t *errfp;
> + svn_stream_t *out;
> +
> + apr_status_t apr_err = apr_file_open_stderr(&errfp, pool);
> + if (apr_err)
> + return svn_error_wrap_apr(apr_err, "Problem opening stderr");
> +
> + out = svn_stream_from_aprfile2(errfp, TRUE, pool);
> +
> + tree_editor->set_target_revision = set_target_revision;
> + tree_editor->open_root = open_root;
> + tree_editor->delete_entry = delete_entry;
> + tree_editor->add_directory = add_directory;
> + tree_editor->open_directory = open_directory;
> + tree_editor->change_dir_prop = change_dir_prop;
> + tree_editor->close_directory = close_directory;
> + tree_editor->absent_directory = absent_directory;
> + tree_editor->add_file = add_file;
> + tree_editor->open_file = open_file;
> + tree_editor->apply_textdelta = apply_textdelta;
> + tree_editor->change_file_prop = change_file_prop;
> + tree_editor->close_file = close_file;
> + tree_editor->absent_file = absent_file;
> + tree_editor->close_edit = close_edit;
I take it that the fields of svn_delta_editor_t do not have a
well-defined order? Ugh.
In any case, I suspect this would be easier to read rearranged a little:
1. declarations for callbacks
2. get_debug_editor implementation
3. definitions of types not needed in get_debug_editor()
4. implementations of callbacks
That way, a person reading straight through can figure out what’s
going on a little earlier.
> --- /dev/null
> +++ b/svnclient_ra.c
[...]
> +int main()
> +{
> + const char url[] = "http://svn.apache.org/repos/asf";
> + svn_revnum_t start_revision = 1, end_revision = 5;
> + if (svn_cmdline_init ("svnclient_ra", stderr) != EXIT_SUCCESS)
> + return 1;
> + pool = svn_pool_create(NULL);
> +
> + SVN_INT_ERR(open_connection(url));
> + SVN_INT_ERR(replay_range(start_revision, end_revision));
> +
> + close_connection();
> + return 0;
> +}
What is svn_cmdline_init? Is this code destined for inclusion in svn
upstream, and if so, where can one find the surrounding code this
should fit in with?
Jonathan
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [WIP PATCH 1/7] Add skeleton RA svnclient
2010-06-25 0:14 ` Jonathan Nieder
@ 2010-06-25 9:07 ` Daniel Shahaf
2010-06-25 11:07 ` Ramkumar Ramachandra
2010-06-25 13:34 ` Jonathan Nieder
0 siblings, 2 replies; 18+ messages in thread
From: Daniel Shahaf @ 2010-06-25 9:07 UTC (permalink / raw)
To: Jonathan Nieder
Cc: Ramkumar Ramachandra, Git Mailing List, David Michael Barr,
Sverre Rabbelier
[-- Attachment #1: Type: TEXT/PLAIN, Size: 5529 bytes --]
Jonathan Nieder wrote on Fri, 25 Jun 2010 at 03:14 -0000:
> Ramkumar Ramachandra wrote:
>
> > In future, it will dump the data in every revision
> > to stdout in dumpfile format (hopefully) without resorting to the FS
> > API.
>
> For now, just some naïve questions. Warning: I know nothing about
> svn internals.
>
> I assume this corresponds to the ra-svn branch of
> <http://github.com/artagnon/svn-dump-fast-export.git>. Has the
> relevant code changed much since you sent it?
>
> > --- /dev/null
> > +++ b/debug_editor.c
> > @@ -0,0 +1,413 @@
> > +#include "svn_pools.h"
> > +#include "svn_cmdline.h"
> > +#include "svn_client.h"
> > +#include "svn_ra.h"
> > +
> > +struct edit_baton
>
> What is a baton?
>
The context object for a callback.
You call:
some_function(your_callback_function, your_baton)
which then calls:
your_callback_function(your_baton, other_arguments)
> [...]
> > + void *wrapped_edit_baton;
> [...]
> > + void *edit_baton;
> > + void *wrapped_dir_baton;
> [...]
> > + void *edit_baton;
> > + void *wrapped_file_baton;
>
> Are these opaque types necessary?
>
The convention in Subversion's code is to convert the void * to
a concrete_baton_t * only inside the callback. If you wish to declare
these, e.g., as
debug_editor_baton_t *wrapped_baton;
You can probably do that too.
> > +
> > +static svn_error_t *
> > +write_indent(struct edit_baton *eb, apr_pool_t *pool)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < eb->indent_level; ++i)
> > + SVN_ERR(svn_stream_printf(eb->out, pool, " "));
> > +
> > + return SVN_NO_ERROR;
> > +}
>
> What does this do? Is SVN_ERR for debugging?
That's how we implement exception throwing in C. SVN_ERR means "if this
returned a non-NULL svn_error_t *, then return that error to our
caller".
The other pattern does
svn_error_t *err = svn_stream_printf();
and then inspects err and err->apr_err to decide whether to ignore the
error or return it (possibly wrapped).
> Where does the output go?
>
SVN_ERR does not print anything. It may return(), though.
> > +static svn_error_t *
> > +set_target_revision(void *edit_baton,
> > + svn_revnum_t target_revision,
> > + apr_pool_t *pool)
> [...]
> > +static svn_error_t *
> > +open_root(void *edit_baton,
> [...]
> > +static svn_error_t *
> > +close_edit(void *edit_baton,
> [...]
>
> I take it these are callbacks? Is there overview documentation for
> them somewhere?
>
svn_delta_editor_t in
http://svn.apache.org/repos/asf/subversion/trunk/subversion/include/svn_delta.h
> > +svn_error_t *
> > +svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
> > + void **edit_baton,
> > + const svn_delta_editor_t *wrapped_editor,
> > + void *wrapped_edit_baton,
> > + apr_pool_t *pool)
> > +{
> > + svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
> > + struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
> > + apr_file_t *errfp;
> > + svn_stream_t *out;
> > +
> > + apr_status_t apr_err = apr_file_open_stderr(&errfp, pool);
> > + if (apr_err)
> > + return svn_error_wrap_apr(apr_err, "Problem opening stderr");
> > +
> > + out = svn_stream_from_aprfile2(errfp, TRUE, pool);
> > +
> > + tree_editor->set_target_revision = set_target_revision;
> > + tree_editor->open_root = open_root;
> > + tree_editor->delete_entry = delete_entry;
> > + tree_editor->add_directory = add_directory;
> > + tree_editor->open_directory = open_directory;
> > + tree_editor->change_dir_prop = change_dir_prop;
> > + tree_editor->close_directory = close_directory;
> > + tree_editor->absent_directory = absent_directory;
> > + tree_editor->add_file = add_file;
> > + tree_editor->open_file = open_file;
> > + tree_editor->apply_textdelta = apply_textdelta;
> > + tree_editor->change_file_prop = change_file_prop;
> > + tree_editor->close_file = close_file;
> > + tree_editor->absent_file = absent_file;
> > + tree_editor->close_edit = close_edit;
>
> I take it that the fields of svn_delta_editor_t do not have a
> well-defined order? Ugh.
>
I don't understand. It seems that the fields here appear in the same
order as in the definition of struct svn_delta_editor_t.
> In any case, I suspect this would be easier to read rearranged a little:
>
> 1. declarations for callbacks
> 2. get_debug_editor implementation
> 3. definitions of types not needed in get_debug_editor()
> 4. implementations of callbacks
>
> That way, a person reading straight through can figure out what’s
> going on a little earlier.
>
> > --- /dev/null
> > +++ b/svnclient_ra.c
> [...]
> > +int main()
> > +{
> > + const char url[] = "http://svn.apache.org/repos/asf";
> > + svn_revnum_t start_revision = 1, end_revision = 5;
> > + if (svn_cmdline_init ("svnclient_ra", stderr) != EXIT_SUCCESS)
> > + return 1;
> > + pool = svn_pool_create(NULL);
> > +
> > + SVN_INT_ERR(open_connection(url));
> > + SVN_INT_ERR(replay_range(start_revision, end_revision));
> > +
> > + close_connection();
> > + return 0;
> > +}
>
> What is svn_cmdline_init?
A Subversion API that does some necessary initializations (e.g., calls
apr_initialize()). See subversion/include/svn_cmdline.h for docs
(and subversion/libsvn_subr/cmdline.c for the implementation).
> Is this code destined for inclusion in svn upstream, and if so, where
> can one find the surrounding code this should fit in with?
>
> Jonathan
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [WIP PATCH 1/7] Add skeleton RA svnclient
2010-06-25 9:07 ` Daniel Shahaf
@ 2010-06-25 11:07 ` Ramkumar Ramachandra
2010-06-25 11:30 ` Daniel Shahaf
2010-06-25 14:45 ` [WIP PATCH 1/7] Add skeleton RA svnclient Jonathan Nieder
2010-06-25 13:34 ` Jonathan Nieder
1 sibling, 2 replies; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-25 11:07 UTC (permalink / raw)
To: Jonathan Nieder
Cc: Git Mailing List, David Michael Barr, Sverre Rabbelier,
Daniel Shahaf
Hi Jonathan and Daniel,
Jonathan: First, thanks for bringing up these questions- they will
definitely help future reviewers. I'll now sprinkle Daniel's replies
with a few of my observations.
Daniel: Thanks for responding to the questions- your insights as a
core Subversion developer are most appreciated. I'll add a few notes
to your answers now.
Daniel Shahaf wrote:
> Jonathan Nieder wrote on Fri, 25 Jun 2010 at 03:14 -0000:
>> For now, just some naïve questions. Warning: I know nothing about
>> svn internals.
That's alright. I highly encourage naïve questions- I'm new to SVN
myself. I also highly recommend reading the API documentation and
going through the code for answers to "why is it like THIS" questions
as I haven't manged to clean out the Subversion style yet. Hopefully,
I'll have some good notes that I can attach with my next series to put
in the trunk.
>> I assume this corresponds to the ra-svn branch of
>> <http://github.com/artagnon/svn-dump-fast-export.git>. Has the
>> relevant code changed much since you sent it?
Yes. I've managed to fix the deltified dump, and have now started
working on a full text dump. Due to my low familiarity with the libsvn
API, the cleanups are mixed with my code in the history; it needs a
thorough line-by-line scrubbing.
>> What is a baton?
>>
>
> The context object for a callback.
>
> You call:
>
> some_function(your_callback_function, your_baton)
>
> which then calls:
>
> your_callback_function(your_baton, other_arguments)
In general, I've found that batons are void * objects in which you can
stuff anything you like and pass around from function to function:
I've abused them quite heavily in my code by stuffing all kinds of
things into them: see fb->eb->* in my current code for an example of
this.
>> [...]
>> > + void *wrapped_edit_baton;
>> [...]
>> > + void *edit_baton;
>> > + void *wrapped_dir_baton;
>> [...]
>> > + void *edit_baton;
>> > + void *wrapped_file_baton;
>>
>> Are these opaque types necessary?
>>
>
> The convention in Subversion's code is to convert the void * to
> a concrete_baton_t * only inside the callback. If you wish to declare
> these, e.g., as
>
> debug_editor_baton_t *wrapped_baton;
>
> You can probably do that too.
The function prototypes in libsvn contain void * parameters
corresponding to batons, so I'd have to typecast explicitly to avoid
any warnings. I think Jonathan's also referring to the absence of the
"struct" keyword everywhere, as that is against Git policy.
Unfortunately, everything is typedef'ed in libsvn, and we cannot do
much about that.
>> What does this do? Is SVN_ERR for debugging?
>
> That's how we implement exception throwing in C. SVN_ERR means "if this
> returned a non-NULL svn_error_t *, then return that error to our
> caller".
>
> The other pattern does
>
> svn_error_t *err = svn_stream_printf();
>
> and then inspects err and err->apr_err to decide whether to ignore the
> error or return it (possibly wrapped).
>> Where does the output go?
>>
>
> SVN_ERR does not print anything. It may return(), though.
Embarrassingly enough, write_indent does exactly what it says it does:
It writes some spaces (or indent) to eb->out, which you'll find is
actually stderr in svn_delta__get_debug. In the cleanup, I should
probably get rid of this. As far as the error handling is concerned,
to be terse, SVN_ERR and SVN_INT_ERR are cpp macros. They are defined
as follows in svn_error.h (with line numbers from the trunk file).
Note however, that even with all this error handling, the most common
type of error I get by far is the segfault: I'll make an effort to
document the pitfalls.
00284 #define SVN_ERR(expr) \
00285 do { \
00286 svn_error_t *svn_err__temp = (expr); \
00287 if (svn_err__temp) \
00288 return svn_error_return(svn_err__temp); \
00289 } while (0)
00336 #define SVN_INT_ERR(expr) \
00337 do { \
00338 svn_error_t *svn_err__temp = (expr); \
00339 if (svn_err__temp) { \
00340 svn_handle_error2(svn_err__temp, stderr, FALSE, "svn: "); \
00341 svn_error_clear(svn_err__temp); \
00342 return EXIT_FAILURE; } \
00343 } while (0)
>> I take it these are callbacks? Is there overview documentation for
>> them somewhere?
>>
>
> svn_delta_editor_t in
> http://svn.apache.org/repos/asf/subversion/trunk/subversion/include/svn_delta.h
Yes, they are callbacks that are fired automatically by the editor. In
svn_delta.h, look at struct svn_delta_editor_t (and the corresponding
doxygen-style comments).
>> I take it that the fields of svn_delta_editor_t do not have a
>> well-defined order? Ugh.
No, they don't. I've tried to stick to the order in the struct
svn_delta_editor_t.
>> In any case, I suspect this would be easier to read rearranged a little:
>>
>> 1. declarations for callbacks
>> 2. get_debug_editor implementation
>> 3. definitions of types not needed in get_debug_editor()
>> 4. implementations of callbacks
>>
>> That way, a person reading straight through can figure out what’s
>> going on a little earlier.
Agreed. I'm still struggling to clean up the Subversion-style code. We
can probably discuss this at length on IRC?
>> What is svn_cmdline_init?
>
> A Subversion API that does some necessary initializations (e.g., calls
> apr_initialize()). See subversion/include/svn_cmdline.h for docs
> (and subversion/libsvn_subr/cmdline.c for the implementation).
These svn_cmdline functions are actually shortcuts- they do all the
initializations required for a "typical" command line SVN client. It
saves me the trouble of having to figure out what I missed
initializing: I'll be using more of them in future; to eliminate the
auth baton creation by hand, for example.
>> Is this code destined for inclusion in svn upstream, and if so, where
>> can one find the surrounding code this should fit in with?
Yes, but with a lot of style transformations. In svnsync/main.c.
Atleast that's the plan, as per the discussion on #svn-dev
-- Ram
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [WIP PATCH 1/7] Add skeleton RA svnclient
2010-06-25 11:07 ` Ramkumar Ramachandra
@ 2010-06-25 11:30 ` Daniel Shahaf
2010-06-25 15:30 ` OT: typesafe callbacks in C (Re: [WIP PATCH 1/7] Add skeleton RA svnclient) Jonathan Nieder
2010-06-25 14:45 ` [WIP PATCH 1/7] Add skeleton RA svnclient Jonathan Nieder
1 sibling, 1 reply; 18+ messages in thread
From: Daniel Shahaf @ 2010-06-25 11:30 UTC (permalink / raw)
To: Ramkumar Ramachandra
Cc: Jonathan Nieder, Git Mailing List, David Michael Barr,
Sverre Rabbelier
[-- Attachment #1: Type: TEXT/PLAIN, Size: 4032 bytes --]
Ramkumar Ramachandra wrote on Fri, 25 Jun 2010 at 14:07 -0000:
> Daniel Shahaf wrote:
> > Jonathan Nieder wrote on Fri, 25 Jun 2010 at 03:14 -0000:
> >> What is a baton?
> >>
> >
> > The context object for a callback.
> >
> > You call:
> >
> > some_function(your_callback_function, your_baton)
> >
> > which then calls:
> >
> > your_callback_function(your_baton, other_arguments)
>
> In general, I've found that batons are void * objects in which you can
> stuff anything you like and pass around from function to function:
> I've abused them quite heavily in my code by stuffing all kinds of
> things into them: see fb->eb->* in my current code for an example of
> this.
>
We do that too sometimes:
% pwd
$trunk_wc/subversion/libsvn_client/
% grep -- "->eb->" *.c | head
commit_util.c: return (*db->eb->real_editor->add_file)(path, db->real_baton,
commit_util.c: return (*db->eb->real_editor->delete_entry)(path, revision,
commit_util.c: return (*db->eb->real_editor->open_file)(path, db->real_baton,
commit_util.c: return (*fb->eb->real_editor->close_file)(fb->real_baton,
commit_util.c: return (*fb->eb->real_editor->change_file_prop)(fb->real_baton,
commit_util.c: return (*fb->eb->real_editor->apply_textdelta)(fb->real_baton,
...
> >> [...]
> >> > + void *wrapped_edit_baton;
> >> [...]
> >> > + void *edit_baton;
> >> > + void *wrapped_dir_baton;
> >> [...]
> >> > + void *edit_baton;
> >> > + void *wrapped_file_baton;
> >>
> >> Are these opaque types necessary?
> >>
> >
> > The convention in Subversion's code is to convert the void * to
> > a concrete_baton_t * only inside the callback. If you wish to declare
> > these, e.g., as
> >
> > debug_editor_baton_t *wrapped_baton;
> >
> > You can probably do that too.
>
> The function prototypes in libsvn contain void * parameters
> corresponding to batons, so I'd have to typecast explicitly to avoid
> any warnings.
By the way, a common pitfall is to mis-treat the void *baton argument as
the wrong type of baton. That is, code of the form
f(void *baton) {
foo_baton_t *fb = baton;
}
instead of
f(void *baton) {
bar_baton_t *bb = baton;
}
> I think Jonathan's also referring to the absence of the
> "struct" keyword everywhere, as that is against Git policy.
> Unfortunately, everything is typedef'ed in libsvn, and we cannot do
> much about that.
>
Usually we do
typedef struct svn_error_t svn_error_t;
so you can add the 'struct' back if you want.
> >> What does this do? Is SVN_ERR for debugging?
> >
> > That's how we implement exception throwing in C. SVN_ERR means "if this
> > returned a non-NULL svn_error_t *, then return that error to our
> > caller".
> >
> > The other pattern does
> >
> > svn_error_t *err = svn_stream_printf();
> >
> > and then inspects err and err->apr_err to decide whether to ignore the
> > error or return it (possibly wrapped).
>
> >> Where does the output go?
> >>
> >
> > SVN_ERR does not print anything. It may return(), though.
>
> Embarrassingly enough, write_indent does exactly what it says it does:
> It writes some spaces (or indent) to eb->out
To represent nesting.
> Note however, that even with all this error handling, the most common
> type of error I get by far is the segfault: I'll make an effort to
> document the pitfalls.
>
Note there are several kinds of errors that can cause a segfault.
(@Ram, you've encountered some of them already, I know.)
> >> I take it these are callbacks? Is there overview documentation for
> >> them somewhere?
> >>
> >
> > svn_delta_editor_t in
> > http://svn.apache.org/repos/asf/subversion/trunk/subversion/include/svn_delta.h
>
> Yes, they are callbacks that are fired automatically by the editor. In
> svn_delta.h, look at struct svn_delta_editor_t (and the corresponding
> doxygen-style comments).
>
The compiled doxygen docs are available on
<http://subversion.apache.org/docs/#api>. Personally I always
just read the header file directly (with :set filetype=c.doxygen).
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [WIP PATCH 1/7] Add skeleton RA svnclient
2010-06-25 11:07 ` Ramkumar Ramachandra
2010-06-25 11:30 ` Daniel Shahaf
@ 2010-06-25 14:45 ` Jonathan Nieder
1 sibling, 0 replies; 18+ messages in thread
From: Jonathan Nieder @ 2010-06-25 14:45 UTC (permalink / raw)
To: Ramkumar Ramachandra
Cc: Git Mailing List, David Michael Barr, Sverre Rabbelier,
Daniel Shahaf
Hi Ram,
Ramkumar Ramachandra wrote:
> I also highly recommend reading the API documentation and
> going through the code for answers to "why is it like THIS" questions
> as I haven't manged to clean out the Subversion style yet.
If this code is ultimately destined for the svnsync tree (as it seems
it is), it might be possible to save time by just sticking to the svn
style. I think this would be a typical place where we relax the git
style guidelines a bit.
On the other hand, during development, if you want to use some other
style (or if you want to write in Smalltalk for that matter), that’s
fine by me. I don’t want to dictate your development style. I am
only mentioning style now because I suspect it would be easier to
review code that follows a single convention (which could be
Subversion’s, or Git’s, or some well defined hybrid, or something else
entirely, or ...).
>> SVN_ERR does not print anything. It may return(), though.
Ah, so it is an exception handling mechanism.
> These svn_cmdline functions are actually shortcuts- they do all the
> initializations required for a "typical" command line SVN client. It
> saves me the trouble of having to figure out what I missed
> initializing: I'll be using more of them in future; to eliminate the
> auth baton creation by hand, for example.
Thanks again for the explanations.
Jonathan
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [WIP PATCH 1/7] Add skeleton RA svnclient
2010-06-25 9:07 ` Daniel Shahaf
2010-06-25 11:07 ` Ramkumar Ramachandra
@ 2010-06-25 13:34 ` Jonathan Nieder
1 sibling, 0 replies; 18+ messages in thread
From: Jonathan Nieder @ 2010-06-25 13:34 UTC (permalink / raw)
To: Daniel Shahaf
Cc: Ramkumar Ramachandra, Git Mailing List, David Michael Barr,
Sverre Rabbelier
Daniel Shahaf wrote:
> I don't understand. It seems that the fields here appear in the same
> order as in the definition of struct svn_delta_editor_t.
Embarrassingly, I was just confused. Thanks for the answers!
Jonathan
^ permalink raw reply [flat|nested] 18+ messages in thread
* [WIP PATCH 2/7] Add stripped dump editor
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 1/7] Add skeleton RA svnclient Ramkumar Ramachandra
@ 2010-06-23 16:22 ` Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 3/7] Import dump_node to dump what changed and cleanup whitespace Ramkumar Ramachandra
` (5 subsequent siblings)
7 siblings, 0 replies; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 16:22 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
Replace the default editor with a dump editor from libsvn_repos/dump.c
after stripping off filesystem dependencies. Currently, the dump
editor does nothing, but will dump some revision information to stdout
in future.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
Makefile | 2 +-
dump_editor.c | 365 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
dump_editor.h | 10 ++
svnclient_ra.c | 19 ++-
4 files changed, 389 insertions(+), 7 deletions(-)
create mode 100644 dump_editor.c
create mode 100644 dump_editor.h
diff --git a/Makefile b/Makefile
index c3c695c..269c406 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
svnclient_ra: *.c *.h
- $(CC) -Wall -Werror -ggdb3 -O0 -o $@ svnclient_ra.c debug_editor.c -lsvn_client-1 -I. -I/usr/local/include/subversion-1 -I/usr/include/apr-1.0
+ $(CC) -Wall -ggdb3 -O0 -o $@ svnclient_ra.c debug_editor.c dump_editor.c -lsvn_client-1 -I. -I/usr/local/include/subversion-1 -I/usr/include/apr-1.0
clean:
$(RM) svnclient_ra
diff --git a/dump_editor.c b/dump_editor.c
new file mode 100644
index 0000000..f5353b0
--- /dev/null
+++ b/dump_editor.c
@@ -0,0 +1,365 @@
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_iter.h"
+#include "svn_repos.h"
+#include "svn_string.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_time.h"
+#include "svn_checksum.h"
+#include "svn_props.h"
+
+#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
+/*----------------------------------------------------------------------*/
+/** An editor which dumps node-data in 'dumpfile format' to a file. **/
+
+/* Look, mom! No file batons! */
+
+struct edit_baton
+{
+ /* The stream to dump to: stdout */
+ svn_stream_t *stream;
+
+ svn_revnum_t current_rev;
+
+ /* reusable buffer for writing file contents */
+ char buffer[SVN__STREAM_CHUNK_SIZE];
+ apr_size_t bufsize;
+};
+
+struct dir_baton
+{
+ struct edit_baton *edit_baton;
+ 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 *path;
+
+ /* the comparison path and revision of this directory. if both of
+ these are valid, use them as a source against which to compare
+ the directory instead of the default comparison source of PATH in
+ the previous revision. */
+ const char *cmp_path;
+ svn_revnum_t cmp_rev;
+
+ /* hash of paths that need to be deleted, though some -might- be
+ replaced. maps const char * paths to this dir_baton. (they're
+ full paths, because that's what the editor driver gives us. but
+ really, they're all within this directory.) */
+ apr_hash_t *deleted_entries;
+
+ /* pool to be used for deleting the hash items */
+ apr_pool_t *pool;
+};
+
+
+/* Make a directory baton to represent the directory was path
+ (relative to EDIT_BATON's path) is PATH.
+
+ CMP_PATH/CMP_REV are the path/revision against which this directory
+ should be compared for changes. If either is omitted (NULL for the
+ path, SVN_INVALID_REVNUM for the rev), just compare this directory
+ PATH against itself in the previous revision.
+
+ 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
+ indicated if this directory is newly added in this revision.
+ Perform all allocations in POOL. */
+struct dir_baton *
+make_dir_baton(const char *path,
+ const char *cmp_path,
+ svn_revnum_t cmp_rev,
+ void *edit_baton,
+ void *parent_dir_baton,
+ svn_boolean_t added,
+ apr_pool_t *pool)
+{
+ struct 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 *full_path;
+
+ /* A path relative to nothing? I don't think so. */
+ SVN_ERR_ASSERT_NO_RETURN(!path || pb);
+
+ /* Construct the full path of this node. */
+ if (pb)
+ full_path = svn_path_join("/", path, pool);
+ else
+ full_path = apr_pstrdup(pool, "/");
+
+ /* Remove leading slashes from copyfrom paths. */
+ if (cmp_path)
+ cmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path);
+
+ new_db->edit_baton = eb;
+ new_db->parent_dir_baton = pb;
+ new_db->path = full_path;
+ new_db->cmp_path = cmp_path ? apr_pstrdup(pool, cmp_path) : NULL;
+ new_db->cmp_rev = cmp_rev;
+ new_db->added = added;
+ new_db->written_out = FALSE;
+ new_db->deleted_entries = apr_hash_make(pool);
+ new_db->pool = pool;
+
+ return new_db;
+}
+
+
+svn_error_t *
+open_root(void *edit_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **root_baton)
+{
+ *root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
+ edit_baton, NULL, FALSE, pool);
+ return SVN_NO_ERROR;
+}
+
+
+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(pb->pool, path);
+
+ /* remember this path needs to be deleted. */
+ apr_hash_set(pb->deleted_entries, mypath, APR_HASH_KEY_STRING, pb);
+
+ return SVN_NO_ERROR;
+}
+
+
+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;
+ struct edit_baton *eb = pb->edit_baton;
+ void *val;
+ svn_boolean_t is_copy = FALSE;
+ struct dir_baton *new_db
+ = make_dir_baton(path, copyfrom_path, copyfrom_rev, eb, pb, 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(dump_node(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;
+}
+
+
+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 edit_baton *eb = pb->edit_baton;
+ struct dir_baton *new_db;
+ const char *cmp_path = NULL;
+ svn_revnum_t cmp_rev = SVN_INVALID_REVNUM;
+
+ /* If the parent directory has explicit comparison path and rev,
+ record the same for this one. */
+ if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev))
+ {
+ cmp_path = svn_path_join(pb->cmp_path,
+ svn_dirent_basename(path, pool), pool);
+ cmp_rev = pb->cmp_rev;
+ }
+
+ new_db = make_dir_baton(path, cmp_path, cmp_rev, eb, pb, FALSE, pool);
+ *child_baton = new_db;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+close_directory(void *dir_baton,
+ apr_pool_t *pool)
+{
+ struct dir_baton *db = dir_baton;
+ struct edit_baton *eb = db->edit_baton;
+ apr_hash_index_t *hi;
+ apr_pool_t *subpool = svn_pool_create(pool);
+
+ 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(subpool);
+
+ /* By sending 'svn_node_unknown', the Node-kind: header simply won't
+ be written out. No big deal at all, really. The loader
+ shouldn't care. */
+ /* SVN_ERR(dump_node(eb, path, */
+ /* svn_node_unknown, svn_node_action_delete, */
+ /* FALSE, NULL, SVN_INVALID_REVNUM, subpool)); */
+ }
+
+ svn_pool_destroy(subpool);
+ return SVN_NO_ERROR;
+}
+
+
+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;
+ struct edit_baton *eb = pb->edit_baton;
+ void *val;
+ svn_boolean_t is_copy = FALSE;
+
+ /* 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(dump_node(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);
+
+ *file_baton = NULL; /* muhahahaha */
+ return SVN_NO_ERROR;
+}
+
+
+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;
+ struct edit_baton *eb = pb->edit_baton;
+ const char *cmp_path = NULL;
+ svn_revnum_t cmp_rev = SVN_INVALID_REVNUM;
+
+ /* If the parent directory has explicit comparison path and rev,
+ record the same for this one. */
+ if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev))
+ {
+ cmp_path = svn_path_join(pb->cmp_path,
+ svn_dirent_basename(path, pool), pool);
+ cmp_rev = pb->cmp_rev;
+ }
+
+ /* SVN_ERR(dump_node(eb, path, */
+ /* svn_node_file, svn_node_action_change, */
+ /* FALSE, cmp_path, cmp_rev, pool)); */
+
+ *file_baton = NULL; /* muhahahaha again */
+ return SVN_NO_ERROR;
+}
+
+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;
+ struct edit_baton *eb = db->edit_baton;
+
+ /* 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)
+ {
+ /* SVN_ERR(dump_node(eb, db->path, */
+ /* svn_node_dir, svn_node_action_change, */
+ /* FALSE, db->cmp_path, db->cmp_rev, pool)); */
+ db->written_out = TRUE;
+ }
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+get_dump_editor(const svn_delta_editor_t **editor,
+ void **edit_baton,
+ svn_revnum_t to_rev,
+ apr_pool_t *pool)
+{
+ /* Allocate an edit baton to be stored in every directory baton.
+ Set it up for the directory baton we create here, which is the
+ root baton. */
+ struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
+ svn_delta_editor_t *dump_editor = svn_delta_default_editor(pool);
+
+ /* Set up the edit baton. */
+ svn_stream_for_stdout(&(eb->stream), pool);
+ eb->bufsize = sizeof(eb->buffer);
+ eb->current_rev = to_rev;
+
+
+ /* Set up the editor. */
+ dump_editor->open_root = open_root;
+ dump_editor->delete_entry = delete_entry;
+ dump_editor->add_directory = add_directory;
+ dump_editor->open_directory = open_directory;
+ dump_editor->close_directory = close_directory;
+ dump_editor->change_dir_prop = change_dir_prop;
+ dump_editor->add_file = add_file;
+ dump_editor->open_file = open_file;
+
+ *edit_baton = eb;
+ *editor = dump_editor;
+
+ return SVN_NO_ERROR;
+}
diff --git a/dump_editor.h b/dump_editor.h
new file mode 100644
index 0000000..5e84223
--- /dev/null
+++ b/dump_editor.h
@@ -0,0 +1,10 @@
+#include "svn_pools.h"
+#include "svn_cmdline.h"
+#include "svn_client.h"
+#include "svn_ra.h"
+
+svn_error_t *
+get_dump_editor(const svn_delta_editor_t **editor,
+ void **edit_baton,
+ svn_revnum_t to_rev,
+ apr_pool_t *pool);
diff --git a/svnclient_ra.c b/svnclient_ra.c
index 2ed04af..24d99cb 100644
--- a/svnclient_ra.c
+++ b/svnclient_ra.c
@@ -4,6 +4,7 @@
#include "svn_ra.h"
#include "debug_editor.h"
+#include "dump_editor.h"
static apr_pool_t *pool = NULL;
static svn_client_ctx_t *ctx = NULL;
@@ -92,16 +93,22 @@ svn_error_t *open_connection(const char *url)
svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_revision)
{
+ svn_delta_editor_t *dump_editor, *debug_editor;
+ void *debug_baton, *dump_baton;
+
svn_revnum_t latest_revision;
- svn_delta_editor_t *editor, *debug_editor;
- replay_baton_t *replay_baton = apr_palloc(pool, sizeof(replay_baton_t));
- void *debug_baton;
SVN_ERR(svn_ra_get_latest_revnum(session, &latest_revision, pool));
printf("%ld\n", latest_revision);
- editor = svn_delta_default_editor(pool);
+
+ SVN_ERR(get_dump_editor((const svn_delta_editor_t **)&dump_editor,
+ &dump_baton, end_revision, pool));
+
SVN_ERR(svn_delta__get_debug_editor((const svn_delta_editor_t **)&debug_editor,
- &debug_baton, editor,
- NULL, pool));
+ &debug_baton,
+ (const svn_delta_editor_t *)dump_editor,
+ dump_baton, pool));
+
+ replay_baton_t *replay_baton = apr_palloc(pool, sizeof(replay_baton_t));
replay_baton->editor = debug_editor;
replay_baton->baton = debug_baton;
SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [WIP PATCH 3/7] Import dump_node to dump what changed and cleanup whitespace
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 1/7] Add skeleton RA svnclient Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 2/7] Add stripped dump editor Ramkumar Ramachandra
@ 2010-06-23 16:22 ` Ramkumar Ramachandra
2010-06-23 17:05 ` Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 4/7] Replace deprecated svn_path_join Ramkumar Ramachandra
` (4 subsequent siblings)
7 siblings, 1 reply; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 16:22 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
Import dump_node from dump.c after stripping it off filesystem backing
to dump which files/ directories were added or removed without
actually dumping the delta. Modify svnclient_ra to use just the dump
editor, and not the debug editor. Also cleanup whitespace to conform
to Git style. Add LICENSE file.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
LICENSE | 14 +++
dump_editor.c | 344 ++++++++++++++++++++++++++++++++++++++------------------
svnclient_ra.c | 6 +-
3 files changed, 251 insertions(+), 113 deletions(-)
create mode 100644 LICENSE
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c8f39ff
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,14 @@
+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.
diff --git a/dump_editor.c b/dump_editor.c
index f5353b0..ba0630f 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -1,3 +1,7 @@
+/* Licensed under Apache license.
+ * See LICENSE for details.
+ */
+
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_iter.h"
@@ -10,13 +14,8 @@
#include "svn_props.h"
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
-/*----------------------------------------------------------------------*/
-/** An editor which dumps node-data in 'dumpfile format' to a file. **/
-
-/* Look, mom! No file batons! */
-struct edit_baton
-{
+struct edit_baton {
/* The stream to dump to: stdout */
svn_stream_t *stream;
@@ -27,8 +26,7 @@ struct edit_baton
apr_size_t bufsize;
};
-struct dir_baton
-{
+struct dir_baton {
struct edit_baton *edit_baton;
struct dir_baton *parent_dir_baton;
@@ -71,20 +69,19 @@ struct dir_baton
or NULL if this is the top-level directory of the edit. ADDED
indicated if this directory is newly added in this revision.
Perform all allocations in POOL. */
-struct dir_baton *
-make_dir_baton(const char *path,
- const char *cmp_path,
- svn_revnum_t cmp_rev,
- void *edit_baton,
- void *parent_dir_baton,
- svn_boolean_t added,
- apr_pool_t *pool)
-{
+struct dir_baton *make_dir_baton(const char *path,
+ const char *cmp_path,
+ svn_revnum_t cmp_rev,
+ void *edit_baton,
+ void *parent_dir_baton,
+ svn_boolean_t added,
+ apr_pool_t *pool) {
struct 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 *full_path;
+
/* A path relative to nothing? I don't think so. */
SVN_ERR_ASSERT_NO_RETURN(!path || pb);
@@ -111,24 +108,170 @@ make_dir_baton(const char *path,
return new_db;
}
+static svn_error_t *dump_node(struct 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 *cmp_path,
+ svn_revnum_t cmp_rev,
+ apr_pool_t *pool)
+{
+ apr_size_t len;
+ svn_boolean_t must_dump_text = TRUE, must_dump_props = TRUE;
+ const char *compare_path = path;
+ svn_revnum_t compare_rev = eb->current_rev - 1;
+
+ /* Write out metadata headers for this file node. */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
+ (*path == '/') ? path + 1 : path));
+ 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"));
+
+ /* Remove leading slashes from copyfrom paths. */
+ if (cmp_path)
+ cmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path);
-svn_error_t *
-open_root(void *edit_baton,
- svn_revnum_t base_revision,
- apr_pool_t *pool,
- void **root_baton)
+ /* Validate the comparison path/rev. */
+ if (ARE_VALID_COPY_ARGS(cmp_path, cmp_rev)) {
+ compare_path = cmp_path;
+ compare_rev = cmp_rev;
+ }
+
+ switch (action) {
+ /* Appropriately handle the four svn_node_action actions */
+
+ case svn_node_action_change:
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_NODE_ACTION
+ ": change\n"));
+
+ /* either the text or props changed, or possibly both. */
+ /* SVN_ERR(svn_props_changed(&must_dump_props, */
+ /* compare_path, path, pool)); */
+ if (kind == svn_node_file)
+ /* SVN_ERR(svn_contents_changed(&must_dump_text, */
+ /* compare_path, path, pool)); */
+ break;
+
+ case svn_node_action_replace:
+ if (!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"));
+
+ /* definitely need to dump all content for a replace. */
+ if (kind == svn_node_file)
+ must_dump_text = TRUE;
+ must_dump_props = TRUE;
+ break;
+ }
+ /* more complex: delete original, then add-with-history. */
+
+ /* 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,
+ is_copy, compare_path, compare_rev, pool));
+
+ /* we can leave this routine quietly now, don't need to dump
+ any content; that was already done in the second record. */
+ must_dump_text = FALSE;
+ must_dump_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. */
+ must_dump_text = FALSE;
+ must_dump_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) {
+ /* Dump all contents for a simple 'add'. */
+ if (kind == svn_node_file)
+ must_dump_text = TRUE;
+ must_dump_props = 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",
+ cmp_rev, cmp_path));
+
+ /* Need to decide if the copied node had any extra textual or
+ property mods as well. */
+ /* SVN_ERR(svn_fs_props_changed(&must_dump_props, */
+ /* compare_path, path, pool)); */
+ /* if (kind == svn_node_file) */
+ /* { */
+ /* svn_checksum_t *checksum; */
+ /* const char *hex_digest; */
+ /* SVN_ERR(svn_fs_contents_changed(&must_dump_text, */
+ /* compare_root, compare_path, */
+ /* eb->fs_root, path, pool)); */
+
+ /* SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, */
+ /* compare_root, compare_path, */
+ /* TRUE, pool)); */
+ /* hex_digest = svn_checksum_to_cstring(checksum, pool); */
+ /* if (hex_digest) */
+ /* SVN_ERR(svn_stream_printf(eb->stream, pool, */
+ /* SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_MD5 */
+ /* ": %s\n", hex_digest)); */
+
+ /* SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1, */
+ /* compare_root, compare_path, */
+ /* TRUE, pool)); */
+ /* hex_digest = svn_checksum_to_cstring(checksum, pool); */
+ /* if (hex_digest) */
+ /* SVN_ERR(svn_stream_printf(eb->stream, pool, */
+ /* SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_SHA1 */
+ /* ": %s\n", hex_digest)); */
+ /* } */
+ break;
+ }
+ if (!must_dump_text && !must_dump_props) {
+ len = 2;
+ return svn_stream_write(eb->stream, "\n\n", &len); /* ### needed? */
+ }
+ return SVN_NO_ERROR;
+}
+svn_error_t *open_root(void *edit_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **root_baton)
{
*root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
edit_baton, NULL, FALSE, pool);
return SVN_NO_ERROR;
}
-
-svn_error_t *
-delete_entry(const char *path,
- svn_revnum_t revision,
- void *parent_baton,
- apr_pool_t *pool)
+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(pb->pool, path);
@@ -139,14 +282,12 @@ delete_entry(const char *path,
return SVN_NO_ERROR;
}
-
-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)
+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;
struct edit_baton *eb = pb->edit_baton;
@@ -162,13 +303,13 @@ add_directory(const char *path,
is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
/* Dump the node. */
- /* SVN_ERR(dump_node(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)); */
+ SVN_ERR(dump_node(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. */
@@ -180,13 +321,11 @@ add_directory(const char *path,
return SVN_NO_ERROR;
}
-
-svn_error_t *
-open_directory(const char *path,
- void *parent_baton,
- svn_revnum_t base_revision,
- apr_pool_t *pool,
- void **child_baton)
+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 edit_baton *eb = pb->edit_baton;
@@ -196,8 +335,7 @@ 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->cmp_path, pb->cmp_rev))
- {
+ if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev)) {
cmp_path = svn_path_join(pb->cmp_path,
svn_dirent_basename(path, pool), pool);
cmp_rev = pb->cmp_rev;
@@ -208,10 +346,8 @@ open_directory(const char *path,
return SVN_NO_ERROR;
}
-
-svn_error_t *
-close_directory(void *dir_baton,
- apr_pool_t *pool)
+svn_error_t *close_directory(void *dir_baton,
+ apr_pool_t *pool)
{
struct dir_baton *db = dir_baton;
struct edit_baton *eb = db->edit_baton;
@@ -220,8 +356,7 @@ close_directory(void *dir_baton,
for (hi = apr_hash_first(pool, db->deleted_entries);
hi;
- hi = apr_hash_next(hi))
- {
+ hi = apr_hash_next(hi)) {
const void *key;
const char *path;
apr_hash_this(hi, &key, NULL, NULL);
@@ -232,23 +367,21 @@ close_directory(void *dir_baton,
/* By sending 'svn_node_unknown', the Node-kind: header simply won't
be written out. No big deal at all, really. The loader
shouldn't care. */
- /* SVN_ERR(dump_node(eb, path, */
- /* svn_node_unknown, svn_node_action_delete, */
- /* FALSE, NULL, SVN_INVALID_REVNUM, subpool)); */
+ SVN_ERR(dump_node(eb, path,
+ svn_node_unknown, svn_node_action_delete,
+ FALSE, NULL, SVN_INVALID_REVNUM, subpool));
}
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
-
-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)
+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;
struct edit_baton *eb = pb->edit_baton;
@@ -262,29 +395,29 @@ add_file(const char *path,
is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
/* Dump the node. */
- /* SVN_ERR(dump_node(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)); */
+ SVN_ERR(dump_node(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);
- *file_baton = NULL; /* muhahahaha */
+ /* TODO: Store the delta in file_baton */
+ *file_baton = NULL;
return SVN_NO_ERROR;
}
-svn_error_t *
-open_file(const char *path,
- void *parent_baton,
- svn_revnum_t ancestor_revision,
- apr_pool_t *pool,
- void **file_baton)
+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;
struct edit_baton *eb = pb->edit_baton;
@@ -293,26 +426,25 @@ open_file(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->cmp_path, pb->cmp_rev))
- {
+ if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev)) {
cmp_path = svn_path_join(pb->cmp_path,
svn_dirent_basename(path, pool), pool);
cmp_rev = pb->cmp_rev;
}
- /* SVN_ERR(dump_node(eb, path, */
- /* svn_node_file, svn_node_action_change, */
- /* FALSE, cmp_path, cmp_rev, pool)); */
+ SVN_ERR(dump_node(eb, path,
+ svn_node_file, svn_node_action_change,
+ FALSE, cmp_path, cmp_rev, pool));
- *file_baton = NULL; /* muhahahaha again */
+ /* TODO: Store the delta in file_baton */
+ *file_baton = NULL;
return SVN_NO_ERROR;
}
-svn_error_t *
-change_dir_prop(void *parent_baton,
- const char *name,
- const svn_string_t *value,
- apr_pool_t *pool)
+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;
struct edit_baton *eb = db->edit_baton;
@@ -320,35 +452,27 @@ change_dir_prop(void *parent_baton,
/* 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)
- {
- /* SVN_ERR(dump_node(eb, db->path, */
- /* svn_node_dir, svn_node_action_change, */
- /* FALSE, db->cmp_path, db->cmp_rev, pool)); */
+ if (! db->written_out) {
+ SVN_ERR(dump_node(eb, db->path,
+ svn_node_dir, svn_node_action_change,
+ FALSE, db->cmp_path, db->cmp_rev, pool));
db->written_out = TRUE;
}
return SVN_NO_ERROR;
}
-svn_error_t *
-get_dump_editor(const svn_delta_editor_t **editor,
- void **edit_baton,
- svn_revnum_t to_rev,
- apr_pool_t *pool)
+svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
+ void **edit_baton,
+ svn_revnum_t to_rev,
+ apr_pool_t *pool)
{
- /* Allocate an edit baton to be stored in every directory baton.
- Set it up for the directory baton we create here, which is the
- root baton. */
struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
svn_delta_editor_t *dump_editor = svn_delta_default_editor(pool);
- /* Set up the edit baton. */
svn_stream_for_stdout(&(eb->stream), pool);
eb->bufsize = sizeof(eb->buffer);
eb->current_rev = to_rev;
-
- /* Set up the editor. */
dump_editor->open_root = open_root;
dump_editor->delete_entry = delete_entry;
dump_editor->add_directory = add_directory;
diff --git a/svnclient_ra.c b/svnclient_ra.c
index 24d99cb..0b9e002 100644
--- a/svnclient_ra.c
+++ b/svnclient_ra.c
@@ -109,8 +109,8 @@ svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_revision
dump_baton, pool));
replay_baton_t *replay_baton = apr_palloc(pool, sizeof(replay_baton_t));
- replay_baton->editor = debug_editor;
- replay_baton->baton = debug_baton;
+ replay_baton->editor = dump_editor;
+ replay_baton->baton = dump_baton;
SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
0, TRUE, replay_revstart, replay_revend,
replay_baton, pool));
@@ -125,7 +125,7 @@ void close_connection()
int main()
{
const char url[] = "http://svn.apache.org/repos/asf";
- svn_revnum_t start_revision = 1, end_revision = 5;
+ svn_revnum_t start_revision = 1, end_revision = 50;
if (svn_cmdline_init ("svnclient_ra", stderr) != EXIT_SUCCESS)
return 1;
pool = svn_pool_create(NULL);
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [WIP PATCH 3/7] Import dump_node to dump what changed and cleanup whitespace
2010-06-23 16:22 ` [WIP PATCH 3/7] Import dump_node to dump what changed and cleanup whitespace Ramkumar Ramachandra
@ 2010-06-23 17:05 ` Ramkumar Ramachandra
0 siblings, 0 replies; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 17:05 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
Hi,
Ramkumar Ramachandra wrote:
> +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
Daniel pointed out that my code isn't licensed to the ASF before it's
merged back into Subversion; the dump.c I've taken directly from the
Subversion trunk is though. I'll find out the exact semantics and
correct this.
-- Ram
^ permalink raw reply [flat|nested] 18+ messages in thread
* [WIP PATCH 4/7] Replace deprecated svn_path_join
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
` (2 preceding siblings ...)
2010-06-23 16:22 ` [WIP PATCH 3/7] Import dump_node to dump what changed and cleanup whitespace Ramkumar Ramachandra
@ 2010-06-23 16:22 ` Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 5/7] Trigger dump_node in change_dir_prop Ramkumar Ramachandra
` (3 subsequent siblings)
7 siblings, 0 replies; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 16:22 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
Strip the deprecated svn_path_join API, using svn_path_compose
instead. Re-add -Werror to the Makefile.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
Makefile | 2 +-
dump_editor.c | 21 ++++++++++++++-------
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/Makefile b/Makefile
index 269c406..cf7fef7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
svnclient_ra: *.c *.h
- $(CC) -Wall -ggdb3 -O0 -o $@ svnclient_ra.c debug_editor.c dump_editor.c -lsvn_client-1 -I. -I/usr/local/include/subversion-1 -I/usr/include/apr-1.0
+ $(CC) -Wall -Werror -ggdb3 -O0 -o $@ svnclient_ra.c debug_editor.c dump_editor.c -lsvn_client-1 -I. -I/usr/local/include/subversion-1 -I/usr/include/apr-1.0
clean:
$(RM) svnclient_ra
diff --git a/dump_editor.c b/dump_editor.c
index ba0630f..00c838a 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -80,14 +80,17 @@ struct dir_baton *make_dir_baton(const char *path,
struct dir_baton *pb = parent_dir_baton;
struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
const char *full_path;
-
+ apr_array_header_t *compose_path = apr_array_make(pool, 2, sizeof(const char *));
/* A path relative to nothing? I don't think so. */
SVN_ERR_ASSERT_NO_RETURN(!path || pb);
/* Construct the full path of this node. */
- if (pb)
- full_path = svn_path_join("/", path, pool);
+ if (pb) {
+ APR_ARRAY_PUSH(compose_path, const char *) = "/";
+ APR_ARRAY_PUSH(compose_path, const char *) = path;
+ full_path = svn_path_compose(compose_path, pool);
+ }
else
full_path = apr_pstrdup(pool, "/");
@@ -332,12 +335,14 @@ svn_error_t *open_directory(const char *path,
struct dir_baton *new_db;
const char *cmp_path = NULL;
svn_revnum_t cmp_rev = SVN_INVALID_REVNUM;
+ apr_array_header_t *compose_path = apr_array_make(pool, 2, sizeof(const char *));
/* If the parent directory has explicit comparison path and rev,
record the same for this one. */
if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev)) {
- cmp_path = svn_path_join(pb->cmp_path,
- svn_dirent_basename(path, pool), pool);
+ APR_ARRAY_PUSH(compose_path, const char *) = pb->cmp_path;
+ APR_ARRAY_PUSH(compose_path, const char *) = svn_dirent_basename(path, pool);
+ cmp_path = svn_path_compose(compose_path, pool);
cmp_rev = pb->cmp_rev;
}
@@ -424,11 +429,13 @@ svn_error_t *open_file(const char *path,
const char *cmp_path = NULL;
svn_revnum_t cmp_rev = SVN_INVALID_REVNUM;
+ apr_array_header_t *compose_path = apr_array_make(pool, 2, sizeof(const char *));
/* If the parent directory has explicit comparison path and rev,
record the same for this one. */
if (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev)) {
- cmp_path = svn_path_join(pb->cmp_path,
- svn_dirent_basename(path, pool), pool);
+ APR_ARRAY_PUSH(compose_path, const char *) = pb->cmp_path;
+ APR_ARRAY_PUSH(compose_path, const char *) = svn_dirent_basename(path, pool);
+ cmp_path = svn_path_compose(compose_path, pool);
cmp_rev = pb->cmp_rev;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [WIP PATCH 5/7] Trigger dump_node in change_dir_prop
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
` (3 preceding siblings ...)
2010-06-23 16:22 ` [WIP PATCH 4/7] Replace deprecated svn_path_join Ramkumar Ramachandra
@ 2010-06-23 16:22 ` Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 6/7] Add file_baton and trigger dump_node in change_file_prop Ramkumar Ramachandra
` (2 subsequent siblings)
7 siblings, 0 replies; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 16:22 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
Trigger dump_node to dump property length in change_dir_prop. Use the
edit_baton to store the changed property before dumping it.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
dump_editor.c | 111 +++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 89 insertions(+), 22 deletions(-)
diff --git a/dump_editor.c b/dump_editor.c
index 00c838a..a80d711 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -15,12 +15,22 @@
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
+static svn_boolean_t must_dump_text = FALSE, must_dump_props = FALSE;
+static svn_boolean_t text_changed = FALSE, props_changed = FALSE;
+
struct edit_baton {
/* The stream to dump to: stdout */
svn_stream_t *stream;
svn_revnum_t current_rev;
+ /* Store the properties that changed */
+ apr_hash_t *properties;
+ apr_hash_t *del_properties; /* Value is always 0x1 */
+
+ /* Store the text delta */
+ const char *delta_text;
+
/* reusable buffer for writing file contents */
char buffer[SVN__STREAM_CHUNK_SIZE];
apr_size_t bufsize;
@@ -56,6 +66,41 @@ struct dir_baton {
apr_pool_t *pool;
};
+static void write_hash_to_stringbuf(apr_hash_t *hash,
+ svn_stringbuf_t **strbuf,
+ apr_pool_t *pool) {
+ apr_hash_index_t *this;
+ *strbuf = svn_stringbuf_create("", pool);
+
+ for (this = apr_hash_first(pool, hash); this; this = apr_hash_next(this))
+ {
+ const void *key;
+ void *val;
+ apr_ssize_t keylen;
+ svn_string_t *value;
+
+ /* Get this key and val. */
+ apr_hash_this(this, &key, &keylen, &val);
+ value = val;
+
+ /* Output name length, then name. */
+ svn_stringbuf_appendcstr(*strbuf,
+ apr_psprintf(pool, "K %" APR_SSIZE_T_FMT "\n",
+ keylen));
+
+ svn_stringbuf_appendbytes(*strbuf, (const char *) key, keylen);
+ svn_stringbuf_appendbytes(*strbuf, "\n", 1);
+
+ /* Output value length, then value. */
+ svn_stringbuf_appendcstr(*strbuf,
+ apr_psprintf(pool, "V %" APR_SIZE_T_FMT "\n",
+ value->len));
+
+ svn_stringbuf_appendbytes(*strbuf, value->data, value->len);
+ svn_stringbuf_appendbytes(*strbuf, "\n", 1);
+ }
+ svn_stringbuf_appendbytes(*strbuf, "PROPS-END\n", 10);
+}
/* Make a directory baton to represent the directory was path
(relative to EDIT_BATON's path) is PATH.
@@ -120,10 +165,11 @@ static svn_error_t *dump_node(struct edit_baton *eb,
svn_revnum_t cmp_rev,
apr_pool_t *pool)
{
- apr_size_t len;
- svn_boolean_t must_dump_text = TRUE, must_dump_props = TRUE;
+ apr_size_t len, proplen;
const char *compare_path = path;
svn_revnum_t compare_rev = eb->current_rev - 1;
+ svn_stringbuf_t *propstring;
+ svn_filesize_t content_length = 0;
/* Write out metadata headers for this file node. */
SVN_ERR(svn_stream_printf(eb->stream, pool,
@@ -153,13 +199,10 @@ static svn_error_t *dump_node(struct edit_baton *eb,
SVN_ERR(svn_stream_printf(eb->stream, pool,
SVN_REPOS_DUMPFILE_NODE_ACTION
": change\n"));
-
- /* either the text or props changed, or possibly both. */
- /* SVN_ERR(svn_props_changed(&must_dump_props, */
- /* compare_path, path, pool)); */
+
+ must_dump_props = props_changed;
if (kind == svn_node_file)
- /* SVN_ERR(svn_contents_changed(&must_dump_text, */
- /* compare_path, path, pool)); */
+ must_dump_text = text_changed;
break;
case svn_node_action_replace:
@@ -223,28 +266,24 @@ static svn_error_t *dump_node(struct edit_baton *eb,
": %s\n",
cmp_rev, cmp_path));
- /* Need to decide if the copied node had any extra textual or
- property mods as well. */
- /* SVN_ERR(svn_fs_props_changed(&must_dump_props, */
- /* compare_path, path, pool)); */
- /* if (kind == svn_node_file) */
- /* { */
+ must_dump_props = props_changed;
+ /* if (kind == svn_node_file) { */
/* svn_checksum_t *checksum; */
/* const char *hex_digest; */
- /* SVN_ERR(svn_fs_contents_changed(&must_dump_text, */
- /* compare_root, compare_path, */
- /* eb->fs_root, path, pool)); */
+ /* must_dump_text = text_changed; */
- /* SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, */
- /* compare_root, compare_path, */
- /* TRUE, pool)); */
+ /* /\* MD5 checksum *\/ */
+ /* SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, */
+ /* compare_root, compare_path, */
+ /* TRUE, pool)); */
/* hex_digest = svn_checksum_to_cstring(checksum, pool); */
/* if (hex_digest) */
/* SVN_ERR(svn_stream_printf(eb->stream, pool, */
/* SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_MD5 */
/* ": %s\n", hex_digest)); */
- /* SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1, */
+ /* /\* SHA1 checksum *\/ */
+ /* SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1, */
/* compare_root, compare_path, */
/* TRUE, pool)); */
/* hex_digest = svn_checksum_to_cstring(checksum, pool); */
@@ -257,7 +296,23 @@ static svn_error_t *dump_node(struct edit_baton *eb,
}
if (!must_dump_text && !must_dump_props) {
len = 2;
- return svn_stream_write(eb->stream, "\n\n", &len); /* ### needed? */
+ return svn_stream_write(eb->stream, "\n\n", &len);
+ }
+
+ /* If we are supposed to dump properties, write out a property
+ length header and generate a stringbuf that contains those
+ property values here. */
+ if (must_dump_props) {
+ write_hash_to_stringbuf(eb->properties, &propstring, pool);
+ proplen = propstring->len;
+ content_length += proplen;
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
+ ": %" APR_SIZE_T_FMT "\n", proplen));
+ }
+ if (must_dump_text && (kind == svn_node_file)) {
+ /* svn_stream_t *contents; */
+ ;
}
return SVN_NO_ERROR;
}
@@ -456,6 +511,15 @@ svn_error_t *change_dir_prop(void *parent_baton,
struct dir_baton *db = parent_baton;
struct edit_baton *eb = db->edit_baton;
+ if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+ return SVN_NO_ERROR;
+
+ value ? apr_hash_set(eb->properties, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, svn_string_dup(value, pool)) :
+ apr_hash_set(eb->del_properties, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, (void *)0x1);
+ props_changed = TRUE;
+
/* 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. */
@@ -479,6 +543,9 @@ svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
svn_stream_for_stdout(&(eb->stream), pool);
eb->bufsize = sizeof(eb->buffer);
eb->current_rev = to_rev;
+ eb->properties = apr_hash_make(pool);
+ eb->del_properties = apr_hash_make(pool);
+ eb->delta_text = apr_pcalloc(pool, sizeof(const char *));
dump_editor->open_root = open_root;
dump_editor->delete_entry = delete_entry;
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [WIP PATCH 6/7] Add file_baton and trigger dump_node in change_file_prop
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
` (4 preceding siblings ...)
2010-06-23 16:22 ` [WIP PATCH 5/7] Trigger dump_node in change_dir_prop Ramkumar Ramachandra
@ 2010-06-23 16:22 ` Ramkumar Ramachandra
2010-06-23 16:22 ` [WIP PATCH 7/7] Dump the text delta Ramkumar Ramachandra
2010-06-23 17:18 ` [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
7 siblings, 0 replies; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 16:22 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
Add a file_baton structure, and fill it in in open_file and add_file
functions. It is to be used by apply_textdelta and change_file_prop
functions. Trigger dump_node in change_file_prop. Dump the actual
properties along with the property lengths.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
dump_editor.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 89 insertions(+), 11 deletions(-)
diff --git a/dump_editor.c b/dump_editor.c
index a80d711..7bd00a4 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -15,7 +15,6 @@
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
-static svn_boolean_t must_dump_text = FALSE, must_dump_props = FALSE;
static svn_boolean_t text_changed = FALSE, props_changed = FALSE;
struct edit_baton {
@@ -66,9 +65,16 @@ struct dir_baton {
apr_pool_t *pool;
};
+struct file_baton {
+ /* Store the path of the file */
+ const char *path;
+ struct edit_baton *eb;
+};
+
static void write_hash_to_stringbuf(apr_hash_t *hash,
svn_stringbuf_t **strbuf,
- apr_pool_t *pool) {
+ apr_pool_t *pool)
+{
apr_hash_index_t *this;
*strbuf = svn_stringbuf_create("", pool);
@@ -120,7 +126,8 @@ struct dir_baton *make_dir_baton(const char *path,
void *edit_baton,
void *parent_dir_baton,
svn_boolean_t added,
- apr_pool_t *pool) {
+ apr_pool_t *pool)
+{
struct edit_baton *eb = edit_baton;
struct dir_baton *pb = parent_dir_baton;
struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
@@ -156,6 +163,18 @@ struct dir_baton *make_dir_baton(const char *path,
return new_db;
}
+struct file_baton *make_file_baton(struct edit_baton *eb,
+ const char *path,
+ apr_pool_t *pool)
+{
+ struct file_baton *new_fb = apr_pcalloc(pool, sizeof(struct file_baton));
+ new_fb->path = apr_pcalloc(pool, sizeof(const char *));
+ new_fb->path = path;
+ new_fb->eb = eb;
+
+ return new_fb;
+}
+
static svn_error_t *dump_node(struct edit_baton *eb,
const char *path, /* an absolute path. */
svn_node_kind_t kind,
@@ -170,6 +189,7 @@ static svn_error_t *dump_node(struct edit_baton *eb,
svn_revnum_t compare_rev = eb->current_rev - 1;
svn_stringbuf_t *propstring;
svn_filesize_t content_length = 0;
+ svn_boolean_t must_dump_text = FALSE, must_dump_props = FALSE;
/* Write out metadata headers for this file node. */
SVN_ERR(svn_stream_printf(eb->stream, pool,
@@ -310,10 +330,44 @@ static svn_error_t *dump_node(struct edit_baton *eb,
SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
": %" APR_SIZE_T_FMT "\n", proplen));
}
+
+ /* If we are supposed to dump text, write out a text length header
+ here, and an MD5 checksum (if available). */
if (must_dump_text && (kind == svn_node_file)) {
- /* svn_stream_t *contents; */
;
}
+
+ /* 'Content-length:' is the last header before we dump the content,
+ and is the sum of the text and prop contents lengths. We write
+ this only for the benefit of non-Subversion RFC-822 parsers. */
+ SVN_ERR(svn_stream_printf(eb->stream, pool,
+ SVN_REPOS_DUMPFILE_CONTENT_LENGTH
+ ": %" SVN_FILESIZE_T_FMT "\n\n",
+ content_length));
+
+ /* Now dump the text and properties */
+ if (must_dump_props)
+ {
+ len = propstring->len;
+ SVN_ERR(svn_stream_write(eb->stream, propstring->data, &len));
+ }
+ /* if (must_dump_text && (kind == svn_node_file)) */
+ /* { */
+ /* svn_stream_t *contents; */
+
+ /* if (delta_file) */
+ /* { */
+ /* /\* Make sure to close the underlying file when the stream is */
+ /* closed. *\/ */
+ /* contents = svn_stream_from_aprfile2(delta_file, FALSE, pool); */
+ /* } */
+ /* else */
+ /* SVN_ERR(svn_fs_file_contents(&contents, eb->fs_root, path, pool)); */
+
+ /* SVN_ERR(svn_stream_copy3(contents, svn_stream_disown(eb->stream, pool), */
+ /* NULL, NULL, pool)); */
+ /* } */
+
return SVN_NO_ERROR;
}
svn_error_t *open_root(void *edit_baton,
@@ -467,12 +521,12 @@ svn_error_t *add_file(const char *path,
/* delete the path, it's now been dumped. */
apr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);
- /* TODO: Store the delta in file_baton */
- *file_baton = NULL;
+ /* Build a nice file baton to pass to change_file_prop and apply_textdelta */
+ *file_baton = make_file_baton(eb, path, pool);
+
return SVN_NO_ERROR;
}
-
svn_error_t *open_file(const char *path,
void *parent_baton,
svn_revnum_t ancestor_revision,
@@ -497,9 +551,10 @@ svn_error_t *open_file(const char *path,
SVN_ERR(dump_node(eb, path,
svn_node_file, svn_node_action_change,
FALSE, cmp_path, cmp_rev, pool));
-
- /* TODO: Store the delta in file_baton */
- *file_baton = NULL;
+
+ /* Build a nice file baton to pass to change_file_prop and apply_textdelta */
+ *file_baton = make_file_baton(eb, path, pool);
+
return SVN_NO_ERROR;
}
@@ -532,6 +587,29 @@ svn_error_t *change_dir_prop(void *parent_baton,
return SVN_NO_ERROR;
}
+svn_error_t *change_file_prop(void *file_baton,
+ const char *name,
+ const svn_string_t *value,
+ apr_pool_t *pool)
+{
+ struct file_baton *fb = file_baton;
+
+ if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+ return SVN_NO_ERROR;
+
+ value ? apr_hash_set(fb->eb->properties, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, svn_string_dup(value, pool)) :
+ apr_hash_set(fb->eb->del_properties, apr_pstrdup(pool, name),
+ APR_HASH_KEY_STRING, (void *)0x1);
+ props_changed = TRUE;
+
+ SVN_ERR(dump_node(fb->eb, fb->path,
+ svn_node_dir, svn_node_action_change,
+ FALSE, NULL, 0, pool));
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
void **edit_baton,
svn_revnum_t to_rev,
@@ -545,7 +623,6 @@ svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
eb->current_rev = to_rev;
eb->properties = apr_hash_make(pool);
eb->del_properties = apr_hash_make(pool);
- eb->delta_text = apr_pcalloc(pool, sizeof(const char *));
dump_editor->open_root = open_root;
dump_editor->delete_entry = delete_entry;
@@ -553,6 +630,7 @@ svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
dump_editor->open_directory = open_directory;
dump_editor->close_directory = close_directory;
dump_editor->change_dir_prop = change_dir_prop;
+ dump_editor->change_file_prop = change_file_prop;
dump_editor->add_file = add_file;
dump_editor->open_file = open_file;
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [WIP PATCH 7/7] Dump the text delta
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
` (5 preceding siblings ...)
2010-06-23 16:22 ` [WIP PATCH 6/7] Add file_baton and trigger dump_node in change_file_prop Ramkumar Ramachandra
@ 2010-06-23 16:22 ` Ramkumar Ramachandra
2010-06-23 17:18 ` [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
7 siblings, 0 replies; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 16:22 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf
Add a handler and handler_baton to handle text deltas in the editor
baton. Currently, program exits with code 01 because delta source ends
unexpectedly.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
dump_editor.c | 51 +++++++++++++++++++++++++++++++--------------------
1 files changed, 31 insertions(+), 20 deletions(-)
diff --git a/dump_editor.c b/dump_editor.c
index 7bd00a4..2192177 100644
--- a/dump_editor.c
+++ b/dump_editor.c
@@ -27,12 +27,13 @@ struct edit_baton {
apr_hash_t *properties;
apr_hash_t *del_properties; /* Value is always 0x1 */
- /* Store the text delta */
- const char *delta_text;
-
/* reusable buffer for writing file contents */
char buffer[SVN__STREAM_CHUNK_SIZE];
apr_size_t bufsize;
+
+ /* The txdelta handler and handler baton */
+ svn_txdelta_window_handler_t *handler;
+ void **handler_baton;
};
struct dir_baton {
@@ -351,22 +352,9 @@ static svn_error_t *dump_node(struct edit_baton *eb,
len = propstring->len;
SVN_ERR(svn_stream_write(eb->stream, propstring->data, &len));
}
- /* if (must_dump_text && (kind == svn_node_file)) */
- /* { */
- /* svn_stream_t *contents; */
-
- /* if (delta_file) */
- /* { */
- /* /\* Make sure to close the underlying file when the stream is */
- /* closed. *\/ */
- /* contents = svn_stream_from_aprfile2(delta_file, FALSE, pool); */
- /* } */
- /* else */
- /* SVN_ERR(svn_fs_file_contents(&contents, eb->fs_root, path, pool)); */
-
- /* SVN_ERR(svn_stream_copy3(contents, svn_stream_disown(eb->stream, pool), */
- /* NULL, NULL, pool)); */
- /* } */
+ if (must_dump_text && (kind == svn_node_file) && eb->handler) {
+ svn_txdelta_to_svndiff2(eb->handler, eb->handler_baton, eb->stream, 0, pool);
+ }
return SVN_NO_ERROR;
}
@@ -610,6 +598,28 @@ svn_error_t *change_file_prop(void *file_baton,
return SVN_NO_ERROR;
}
+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 file_baton *fb = file_baton;
+ svn_stream_t *source_stream = svn_stream_empty(pool);
+ svn_txdelta_apply(source_stream, fb->eb->stream,
+ NULL, fb->path, pool, handler,
+ handler_baton);
+ fb->eb->handler = handler;
+ fb->eb->handler_baton = handler_baton;
+
+ text_changed = TRUE;
+
+ SVN_ERR(dump_node(fb->eb, fb->path,
+ svn_node_dir, svn_node_action_change,
+ FALSE, NULL, 0, pool));
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
void **edit_baton,
svn_revnum_t to_rev,
@@ -630,7 +640,8 @@ svn_error_t *get_dump_editor(const svn_delta_editor_t **editor,
dump_editor->open_directory = open_directory;
dump_editor->close_directory = close_directory;
dump_editor->change_dir_prop = change_dir_prop;
- dump_editor->change_file_prop = change_file_prop;
+ dump_editor->change_file_prop = change_file_prop;
+ dump_editor->apply_textdelta = apply_textdelta;
dump_editor->add_file = add_file;
dump_editor->open_file = open_file;
--
1.7.1
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [GSoC update] git-remote-svn: Week 8
2010-06-23 16:22 [GSoC update] git-remote-svn: Week 8 Ramkumar Ramachandra
` (6 preceding siblings ...)
2010-06-23 16:22 ` [WIP PATCH 7/7] Dump the text delta Ramkumar Ramachandra
@ 2010-06-23 17:18 ` Ramkumar Ramachandra
2010-06-25 0:42 ` Jonathan Nieder
7 siblings, 1 reply; 18+ messages in thread
From: Ramkumar Ramachandra @ 2010-06-23 17:18 UTC (permalink / raw)
To: Git Mailing List
Cc: David Michael Barr, Jonathan Nieder, Sverre Rabbelier,
Daniel Shahaf, Junio C Hamano
Hi,
I have another doubt. If the 6~8 part series is preferred, shall I
also include one patch that imports dump.c from the Subversion trunk
directly and another to strip off the unnecessary parts, clean up
whitespace and style? In other words, would you prefer to review the
dump.c taken from the Subversion trunk (and some style patches from
me) or my cleaned up version?
-- Ram
^ permalink raw reply [flat|nested] 18+ messages in thread