Author: hwright
Date: Wed Dec 5 00:49:22 2012
New Revision: 1417252
URL: http://svn.apache.org/viewvc?rev=1417252&view=rev
Log:
Manually migrate the Ev2 export implementation (in the case of recursive
directory exports) from the ev2-export branch to trunk, guarded by the
--enable-ev2-impl configure flag.
* subversion/libsvn_client/export.c
(fetch_kind_func): Remove.
(get_editor): Rename to...
(get_editor_ev1): ...this.
(add_file_ev2, add_directory_ev2, target_revision_func, get_editor_ev2): New.
(svn_client_export5): Optionally use the Ev2 implementation for directory
exports.
Modified:
subversion/trunk/subversion/libsvn_client/export.c
Modified: subversion/trunk/subversion/libsvn_client/export.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/export.c?rev=1417252&r1=1417251&r2=1417252&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/export.c (original)
+++ subversion/trunk/subversion/libsvn_client/export.c Wed Dec 5 00:49:22 2012
@@ -43,8 +43,13 @@
#include "svn_private_config.h"
#include "private/svn_subr_private.h"
+#include "private/svn_delta_private.h"
#include "private/svn_wc_private.h"
+#ifndef ENABLE_EV2_IMPL
+#define ENABLE_EV2_IMPL 0
+#endif
+
/*** Code. ***/
@@ -859,26 +864,6 @@ close_file(void *file_baton,
}
static svn_error_t *
-fetch_kind_func(svn_kind_t *kind,
- void *baton,
- const char *path,
- svn_revnum_t base_revision,
- apr_pool_t *scratch_pool)
-{
- /* We know the root of the edit is a directory. */
- if (path[0] == '\0')
- *kind = svn_kind_dir;
-
- /* ### TODO: We could possibly fetch the kind of the object in question
- from the server with a second ra_session, but right now this
- seems to work. */
- else
- *kind = svn_kind_unknown;
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
fetch_props_func(apr_hash_t **props,
void *baton,
const char *path,
@@ -908,16 +893,14 @@ fetch_base_func(const char **filename,
}
static svn_error_t *
-get_editor(const svn_delta_editor_t **export_editor,
- void **edit_baton,
- struct edit_baton *eb,
- svn_client_ctx_t *ctx,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+get_editor_ev1(const svn_delta_editor_t **export_editor,
+ void **edit_baton,
+ struct edit_baton *eb,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_delta_editor_t *editor = svn_delta_default_editor(result_pool);
- svn_delta_shim_callbacks_t *shim_callbacks =
- svn_delta_shim_callbacks_default(result_pool);
editor->set_target_revision = set_target_revision;
editor->open_root = open_root;
@@ -936,19 +919,234 @@ get_editor(const svn_delta_editor_t **ex
edit_baton,
result_pool));
- shim_callbacks->fetch_kind_func = fetch_kind_func;
- shim_callbacks->fetch_props_func = fetch_props_func;
- shim_callbacks->fetch_base_func = fetch_base_func;
- shim_callbacks->fetch_baton = eb;
-
- SVN_ERR(svn_editor__insert_shims(export_editor, edit_baton,
- *export_editor, *edit_baton,
- NULL, NULL, shim_callbacks,
- result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+
+/*** The Ev2 Implementation ***/
+
+static svn_error_t *
+add_file_ev2(void *baton,
+ const char *relpath,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ const char *full_path = svn_dirent_join(eb->root_path, relpath,
+ scratch_pool);
+ /* RELPATH is not canonicalized, i.e. it may still contain spaces etc.
+ * but EB->root_url is. */
+ const char *full_url = svn_path_url_add_component2(eb->root_url,
+ relpath,
+ scratch_pool);
+ const svn_string_t *val;
+ /* The four svn: properties we might actually care about. */
+ const svn_string_t *eol_style_val = NULL;
+ const svn_string_t *keywords_val = NULL;
+ const svn_string_t *executable_val = NULL;
+ svn_boolean_t special = FALSE;
+ /* Any keyword vals to be substituted */
+ const char *revision = NULL;
+ const char *author = NULL;
+ apr_time_t date = 0;
+
+ /* Look at any properties for additional information. */
+ if ( (val = apr_hash_get(props, SVN_PROP_EOL_STYLE, APR_HASH_KEY_STRING)) )
+ eol_style_val = val;
+
+ if ( !eb->ignore_keywords && (val = apr_hash_get(props, SVN_PROP_KEYWORDS,
+ APR_HASH_KEY_STRING)) )
+ keywords_val = val;
+
+ if ( (val = apr_hash_get(props, SVN_PROP_EXECUTABLE, APR_HASH_KEY_STRING)) )
+ executable_val = val;
+
+ /* Try to fill out the baton's keywords-structure too. */
+ if ( (val = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_REV,
+ APR_HASH_KEY_STRING)) )
+ revision = val->data;
+
+ if ( (val = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_DATE,
+ APR_HASH_KEY_STRING)) )
+ SVN_ERR(svn_time_from_cstring(&date, val->data, scratch_pool));
+
+ if ( (val = apr_hash_get(props, SVN_PROP_ENTRY_LAST_AUTHOR,
+ APR_HASH_KEY_STRING)) )
+ author = val->data;
+
+ if ( (val = apr_hash_get(props, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING)) )
+ special = TRUE;
+
+ if (special)
+ {
+ svn_stream_t *tmp_stream;
+
+ SVN_ERR(svn_subst_create_specialfile(&tmp_stream, full_path,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(contents, tmp_stream, eb->cancel_func,
+ eb->cancel_baton, scratch_pool));
+ }
+ else
+ {
+ svn_stream_t *tmp_stream;
+ const char *tmppath;
+
+ /* Create a temporary file in the same directory as the file. We're going
+ to rename the thing into place when we're done. */
+ SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmppath,
+ svn_dirent_dirname(full_path,
+ scratch_pool),
+ svn_io_file_del_none,
+ scratch_pool, scratch_pool));
+
+ /* Possibly wrap the stream to be translated, as dictated by
+ the props. */
+ if (eol_style_val || keywords_val)
+ {
+ svn_subst_eol_style_t style;
+ const char *eol = NULL;
+ svn_boolean_t repair = FALSE;
+ apr_hash_t *final_kw = NULL;
+
+ if (eol_style_val)
+ {
+ SVN_ERR(get_eol_style(&style, &eol, eol_style_val->data,
+ eb->native_eol));
+ repair = TRUE;
+ }
+
+ if (keywords_val)
+ SVN_ERR(svn_subst_build_keywords2(&final_kw, keywords_val->data,
+ revision, full_url, date,
+ author, scratch_pool));
+
+ /* Writing through a translated stream is more efficient than
+ reading through one, so we wrap TMP_STREAM and not CONTENTS. */
+ tmp_stream = svn_subst_stream_translated(tmp_stream, eol, repair,
+ final_kw, TRUE, /* expand */
+ scratch_pool);
+ }
+
+ SVN_ERR(svn_stream_copy3(contents, tmp_stream, eb->cancel_func,
+ eb->cancel_baton, scratch_pool));
+
+ /* Move the file into place. */
+ SVN_ERR(svn_io_file_rename(tmppath, full_path, scratch_pool));
+ }
+
+ if (executable_val)
+ SVN_ERR(svn_io_set_file_executable(full_path, TRUE, FALSE, scratch_pool));
+
+ if (date && (! special))
+ SVN_ERR(svn_io_set_file_affected_time(date, full_path, scratch_pool));
+
+ if (eb->notify_func)
+ {
+ svn_wc_notify_t *notify = svn_wc_create_notify(full_path,
+ svn_wc_notify_update_add,
+ scratch_pool);
+ notify->kind = svn_node_file;
+ (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ }
- return SVN_NO_ERROR;
+ return SVN_NO_ERROR;
}
+static svn_error_t *
+add_directory_ev2(void *baton,
+ const char *relpath,
+ const apr_array_header_t *children,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ svn_node_kind_t kind;
+ const char *full_path = svn_dirent_join(eb->root_path, relpath,
+ scratch_pool);
+ svn_string_t *val;
+
+ SVN_ERR(svn_io_check_path(full_path, &kind, scratch_pool));
+ if (kind == svn_node_none)
+ SVN_ERR(svn_io_dir_make(full_path, APR_OS_DEFAULT, scratch_pool));
+ else if (kind == svn_node_file)
+ return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+ _("'%s' exists and is not a directory"),
+ svn_dirent_local_style(full_path, scratch_pool));
+ else if (! (kind == svn_node_dir && eb->force))
+ return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
+ _("'%s' already exists"),
+ svn_dirent_local_style(full_path, scratch_pool));
+
+ if ( (val = apr_hash_get(props, SVN_PROP_EXTERNALS, APR_HASH_KEY_STRING)) )
+ SVN_ERR(add_externals(eb->externals, full_path, val));
+
+ if (eb->notify_func)
+ {
+ svn_wc_notify_t *notify = svn_wc_create_notify(full_path,
+ svn_wc_notify_update_add,
+ scratch_pool);
+ notify->kind = svn_node_dir;
+ (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+target_revision_func(void *baton,
+ svn_revnum_t target_revision,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+
+ *eb->target_revision = target_revision;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_editor_ev2(const svn_delta_editor_t **export_editor,
+ void **edit_baton,
+ struct edit_baton *eb,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_editor_t *editor;
+ struct svn_delta__extra_baton *exb = apr_pcalloc(result_pool, sizeof(*exb));
+ svn_boolean_t *found_abs_paths = apr_palloc(result_pool,
+ sizeof(*found_abs_paths));
+
+ exb->baton = eb;
+ exb->target_revision = target_revision_func;
+
+ SVN_ERR(svn_editor_create(&editor, eb, ctx->cancel_func, ctx->cancel_baton,
+ result_pool, scratch_pool));
+ SVN_ERR(svn_editor_setcb_add_directory(editor, add_directory_ev2,
+ scratch_pool));
+ SVN_ERR(svn_editor_setcb_add_file(editor, add_file_ev2, scratch_pool));
+
+ *found_abs_paths = TRUE;
+
+ SVN_ERR(svn_delta__delta_from_editor(export_editor, edit_baton,
+ editor, NULL, NULL, found_abs_paths,
+ NULL, NULL,
+ fetch_props_func, eb,
+ fetch_base_func, eb,
+ exb, result_pool));
+
+ /* Create the root of the export. */
+ SVN_ERR(open_root_internal(eb->root_path, eb->force, eb->notify_func,
+ eb->notify_baton, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
/*** Public Interfaces ***/
@@ -1087,8 +1285,12 @@ svn_client_export5(svn_revnum_t *result_
void *report_baton;
svn_boolean_t use_sleep = FALSE;
- SVN_ERR(get_editor(&export_editor, &edit_baton, eb, ctx,
- pool, pool));
+ if (!ENABLE_EV2_IMPL)
+ SVN_ERR(get_editor_ev1(&export_editor, &edit_baton, eb, ctx,
+ pool, pool));
+ else
+ SVN_ERR(get_editor_ev2(&export_editor, &edit_baton, eb, ctx,
+ pool, pool));
/* Manufacture a basic 'report' to the update reporter. */
SVN_ERR(svn_ra_do_update2(ra_session,