{"thread":{"id":"24146","subject":"[GSoC update extra!] git-remote-svn: Week 7","startedAt":"2010-06-18T18:42:09Z","lastAt":"2010-06-18T18:42:11Z","messageCount":3,"participants":["Ramkumar Ramachandra"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"143916","messageId":"1276886531-19037-1-git-send-email-artagnon@gmail.com","threadId":"24146","inReplyTo":null,"subject":"[GSoC update extra!] git-remote-svn: Week 7","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2010-06-18T18:42:09Z","receivedAt":"2010-06-18T18:42:09Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nI thought I'd post a quick update again this week, since there's been\nsome more progress. Daniel Shahaf has been awesome in helping me get\nacquainted with libsvn. I've made some more progress with the client\nand have gained some confidence- I should be able to complete the\n\"dump editor\" soon, but there are plenty of ifs and buts with respect\nto deltas. Hopefully, many of those doubts will be clear by next week.\n\n-- Ram\n\nRamkumar Ramachandra (2):\n  Add skeleton RA svnclient\n  Add stripped dump editor\n\n Makefile       |    4 +\n debug_editor.c |  413 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n debug_editor.h |    6 +\n dump_editor.c  |  365 +++++++++++++++++++++++++++++++++++++++++++++++++\n dump_editor.h  |   10 ++\n svnclient_ra.c |  138 +++++++++++++++++++\n 6 files changed, 936 insertions(+), 0 deletions(-)\n create mode 100644 Makefile\n create mode 100644 debug_editor.c\n create mode 100644 debug_editor.h\n create mode 100644 dump_editor.c\n create mode 100644 dump_editor.h\n create mode 100644 svnclient_ra.c\n"},{"id":"143918","messageId":"1276886531-19037-2-git-send-email-artagnon@gmail.com","threadId":"24146","inReplyTo":"1276886531-19037-1-git-send-email-artagnon@gmail.com","subject":"[WIP PATCH 1/2] Add skeleton RA svnclient","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2010-06-18T18:42:10Z","receivedAt":"2010-06-18T18:42:10Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The SVN client uses the RA API to connect to a remote server and\nreplay revisions. Currently, it wraps a debug editor to print out some\ntree information. In future, it will dump the data in every revision\nto stdout in dumpfile format (hopefully) without resorting to the FS\nAPI.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Makefile       |    4 +\n debug_editor.c |  413 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n debug_editor.h |    6 +\n svnclient_ra.c |  131 ++++++++++++++++++\n 4 files changed, 554 insertions(+), 0 deletions(-)\n create mode 100644 Makefile\n create mode 100644 debug_editor.c\n create mode 100644 debug_editor.h\n create mode 100644 svnclient_ra.c\n\ndiff --git a/Makefile b/Makefile\nnew file mode 100644\nindex 0000000..c3c695c\n--- /dev/null\n+++ b/Makefile\n@@ -0,0 +1,4 @@\n+svnclient_ra: *.c *.h\n+\t$(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\n+clean:\n+\t$(RM) svnclient_ra\ndiff --git a/debug_editor.c b/debug_editor.c\nnew file mode 100644\nindex 0000000..ef77e44\n--- /dev/null\n+++ b/debug_editor.c\n@@ -0,0 +1,413 @@\n+#include \"svn_pools.h\"\n+#include \"svn_cmdline.h\"\n+#include \"svn_client.h\"\n+#include \"svn_ra.h\"\n+\n+struct edit_baton\n+{\n+  const svn_delta_editor_t *wrapped_editor;\n+  void *wrapped_edit_baton;\n+\n+  int indent_level;\n+\n+  svn_stream_t *out;\n+};\n+\n+struct dir_baton\n+{\n+  void *edit_baton;\n+  void *wrapped_dir_baton;\n+};\n+\n+struct file_baton\n+{\n+  void *edit_baton;\n+  void *wrapped_file_baton;\n+};\n+\n+static svn_error_t *\n+write_indent(struct edit_baton *eb, apr_pool_t *pool)\n+{\n+  int i;\n+\n+  for (i = 0; i < eb->indent_level; ++i)\n+    SVN_ERR(svn_stream_printf(eb->out, pool, \" \"));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+set_target_revision(void *edit_baton,\n+                    svn_revnum_t target_revision,\n+                    apr_pool_t *pool)\n+{\n+  struct edit_baton *eb = edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"set_target_revision : %ld\\n\",\n+                            target_revision));\n+\n+  return eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,\n+                                                 target_revision,\n+                                                 pool);\n+}\n+\n+static svn_error_t *\n+open_root(void *edit_baton,\n+          svn_revnum_t base_revision,\n+          apr_pool_t *pool,\n+          void **root_baton)\n+{\n+  struct edit_baton *eb = edit_baton;\n+  struct dir_baton *dir_baton = apr_palloc(pool, sizeof(*dir_baton));\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"open_root : %ld\\n\",\n+                            base_revision));\n+  eb->indent_level++;\n+\n+  SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,\n+                                        base_revision,\n+                                        pool,\n+                                        &dir_baton->wrapped_dir_baton));\n+\n+  dir_baton->edit_baton = edit_baton;\n+\n+  *root_baton = dir_baton;\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+delete_entry(const char *path,\n+             svn_revnum_t base_revision,\n+             void *parent_baton,\n+             apr_pool_t *pool)\n+{\n+  struct dir_baton *pb = parent_baton;\n+  struct edit_baton *eb = pb->edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"delete_entry : %s:%ld\\n\",\n+                            path, base_revision));\n+\n+  return eb->wrapped_editor->delete_entry(path,\n+                                          base_revision,\n+                                          pb->wrapped_dir_baton,\n+                                          pool);\n+}\n+\n+static svn_error_t *\n+add_directory(const char *path,\n+              void *parent_baton,\n+              const char *copyfrom_path,\n+              svn_revnum_t copyfrom_revision,\n+              apr_pool_t *pool,\n+              void **child_baton)\n+{\n+  struct dir_baton *pb = parent_baton;\n+  struct edit_baton *eb = pb->edit_baton;\n+  struct dir_baton *b = apr_palloc(pool, sizeof(*b));\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool,\n+                            \"add_directory : '%s' [from '%s':%ld]\\n\",\n+                            path, copyfrom_path, copyfrom_revision));\n+  eb->indent_level++;\n+\n+  SVN_ERR(eb->wrapped_editor->add_directory(path,\n+                                            pb->wrapped_dir_baton,\n+                                            copyfrom_path,\n+                                            copyfrom_revision,\n+                                            pool,\n+                                            &b->wrapped_dir_baton));\n+\n+  b->edit_baton = eb;\n+  *child_baton = b;\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+open_directory(const char *path,\n+               void *parent_baton,\n+               svn_revnum_t base_revision,\n+               apr_pool_t *pool,\n+               void **child_baton)\n+{\n+  struct dir_baton *pb = parent_baton;\n+  struct edit_baton *eb = pb->edit_baton;\n+  struct dir_baton *db = apr_palloc(pool, sizeof(*db));\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"open_directory : '%s':%ld\\n\",\n+                            path, base_revision));\n+  eb->indent_level++;\n+\n+  SVN_ERR(eb->wrapped_editor->open_directory(path,\n+                                             pb->wrapped_dir_baton,\n+                                             base_revision,\n+                                             pool,\n+                                             &db->wrapped_dir_baton));\n+\n+  db->edit_baton = eb;\n+  *child_baton = db;\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+add_file(const char *path,\n+         void *parent_baton,\n+         const char *copyfrom_path,\n+         svn_revnum_t copyfrom_revision,\n+         apr_pool_t *pool,\n+         void **file_baton)\n+{\n+  struct dir_baton *pb = parent_baton;\n+  struct edit_baton *eb = pb->edit_baton;\n+  struct file_baton *fb = apr_palloc(pool, sizeof(*fb));\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool,\n+                            \"add_file : '%s' [from '%s':%ld]\\n\",\n+                            path, copyfrom_path, copyfrom_revision));\n+\n+  eb->indent_level++;\n+\n+  SVN_ERR(eb->wrapped_editor->add_file(path,\n+                                       pb->wrapped_dir_baton,\n+                                       copyfrom_path,\n+                                       copyfrom_revision,\n+                                       pool,\n+                                       &fb->wrapped_file_baton));\n+\n+  fb->edit_baton = eb;\n+  *file_baton = fb;\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+open_file(const char *path,\n+          void *parent_baton,\n+          svn_revnum_t base_revision,\n+          apr_pool_t *pool,\n+          void **file_baton)\n+{\n+  struct dir_baton *pb = parent_baton;\n+  struct edit_baton *eb = pb->edit_baton;\n+  struct file_baton *fb = apr_palloc(pool, sizeof(*fb));\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"open_file : '%s':%ld\\n\",\n+                            path, base_revision));\n+\n+  eb->indent_level++;\n+\n+  SVN_ERR(eb->wrapped_editor->open_file(path,\n+                                        pb->wrapped_dir_baton,\n+                                        base_revision,\n+                                        pool,\n+                                        &fb->wrapped_file_baton));\n+\n+  fb->edit_baton = eb;\n+  *file_baton = fb;\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+apply_textdelta(void *file_baton,\n+                const char *base_checksum,\n+                apr_pool_t *pool,\n+                svn_txdelta_window_handler_t *handler,\n+                void **handler_baton)\n+{\n+  struct file_baton *fb = file_baton;\n+  struct edit_baton *eb = fb->edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"apply_textdelta : %s\\n\",\n+                            base_checksum));\n+\n+  SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,\n+                                              base_checksum,\n+                                              pool,\n+                                              handler,\n+                                              handler_baton));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+close_file(void *file_baton,\n+           const char *text_checksum,\n+           apr_pool_t *pool)\n+{\n+  struct file_baton *fb = file_baton;\n+  struct edit_baton *eb = fb->edit_baton;\n+\n+  eb->indent_level--;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"close_file : %s\\n\",\n+                            text_checksum));\n+\n+  SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,\n+                                         text_checksum, pool));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+absent_file(const char *path,\n+            void *file_baton,\n+            apr_pool_t *pool)\n+{\n+  struct file_baton *fb = file_baton;\n+  struct edit_baton *eb = fb->edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"absent_file : %s\\n\", path));\n+\n+  SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,\n+                                          pool));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+close_directory(void *dir_baton,\n+                apr_pool_t *pool)\n+{\n+  struct dir_baton *db = dir_baton;\n+  struct edit_baton *eb = db->edit_baton;\n+\n+  eb->indent_level--;\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"close_directory\\n\"));\n+\n+  SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,\n+                                              pool));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+absent_directory(const char *path,\n+                 void *dir_baton,\n+                 apr_pool_t *pool)\n+{\n+  struct dir_baton *db = dir_baton;\n+  struct edit_baton *eb = db->edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"absent_directory : %s\\n\",\n+                            path));\n+\n+  SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,\n+                                               pool));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+change_file_prop(void *file_baton,\n+                 const char *name,\n+                 const svn_string_t *value,\n+                 apr_pool_t *pool)\n+{\n+  struct file_baton *fb = file_baton;\n+  struct edit_baton *eb = fb->edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"change_file_prop : %s\\n\",\n+                            name));\n+\n+  SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,\n+                                               name,\n+                                               value,\n+                                               pool));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+change_dir_prop(void *dir_baton,\n+                const char *name,\n+                const svn_string_t *value,\n+                apr_pool_t *pool)\n+{\n+  struct dir_baton *db = dir_baton;\n+  struct edit_baton *eb = db->edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"change_dir_prop : %s\\n\", name));\n+\n+  SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,\n+                                              name,\n+                                              value,\n+                                              pool));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *\n+close_edit(void *edit_baton,\n+           apr_pool_t *pool)\n+{\n+  struct edit_baton *eb = edit_baton;\n+\n+  SVN_ERR(write_indent(eb, pool));\n+  SVN_ERR(svn_stream_printf(eb->out, pool, \"close_edit\\n\"));\n+\n+  SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));\n+\n+  return SVN_NO_ERROR;\n+}\n+\n+svn_error_t *\n+svn_delta__get_debug_editor(const svn_delta_editor_t **editor,\n+                            void **edit_baton,\n+                            const svn_delta_editor_t *wrapped_editor,\n+                            void *wrapped_edit_baton,\n+                            apr_pool_t *pool)\n+{\n+  svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);\n+  struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));\n+  apr_file_t *errfp;\n+  svn_stream_t *out;\n+\n+  apr_status_t apr_err = apr_file_open_stderr(&errfp, pool);\n+  if (apr_err)\n+    return svn_error_wrap_apr(apr_err, \"Problem opening stderr\");\n+\n+  out = svn_stream_from_aprfile2(errfp, TRUE, pool);\n+\n+  tree_editor->set_target_revision = set_target_revision;\n+  tree_editor->open_root = open_root;\n+  tree_editor->delete_entry = delete_entry;\n+  tree_editor->add_directory = add_directory;\n+  tree_editor->open_directory = open_directory;\n+  tree_editor->change_dir_prop = change_dir_prop;\n+  tree_editor->close_directory = close_directory;\n+  tree_editor->absent_directory = absent_directory;\n+  tree_editor->add_file = add_file;\n+  tree_editor->open_file = open_file;\n+  tree_editor->apply_textdelta = apply_textdelta;\n+  tree_editor->change_file_prop = change_file_prop;\n+  tree_editor->close_file = close_file;\n+  tree_editor->absent_file = absent_file;\n+  tree_editor->close_edit = close_edit;\n+\n+  eb->wrapped_editor = wrapped_editor;\n+  eb->wrapped_edit_baton = wrapped_edit_baton;\n+  eb->out = out;\n+  eb->indent_level = 0;\n+\n+  *editor = tree_editor;\n+  *edit_baton = eb;\n+\n+  return SVN_NO_ERROR;\n+}\ndiff --git a/debug_editor.h b/debug_editor.h\nnew file mode 100644\nindex 0000000..ae87c36\n--- /dev/null\n+++ b/debug_editor.h\n@@ -0,0 +1,6 @@\n+svn_error_t *\n+svn_delta__get_debug_editor(const svn_delta_editor_t **editor,\n+                            void **edit_baton,\n+                            const svn_delta_editor_t *wrapped_editor,\n+                            void *wrapped_edit_baton,\n+                            apr_pool_t *pool);\ndiff --git a/svnclient_ra.c b/svnclient_ra.c\nnew file mode 100644\nindex 0000000..2ed04af\n--- /dev/null\n+++ b/svnclient_ra.c\n@@ -0,0 +1,131 @@\n+#include \"svn_pools.h\"\n+#include \"svn_cmdline.h\"\n+#include \"svn_client.h\"\n+#include \"svn_ra.h\"\n+\n+#include \"debug_editor.h\"\n+\n+static apr_pool_t *pool = NULL;\n+static svn_client_ctx_t *ctx = NULL;\n+static svn_ra_session_t *session = NULL;\n+\n+typedef struct {\n+\tvoid *editor, *baton;\n+} replay_baton_t;\n+\n+static svn_error_t *replay_revstart(svn_revnum_t revision,\n+                                    void *replay_baton,\n+                                    const svn_delta_editor_t **editor,\n+                                    void **edit_baton,\n+                                    apr_hash_t *rev_props,\n+                                    apr_pool_t *pool)\n+{\n+\t*editor = ((replay_baton_t *) replay_baton)->editor;\n+\t*edit_baton = ((replay_baton_t *) replay_baton)->baton;\n+\treturn SVN_NO_ERROR;\n+}\n+\n+static svn_error_t *replay_revend(svn_revnum_t revision,\n+                                  void *replay_baton,\n+                                  const svn_delta_editor_t *editor,\n+                                  void *edit_baton,\n+                                  apr_hash_t *rev_props,\n+                                  apr_pool_t *pool)\n+{\n+\tSVN_ERR(editor->close_edit(edit_baton, pool));\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *build_auth_baton()\n+{\n+\tsvn_auth_provider_object_t *provider;\n+\tapr_array_header_t *providers\n+\t\t= apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *));\n+\n+\tsvn_auth_get_simple_prompt_provider (&provider,\n+\t                                     NULL,\n+\t                                     NULL,\n+\t                                     2,\n+\t                                     pool);\n+\tAPR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;\n+\n+\tsvn_auth_get_username_prompt_provider (&provider,\n+\t                                       NULL,\n+\t                                       NULL,\n+\t                                       2,\n+\t                                       pool);\n+\tAPR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;\n+\n+\tsvn_auth_open (&ctx->auth_baton, providers, pool);\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *populate_context()\n+{\n+\tconst char *http_library;\n+\t\n+\tSVN_ERR(svn_config_get_config(&(ctx->config), NULL, pool));\n+\t\n+\thttp_library = getenv(\"SVN_HTTP_LIBRARY\");\n+\tif (http_library)\n+\t\tsvn_config_set(apr_hash_get(ctx->config, \"servers\", APR_HASH_KEY_STRING),\n+\t\t               \"global\", \"http-library\", http_library);\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *open_connection(const char *url)\n+{\n+\tSVN_ERR(svn_config_ensure (NULL, pool));\n+\tSVN_ERR(svn_client_create_context (&ctx, pool));\n+\tSVN_ERR(svn_ra_initialize(pool));\n+\n+#if defined(WIN32) || defined(__CYGWIN__)\n+\tif (getenv(\"SVN_ASP_DOT_NET_HACK\"))\n+\t\tSVN_ERR(svn_wc_set_adm_dir(\"_svn\", pool));\n+#endif\n+\n+\tSVN_ERR(populate_context());\n+\tSVN_ERR(build_auth_baton());\n+\tSVN_ERR(svn_client_open_ra_session(&session, url, ctx, pool));\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_revision)\n+{\n+\tsvn_revnum_t latest_revision;\n+\tsvn_delta_editor_t *editor, *debug_editor;\n+\treplay_baton_t *replay_baton = apr_palloc(pool, sizeof(replay_baton_t));\n+\tvoid *debug_baton;\n+\tSVN_ERR(svn_ra_get_latest_revnum(session, &latest_revision, pool));\n+\tprintf(\"%ld\\n\", latest_revision);\n+\teditor = svn_delta_default_editor(pool);\n+\tSVN_ERR(svn_delta__get_debug_editor((const svn_delta_editor_t **)&debug_editor,\n+\t                                    &debug_baton, editor,\n+\t                                    NULL, pool));\n+\treplay_baton->editor = debug_editor;\n+\treplay_baton->baton = debug_baton;\n+\tSVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,\n+\t                            0, TRUE, replay_revstart, replay_revend,\n+\t                            replay_baton, pool));\n+\treturn SVN_NO_ERROR;\n+}\n+\n+void close_connection()\n+{\n+\tsvn_pool_destroy(pool);\n+}\n+\n+int main()\n+{\n+\tconst char url[] = \"http://svn.apache.org/repos/asf\";\n+\tsvn_revnum_t start_revision = 1, end_revision = 5;\n+\tif (svn_cmdline_init (\"svnclient_ra\", stderr) != EXIT_SUCCESS)\n+\t\treturn 1;\n+\tpool = svn_pool_create(NULL);\n+\n+\tSVN_INT_ERR(open_connection(url));\n+\tSVN_INT_ERR(replay_range(start_revision, end_revision));\n+\n+\tclose_connection();\n+\treturn 0;\n+}\n-- \n1.7.1\n"},{"id":"143917","messageId":"1276886531-19037-3-git-send-email-artagnon@gmail.com","threadId":"24146","inReplyTo":"1276886531-19037-1-git-send-email-artagnon@gmail.com","subject":"[WIP PATCH 2/2] Add stripped dump editor","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2010-06-18T18:42:11Z","receivedAt":"2010-06-18T18:42:11Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Replace the default editor with a dump editor from libsvn_repos/dump.c\nafter stripping off filesystem dependencies. Currently, the dump\neditor does nothing, but will dump some revision information to stdout\nin future.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Makefile       |    2 +-\n dump_editor.c  |  365 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n dump_editor.h  |   10 ++\n svnclient_ra.c |   19 ++-\n 4 files changed, 389 insertions(+), 7 deletions(-)\n create mode 100644 dump_editor.c\n create mode 100644 dump_editor.h\n\ndiff --git a/Makefile b/Makefile\nindex c3c695c..269c406 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1,4 +1,4 @@\n svnclient_ra: *.c *.h\n-\t$(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\n+\t$(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\n clean:\n \t$(RM) svnclient_ra\ndiff --git a/dump_editor.c b/dump_editor.c\nnew file mode 100644\nindex 0000000..f5353b0\n--- /dev/null\n+++ b/dump_editor.c\n@@ -0,0 +1,365 @@\n+#include \"svn_pools.h\"\n+#include \"svn_error.h\"\n+#include \"svn_iter.h\"\n+#include \"svn_repos.h\"\n+#include \"svn_string.h\"\n+#include \"svn_dirent_uri.h\"\n+#include \"svn_path.h\"\n+#include \"svn_time.h\"\n+#include \"svn_checksum.h\"\n+#include \"svn_props.h\"\n+\n+#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))\n+/*----------------------------------------------------------------------*/\n+/** An editor which dumps node-data in 'dumpfile format' to a file. **/\n+\n+/* Look, mom!  No file batons! */\n+\n+struct edit_baton\n+{\n+\t/* The stream to dump to: stdout */\n+\tsvn_stream_t *stream;\n+\t\n+\tsvn_revnum_t current_rev;\n+\t\n+\t/* reusable buffer for writing file contents */\n+\tchar buffer[SVN__STREAM_CHUNK_SIZE];\n+\tapr_size_t bufsize;\n+};\n+\n+struct dir_baton\n+{\n+\tstruct edit_baton *edit_baton;\n+\tstruct dir_baton *parent_dir_baton;\n+\n+\t/* is this directory a new addition to this revision? */\n+\tsvn_boolean_t added;\n+\n+\t/* has this directory been written to the output stream? */\n+\tsvn_boolean_t written_out;\n+\n+\t/* the absolute path to this directory */\n+\tconst char *path;\n+\n+\t/* the comparison path and revision of this directory.  if both of\n+\t   these are valid, use them as a source against which to compare\n+\t   the directory instead of the default comparison source of PATH in\n+\t   the previous revision. */\n+\tconst char *cmp_path;\n+\tsvn_revnum_t cmp_rev;\n+\n+\t/* hash of paths that need to be deleted, though some -might- be\n+\t   replaced.  maps const char * paths to this dir_baton.  (they're\n+\t   full paths, because that's what the editor driver gives us.  but\n+\t   really, they're all within this directory.) */\n+\tapr_hash_t *deleted_entries;\n+\n+\t/* pool to be used for deleting the hash items */\n+\tapr_pool_t *pool;\n+};\n+\n+\n+/* Make a directory baton to represent the directory was path\n+   (relative to EDIT_BATON's path) is PATH.\n+\n+   CMP_PATH/CMP_REV are the path/revision against which this directory\n+   should be compared for changes.  If either is omitted (NULL for the\n+   path, SVN_INVALID_REVNUM for the rev), just compare this directory\n+   PATH against itself in the previous revision.\n+\n+   PARENT_DIR_BATON is the directory baton of this directory's parent,\n+   or NULL if this is the top-level directory of the edit.  ADDED\n+   indicated if this directory is newly added in this revision.\n+   Perform all allocations in POOL.  */\n+struct dir_baton *\n+make_dir_baton(const char *path,\n+               const char *cmp_path,\n+               svn_revnum_t cmp_rev,\n+               void *edit_baton,\n+               void *parent_dir_baton,\n+               svn_boolean_t added,\n+               apr_pool_t *pool)\n+{\n+\tstruct edit_baton *eb = edit_baton;\n+\tstruct dir_baton *pb = parent_dir_baton;\n+\tstruct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));\n+\tconst char *full_path;\n+\n+\t/* A path relative to nothing?  I don't think so. */\n+\tSVN_ERR_ASSERT_NO_RETURN(!path || pb);\n+\n+\t/* Construct the full path of this node. */\n+\tif (pb)\n+\t\tfull_path = svn_path_join(\"/\", path, pool);\n+\telse\n+\t\tfull_path = apr_pstrdup(pool, \"/\");\n+\n+\t/* Remove leading slashes from copyfrom paths. */\n+\tif (cmp_path)\n+\t\tcmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path);\n+\n+\tnew_db->edit_baton = eb;\n+\tnew_db->parent_dir_baton = pb;\n+\tnew_db->path = full_path;\n+\tnew_db->cmp_path = cmp_path ? apr_pstrdup(pool, cmp_path) : NULL;\n+\tnew_db->cmp_rev = cmp_rev;\n+\tnew_db->added = added;\n+\tnew_db->written_out = FALSE;\n+\tnew_db->deleted_entries = apr_hash_make(pool);\n+\tnew_db->pool = pool;\n+\n+\treturn new_db;\n+}\n+\n+\n+svn_error_t *\n+open_root(void *edit_baton,\n+          svn_revnum_t base_revision,\n+          apr_pool_t *pool,\n+          void **root_baton)\n+{\n+\t*root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,\n+\t                             edit_baton, NULL, FALSE, pool);\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *\n+delete_entry(const char *path,\n+             svn_revnum_t revision,\n+             void *parent_baton,\n+             apr_pool_t *pool)\n+{\n+\tstruct dir_baton *pb = parent_baton;\n+\tconst char *mypath = apr_pstrdup(pb->pool, path);\n+\n+\t/* remember this path needs to be deleted. */\n+\tapr_hash_set(pb->deleted_entries, mypath, APR_HASH_KEY_STRING, pb);\n+\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *\n+add_directory(const char *path,\n+              void *parent_baton,\n+              const char *copyfrom_path,\n+              svn_revnum_t copyfrom_rev,\n+              apr_pool_t *pool,\n+              void **child_baton)\n+{\n+\tstruct dir_baton *pb = parent_baton;\n+\tstruct edit_baton *eb = pb->edit_baton;\n+\tvoid *val;\n+\tsvn_boolean_t is_copy = FALSE;\n+\tstruct dir_baton *new_db\n+\t\t= make_dir_baton(path, copyfrom_path, copyfrom_rev, eb, pb, TRUE, pool);\n+\n+\t/* This might be a replacement -- is the path already deleted? */\n+\tval = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);\n+\n+\t/* Detect an add-with-history. */\n+\tis_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);\n+\n+\t/* Dump the node. */\n+\t/* SVN_ERR(dump_node(eb, path, */\n+\t/*                   svn_node_dir, */\n+\t/*                   val ? svn_node_action_replace : svn_node_action_add, */\n+\t/*                   is_copy, */\n+\t/*                   is_copy ? copyfrom_path : NULL, */\n+\t/*                   is_copy ? copyfrom_rev : SVN_INVALID_REVNUM, */\n+\t/*                   pool)); */\n+\n+\tif (val)\n+\t\t/* Delete the path, it's now been dumped. */\n+\t\tapr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);\n+\n+\tnew_db->written_out = TRUE;\n+\n+\t*child_baton = new_db;\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *\n+open_directory(const char *path,\n+               void *parent_baton,\n+               svn_revnum_t base_revision,\n+               apr_pool_t *pool,\n+               void **child_baton)\n+{\n+\tstruct dir_baton *pb = parent_baton;\n+\tstruct edit_baton *eb = pb->edit_baton;\n+\tstruct dir_baton *new_db;\n+\tconst char *cmp_path = NULL;\n+\tsvn_revnum_t cmp_rev = SVN_INVALID_REVNUM;\n+\n+\t/* If the parent directory has explicit comparison path and rev,\n+\t   record the same for this one. */\n+\tif (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev))\n+\t{\n+\t\tcmp_path = svn_path_join(pb->cmp_path,\n+\t\t                         svn_dirent_basename(path, pool), pool);\n+\t\tcmp_rev = pb->cmp_rev;\n+\t}\n+\n+\tnew_db = make_dir_baton(path, cmp_path, cmp_rev, eb, pb, FALSE, pool);\n+\t*child_baton = new_db;\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *\n+close_directory(void *dir_baton,\n+                apr_pool_t *pool)\n+{\n+\tstruct dir_baton *db = dir_baton;\n+\tstruct edit_baton *eb = db->edit_baton;\n+\tapr_hash_index_t *hi;\n+\tapr_pool_t *subpool = svn_pool_create(pool);\n+\n+\tfor (hi = apr_hash_first(pool, db->deleted_entries);\n+\t     hi;\n+\t     hi = apr_hash_next(hi))\n+\t{\n+\t\tconst void *key;\n+\t\tconst char *path;\n+\t\tapr_hash_this(hi, &key, NULL, NULL);\n+\t\tpath = key;\n+\n+\t\tsvn_pool_clear(subpool);\n+\n+\t\t/* By sending 'svn_node_unknown', the Node-kind: header simply won't\n+\t\t   be written out.  No big deal at all, really.  The loader\n+\t\t   shouldn't care.  */\n+\t\t/* SVN_ERR(dump_node(eb, path, */\n+\t\t/*                   svn_node_unknown, svn_node_action_delete, */\n+\t\t/*                   FALSE, NULL, SVN_INVALID_REVNUM, subpool)); */\n+\t}\n+\n+\tsvn_pool_destroy(subpool);\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *\n+add_file(const char *path,\n+         void *parent_baton,\n+         const char *copyfrom_path,\n+         svn_revnum_t copyfrom_rev,\n+         apr_pool_t *pool,\n+         void **file_baton)\n+{\n+\tstruct dir_baton *pb = parent_baton;\n+\tstruct edit_baton *eb = pb->edit_baton;\n+\tvoid *val;\n+\tsvn_boolean_t is_copy = FALSE;\n+\n+\t/* This might be a replacement -- is the path already deleted? */\n+\tval = apr_hash_get(pb->deleted_entries, path, APR_HASH_KEY_STRING);\n+\n+\t/* Detect add-with-history. */\n+\tis_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);\n+\n+\t/* Dump the node. */\n+\t/* SVN_ERR(dump_node(eb, path, */\n+\t/*                   svn_node_file, */\n+\t/*                   val ? svn_node_action_replace : svn_node_action_add, */\n+\t/*                   is_copy, */\n+\t/*                   is_copy ? copyfrom_path : NULL, */\n+\t/*                   is_copy ? copyfrom_rev : SVN_INVALID_REVNUM, */\n+\t/*                   pool)); */\n+\n+\tif (val)\n+\t\t/* delete the path, it's now been dumped. */\n+\t\tapr_hash_set(pb->deleted_entries, path, APR_HASH_KEY_STRING, NULL);\n+\n+\t*file_baton = NULL;  /* muhahahaha */\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *\n+open_file(const char *path,\n+          void *parent_baton,\n+          svn_revnum_t ancestor_revision,\n+          apr_pool_t *pool,\n+          void **file_baton)\n+{\n+\tstruct dir_baton *pb = parent_baton;\n+\tstruct edit_baton *eb = pb->edit_baton;\n+\tconst char *cmp_path = NULL;\n+\tsvn_revnum_t cmp_rev = SVN_INVALID_REVNUM;\n+\n+\t/* If the parent directory has explicit comparison path and rev,\n+\t   record the same for this one. */\n+\tif (pb && ARE_VALID_COPY_ARGS(pb->cmp_path, pb->cmp_rev))\n+\t{\n+\t\tcmp_path = svn_path_join(pb->cmp_path,\n+\t\t                         svn_dirent_basename(path, pool), pool);\n+\t\tcmp_rev = pb->cmp_rev;\n+\t}\n+\n+\t/* SVN_ERR(dump_node(eb, path, */\n+\t/*                   svn_node_file, svn_node_action_change, */\n+\t/*                   FALSE, cmp_path, cmp_rev, pool)); */\n+\n+\t*file_baton = NULL;  /* muhahahaha again */\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *\n+change_dir_prop(void *parent_baton,\n+                const char *name,\n+                const svn_string_t *value,\n+                apr_pool_t *pool)\n+{\n+\tstruct dir_baton *db = parent_baton;\n+\tstruct edit_baton *eb = db->edit_baton;\n+\n+\t/* This function is what distinguishes between a directory that is\n+\t   opened to merely get somewhere, vs. one that is opened because it\n+\t   *actually* changed by itself.  */\n+\tif (! db->written_out)\n+\t{\n+\t\t/* SVN_ERR(dump_node(eb, db->path, */\n+\t\t/*                   svn_node_dir, svn_node_action_change, */\n+\t\t/*                   FALSE, db->cmp_path, db->cmp_rev, pool)); */\n+\t\tdb->written_out = TRUE;\n+\t}\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *\n+get_dump_editor(const svn_delta_editor_t **editor,\n+                void **edit_baton,\n+                svn_revnum_t to_rev,\n+                apr_pool_t *pool)\n+{\n+\t/* Allocate an edit baton to be stored in every directory baton.\n+\t   Set it up for the directory baton we create here, which is the\n+\t   root baton. */\n+\tstruct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));\n+\tsvn_delta_editor_t *dump_editor = svn_delta_default_editor(pool);\n+\n+\t/* Set up the edit baton. */\n+\tsvn_stream_for_stdout(&(eb->stream), pool);\n+\teb->bufsize = sizeof(eb->buffer);\n+\teb->current_rev = to_rev;\n+\n+\n+\t/* Set up the editor. */\n+\tdump_editor->open_root = open_root;\n+\tdump_editor->delete_entry = delete_entry;\n+\tdump_editor->add_directory = add_directory;\n+\tdump_editor->open_directory = open_directory;\n+\tdump_editor->close_directory = close_directory;\n+\tdump_editor->change_dir_prop = change_dir_prop;\n+\tdump_editor->add_file = add_file;\n+\tdump_editor->open_file = open_file;\n+\n+\t*edit_baton = eb;\n+\t*editor = dump_editor;\n+\n+\treturn SVN_NO_ERROR;\n+}\ndiff --git a/dump_editor.h b/dump_editor.h\nnew file mode 100644\nindex 0000000..5e84223\n--- /dev/null\n+++ b/dump_editor.h\n@@ -0,0 +1,10 @@\n+#include \"svn_pools.h\"\n+#include \"svn_cmdline.h\"\n+#include \"svn_client.h\"\n+#include \"svn_ra.h\"\n+\n+svn_error_t *\n+get_dump_editor(const svn_delta_editor_t **editor,\n+                void **edit_baton,\n+                svn_revnum_t to_rev,\n+                apr_pool_t *pool);\ndiff --git a/svnclient_ra.c b/svnclient_ra.c\nindex 2ed04af..24d99cb 100644\n--- a/svnclient_ra.c\n+++ b/svnclient_ra.c\n@@ -4,6 +4,7 @@\n #include \"svn_ra.h\"\n \n #include \"debug_editor.h\"\n+#include \"dump_editor.h\"\n \n static apr_pool_t *pool = NULL;\n static svn_client_ctx_t *ctx = NULL;\n@@ -92,16 +93,22 @@ svn_error_t *open_connection(const char *url)\n \n svn_error_t *replay_range(svn_revnum_t start_revision, svn_revnum_t end_revision)\n {\n+\tsvn_delta_editor_t *dump_editor, *debug_editor;\n+\tvoid *debug_baton, *dump_baton;\n+\t\n \tsvn_revnum_t latest_revision;\n-\tsvn_delta_editor_t *editor, *debug_editor;\n-\treplay_baton_t *replay_baton = apr_palloc(pool, sizeof(replay_baton_t));\n-\tvoid *debug_baton;\n \tSVN_ERR(svn_ra_get_latest_revnum(session, &latest_revision, pool));\n \tprintf(\"%ld\\n\", latest_revision);\n-\teditor = svn_delta_default_editor(pool);\n+\t\n+\tSVN_ERR(get_dump_editor((const svn_delta_editor_t **)&dump_editor,\n+\t                        &dump_baton, end_revision, pool));\n+\n \tSVN_ERR(svn_delta__get_debug_editor((const svn_delta_editor_t **)&debug_editor,\n-\t                                    &debug_baton, editor,\n-\t                                    NULL, pool));\n+\t                                    &debug_baton,\n+\t                                    (const svn_delta_editor_t *)dump_editor,\n+\t                                    dump_baton, pool));\n+\t\n+\treplay_baton_t *replay_baton = apr_palloc(pool, sizeof(replay_baton_t));\n \treplay_baton->editor = debug_editor;\n \treplay_baton->baton = debug_baton;\n \tSVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,\n-- \n1.7.1\n"}]}