{"thread":{"id":"24109","subject":"[WIP PATCH] Add a skeleton RA SVN client","startedAt":"2010-06-14T16:19:23Z","lastAt":"2010-06-14T16:19:24Z","messageCount":2,"participants":["Ramkumar Ramachandra"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"143682","messageId":"1276532364-6993-1-git-send-email-artagnon@gmail.com","threadId":"24109","inReplyTo":null,"subject":"[GSoC update] git-remote-svn: Week 7","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2010-06-14T16:19:23Z","receivedAt":"2010-06-14T16:19:23Z","isPatch":false,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nI suspect that people are confused about what I'm exactly doing and\nhow to review/ test all the work since I've been posting updates in\nrapid bursts, and writing relatively short emails. For a change, this\nemail is going to be (relatively) long and detailed since things are\nfinally starting to take shape. So, the project involves the following\ncomponents:\n1. The remote helper application or remote-svn (90% complete): There's\nnothing much to see here; I just stripped down remote-curl.c and\nposted a remote-svn.c along with the relevant Makefile rule to build\nit a few weeks ago [1]. What this needs: Some infrastructure to do the\nimporting/ exporting in $GIT_ROOT/vcs-svn/.\n2. David's SVN exporter or svn-fe (80% complete): This is quite an\nexcellent piece of software for turning an SVN dumpfile into a stream\nthat git-fast-import can import [2]. David has validated it against\n940,000 commits of the ASF repository, and it works perfectly. It's\n80% complete because there's some room for refactoring certain parts,\nand cosmetic beautification before the merge into `next`. I work on\nboth `master` and a special `git-merge` branch specifically for\nmerging it into git.git. Jonathan has suggested that two separate\ncomponents should be merged into git.git: svn-fe itself as an\nindependent program in $GIT_ROOT/contrib/ and the `git-merge` branch\nfor creating infrastructure for the remote helper in\n$GIT_ROOT/vcs-svn/. We are currently preparing a series for the\nformer, while the latter was just merged into pu this week [3].\n3. The RA SVN Client or svnclient_ra (15% complete): This piece of\nsofware will be invoked by the remote helper and will use the libsvn\nAPI (yuck!) to contact a remote server and produce output in dumpfile\nformat for the exporter component. Jonas has written a software called\nrsvndump which already does this [4], but the codebase is too clunky\nand outdated (it doesn't use the replay API); I'm therefore attempting\na complete rewrite, and you can find the latest update in a patch in\nthe second part of this series. Note that the replay API forces a\nserver version >= 1.5 restriction, but Sverre and I are alright with\nthis. The cost of backward compatibility is a LOT of ugly code (seen\nin rsvndump).\n4. The importer (0% complete): I'll probably only get started with\nthis after the mid-term evaluations.\n\n[1]: http://article.gmane.org/gmane.comp.version-control.git/147716\n[2]: http://github.com/artagnon/svn-dump-fast-export\n[3]: Commit 9c55c48\n[4]: http://github.com/jgehring/rsvndump\n\n-- Ram\n\nRamkumar Ramachandra (1):\n  Add a skeleton RA SVN client\n\n Makefile       |    2 +\n delta_editor.c |  112 ++++++++++++++++++++++++++++++++++++++++++++++\n delta_editor.h |   66 +++++++++++++++++++++++++++\n svnclient_ra.c |  135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 315 insertions(+), 0 deletions(-)\n create mode 100644 Makefile\n create mode 100644 delta_editor.c\n create mode 100644 delta_editor.h\n create mode 100644 svnclient_ra.c\n"},{"id":"143681","messageId":"1276532364-6993-2-git-send-email-artagnon@gmail.com","threadId":"24109","inReplyTo":"1276532364-6993-1-git-send-email-artagnon@gmail.com","subject":"[WIP PATCH] Add a skeleton RA SVN client","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2010-06-14T16:19:24Z","receivedAt":"2010-06-14T16:19:24Z","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. In future, it will dump the data in every revision\nto stdout in dumpfile format (hopefully) without resorting to the FS\nAPI and svn_repos_dump_fs2.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Makefile       |    2 +\n delta_editor.c |  112 ++++++++++++++++++++++++++++++++++++++++++++++\n delta_editor.h |   66 +++++++++++++++++++++++++++\n svnclient_ra.c |  135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 315 insertions(+), 0 deletions(-)\n create mode 100644 Makefile\n create mode 100644 delta_editor.c\n create mode 100644 delta_editor.h\n create mode 100644 svnclient_ra.c\n\ndiff --git a/Makefile b/Makefile\nnew file mode 100644\nindex 0000000..662061b\n--- /dev/null\n+++ b/Makefile\n@@ -0,0 +1,2 @@\n+svnclient_ra: svnclient_ra.c\n+\tcc -Wall -Werror -ggdb -O1 -o $@ -lsvn_client-1 svnclient_ra.c delta_editor.c -I. -I/usr/include/subversion-1 -I/usr/include/apr-1.0\ndiff --git a/delta_editor.c b/delta_editor.c\nnew file mode 100644\nindex 0000000..8c722cd\n--- /dev/null\n+++ b/delta_editor.c\n@@ -0,0 +1,112 @@\n+#include \"svn_pools.h\"\n+#include \"svn_cmdline.h\"\n+#include \"svn_client.h\"\n+#include \"svn_ra.h\"\n+\n+#include \"delta_editor.h\"\n+\n+svn_error_t *set_target_revision(void *edit_baton,\n+                                 svn_revnum_t target_revision,\n+                                 apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *open_root(void *edit_baton, svn_revnum_t base_revision,\n+                       apr_pool_t *dir_pool, void **root_baton)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *delete_entry(const char *path, svn_revnum_t revision,\n+                          void *parent_baton, apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *add_directory(const char *path, void *parent_baton,\n+                           const char *copyfrom_path,\n+                           svn_revnum_t copyfrom_revision,\n+                           apr_pool_t *dir_pool, void **child_baton)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+\n+svn_error_t *open_directory(const char *path, void *parent_baton,\n+                            svn_revnum_t base_revision,\n+                            apr_pool_t *dir_pool, void **child_baton)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *change_dir_prop(void *dir_baton, const char *name,\n+                             const svn_string_t *value, apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *close_directory(void *dir_baton, apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *absent_directory(const char *path, void *parent_baton,\n+                              apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *add_file(const char *path, void *parent_baton,\n+                      const char *copyfrom_path,\n+                      svn_revnum_t copyfrom_revision,\n+                      apr_pool_t *file_pool, void **file_baton)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *open_file(const char *path, void *parent_baton,\n+                       svn_revnum_t base_revision, apr_pool_t *file_pool,\n+                       void **file_baton)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *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+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *change_file_prop(void *file_baton, const char *name,\n+                              const svn_string_t *value,\n+                              apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *close_file(void *file_baton, const char *text_checksum,\n+                        apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *absent_file(const char *path, void *parent_baton,\n+                         apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *close_edit(void *edit_baton, apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\n+\n+svn_error_t *abort_edit(void *edit_baton, apr_pool_t *pool)\n+{\n+\treturn SVN_NO_ERROR;\n+}\ndiff --git a/delta_editor.h b/delta_editor.h\nnew file mode 100644\nindex 0000000..49652d7\n--- /dev/null\n+++ b/delta_editor.h\n@@ -0,0 +1,66 @@\n+#ifndef DELTA_EDITOR_H_\n+#define DELTA_EDITOR_H_\n+\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 *set_target_revision(void *edit_baton,\n+                                 svn_revnum_t target_revision,\n+                                 apr_pool_t *pool);\n+\n+svn_error_t *open_root(void *edit_baton, svn_revnum_t base_revision,\n+                       apr_pool_t *dir_pool, void **root_baton);\n+\n+svn_error_t *delete_entry(const char *path, svn_revnum_t revision,\n+                          void *parent_baton, apr_pool_t *pool);\n+\n+svn_error_t *add_directory(const char *path, void *parent_baton,\n+                           const char *copyfrom_path,\n+                           svn_revnum_t copyfrom_revision,\n+                           apr_pool_t *dir_pool, void **child_baton);\n+\n+\n+svn_error_t *open_directory(const char *path, void *parent_baton,\n+                            svn_revnum_t base_revision,\n+                            apr_pool_t *dir_pool, void **child_baton);\n+\n+svn_error_t *change_dir_prop(void *dir_baton, const char *name,\n+                             const svn_string_t *value, apr_pool_t *pool);\n+\n+svn_error_t *close_directory(void *dir_baton, apr_pool_t *pool);\n+\n+svn_error_t *absent_directory(const char *path, void *parent_baton,\n+                              apr_pool_t *pool);\n+\n+svn_error_t *add_file(const char *path, void *parent_baton,\n+                      const char *copyfrom_path,\n+                      svn_revnum_t copyfrom_revision,\n+                      apr_pool_t *file_pool, void **file_baton);\n+\n+svn_error_t *open_file(const char *path, void *parent_baton,\n+                       svn_revnum_t base_revision, apr_pool_t *file_pool,\n+                       void **file_baton);\n+\n+svn_error_t *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+svn_error_t *change_file_prop(void *file_baton, const char *name,\n+                              const svn_string_t *value,\n+                              apr_pool_t *pool);\n+\n+svn_error_t *close_file(void *file_baton, const char *text_checksum,\n+                        apr_pool_t *pool);\n+\n+svn_error_t *absent_file(const char *path, void *parent_baton,\n+                         apr_pool_t *pool);\n+\n+svn_error_t *close_edit(void *edit_baton, apr_pool_t *pool);\n+\n+svn_error_t *abort_edit(void *edit_baton, apr_pool_t *pool);\n+\n+#endif\ndiff --git a/svnclient_ra.c b/svnclient_ra.c\nnew file mode 100644\nindex 0000000..a754494\n--- /dev/null\n+++ b/svnclient_ra.c\n@@ -0,0 +1,135 @@\n+#include \"svn_pools.h\"\n+#include \"svn_cmdline.h\"\n+#include \"svn_client.h\"\n+#include \"svn_ra.h\"\n+\n+#include \"delta_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+static svn_error_t *setup_delta_editor(svn_delta_editor_t **editor)\n+{\n+\t*editor = svn_delta_default_editor(pool);\n+\t(*editor)->set_target_revision = set_target_revision;\n+\t(*editor)->open_root = open_root;\n+\t(*editor)->delete_entry = delete_entry;\n+\t(*editor)->add_directory = add_directory;\n+\t(*editor)->open_directory = open_directory;\n+\t(*editor)->add_file = add_file;\n+\t(*editor)->open_file = open_file;\n+\t(*editor)->apply_textdelta = apply_textdelta;\n+\t(*editor)->close_file = close_file;\n+\t(*editor)->close_directory = close_directory;\n+\t(*editor)->change_file_prop = change_file_prop;\n+\t(*editor)->change_dir_prop = change_dir_prop;\n+\t(*editor)->close_edit = close_edit;\n+\t(*editor)->absent_directory = absent_directory;\n+\t(*editor)->absent_file = absent_file;\n+\t(*editor)->abort_edit = abort_edit;\n+\treturn SVN_NO_ERROR;\n+}\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+\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+\tSVN_ERR(svn_config_get_config(&(ctx->config), NULL, pool));\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;\n+\tsvn_error_t *err;\n+\tSVN_ERR(svn_ra_get_latest_revnum(session, &latest_revision, pool));\n+\tprintf(\"%ld\\n\", latest_revision);\n+\tSVN_ERR(setup_delta_editor(&editor));\n+\tSVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,\n+\t                            0, TRUE, replay_revstart, replay_revend, NULL, 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/subversion/trunk\";\n+\tsvn_revnum_t start_revision = 0, end_revision = 5;\n+\tif (svn_cmdline_init (\"svnclient_ra\", stderr) != EXIT_SUCCESS)\n+\t\treturn EXIT_FAILURE;\n+\tpool = svn_pool_create(NULL);\n+\n+\tif(open_connection(url) != SVN_NO_ERROR)\n+\t\treturn 1;\n+\tif(replay_range(start_revision, end_revision) != SVN_NO_ERROR)\n+\t\treturn 1;\n+\n+\tclose_connection();\n+\treturn 0;\n+}\n-- \n1.7.1\n"}]}