summaryrefslogtreecommitdiff
path: root/subversion/svnbench/null-export-cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svnbench/null-export-cmd.c')
-rw-r--r--subversion/svnbench/null-export-cmd.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/subversion/svnbench/null-export-cmd.c b/subversion/svnbench/null-export-cmd.c
new file mode 100644
index 0000000..8220bfb
--- /dev/null
+++ b/subversion/svnbench/null-export-cmd.c
@@ -0,0 +1,346 @@
+/*
+ * export-cmd.c -- Subversion export command
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_client.h"
+#include "svn_error.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_cmdline.h"
+#include "cl.h"
+
+#include "svn_private_config.h"
+#include "private/svn_string_private.h"
+#include "private/svn_client_private.h"
+
+/*** The export editor code. ***/
+
+/* ---------------------------------------------------------------------- */
+
+/*** A dedicated 'export' editor, which does no .svn/ accounting. ***/
+
+typedef struct edit_baton_t
+{
+ apr_int64_t file_count;
+ apr_int64_t dir_count;
+ apr_int64_t byte_count;
+ apr_int64_t prop_count;
+ apr_int64_t prop_byte_count;
+} edit_baton_t;
+
+static svn_error_t *
+set_target_revision(void *edit_baton,
+ svn_revnum_t target_revision,
+ apr_pool_t *pool)
+{
+ return SVN_NO_ERROR;
+}
+
+
+/* Just ensure that the main export directory exists. */
+static svn_error_t *
+open_root(void *edit_baton,
+ svn_revnum_t base_revision,
+ apr_pool_t *pool,
+ void **root_baton)
+{
+ *root_baton = edit_baton;
+ return SVN_NO_ERROR;
+}
+
+
+/* Ensure the directory exists, and send feedback. */
+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 **baton)
+{
+ edit_baton_t *eb = parent_baton;
+ eb->dir_count++;
+
+ *baton = parent_baton;
+ return SVN_NO_ERROR;
+}
+
+
+/* Build a file baton. */
+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 **baton)
+{
+ edit_baton_t *eb = parent_baton;
+ eb->file_count++;
+
+ *baton = parent_baton;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+window_handler(svn_txdelta_window_t *window, void *baton)
+{
+ edit_baton_t *eb = baton;
+ if (window != NULL)
+ eb->byte_count += window->tview_len;
+
+ return SVN_NO_ERROR;
+}
+
+/* Write incoming data into the tmpfile stream */
+
+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)
+{
+ *handler_baton = file_baton;
+ *handler = window_handler;
+
+ 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)
+{
+ edit_baton_t *eb = file_baton;
+ eb->prop_count++;
+ eb->prop_byte_count += value->len;
+
+ 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)
+{
+ edit_baton_t *eb = dir_baton;
+ eb->prop_count++;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+close_file(void *file_baton,
+ const char *text_checksum,
+ apr_pool_t *pool)
+{
+ return SVN_NO_ERROR;
+}
+
+
+/*** Public Interfaces ***/
+
+static svn_error_t *
+bench_null_export(svn_revnum_t *result_rev,
+ const char *from_path_or_url,
+ svn_opt_revision_t *peg_revision,
+ svn_opt_revision_t *revision,
+ svn_depth_t depth,
+ void *baton,
+ svn_client_ctx_t *ctx,
+ svn_boolean_t quiet,
+ apr_pool_t *pool)
+{
+ svn_revnum_t edit_revision = SVN_INVALID_REVNUM;
+ svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
+
+ SVN_ERR_ASSERT(peg_revision != NULL);
+ SVN_ERR_ASSERT(revision != NULL);
+
+ if (peg_revision->kind == svn_opt_revision_unspecified)
+ peg_revision->kind = svn_path_is_url(from_path_or_url)
+ ? svn_opt_revision_head
+ : svn_opt_revision_working;
+
+ if (revision->kind == svn_opt_revision_unspecified)
+ revision = peg_revision;
+
+ if (from_is_url || ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
+ {
+ svn_client__pathrev_t *loc;
+ svn_ra_session_t *ra_session;
+ svn_node_kind_t kind;
+
+ /* Get the RA connection. */
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
+ from_path_or_url, NULL,
+ peg_revision,
+ revision, ctx, pool));
+
+ SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, pool));
+
+ if (kind == svn_node_file)
+ {
+ apr_hash_t *props;
+
+ /* Since you cannot actually root an editor at a file, we
+ * manually drive a few functions of our editor. */
+
+ /* Step outside the editor-likeness for a moment, to actually talk
+ * to the repository. */
+ /* ### note: the stream will not be closed */
+ SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
+ svn_stream_empty(pool),
+ NULL, &props, pool));
+ }
+ else if (kind == svn_node_dir)
+ {
+ void *edit_baton = NULL;
+ const svn_delta_editor_t *export_editor = NULL;
+ const svn_ra_reporter3_t *reporter;
+ void *report_baton;
+
+ svn_delta_editor_t *editor = svn_delta_default_editor(pool);
+
+ editor->set_target_revision = set_target_revision;
+ editor->open_root = open_root;
+ editor->add_directory = add_directory;
+ editor->add_file = add_file;
+ editor->apply_textdelta = apply_textdelta;
+ editor->close_file = close_file;
+ editor->change_file_prop = change_file_prop;
+ editor->change_dir_prop = change_dir_prop;
+
+ /* for ra_svn, we don't need an editior in quiet mode */
+ if (!quiet || strncmp(loc->repos_root_url, "svn:", 4))
+ SVN_ERR(svn_delta_get_cancellation_editor(ctx->cancel_func,
+ ctx->cancel_baton,
+ editor,
+ baton,
+ &export_editor,
+ &edit_baton,
+ pool));
+
+ /* Manufacture a basic 'report' to the update reporter. */
+ SVN_ERR(svn_ra_do_update3(ra_session,
+ &reporter, &report_baton,
+ loc->rev,
+ "", /* no sub-target */
+ depth,
+ FALSE, /* don't want copyfrom-args */
+ FALSE, /* don't want ignore_ancestry */
+ export_editor, edit_baton,
+ pool, pool));
+
+ SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
+ /* Depth is irrelevant, as we're
+ passing start_empty=TRUE anyway. */
+ svn_depth_infinity,
+ TRUE, /* "help, my dir is empty!" */
+ NULL, pool));
+
+ SVN_ERR(reporter->finish_report(report_baton, pool));
+ }
+ else if (kind == svn_node_none)
+ {
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("URL '%s' doesn't exist"),
+ from_path_or_url);
+ }
+ /* kind == svn_node_unknown not handled */
+ }
+
+
+ if (result_rev)
+ *result_rev = edit_revision;
+
+ return SVN_NO_ERROR;
+}
+
+
+/*** Code. ***/
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_cl__null_export(apr_getopt_t *os,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+ svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
+ const char *from;
+ apr_array_header_t *targets;
+ svn_error_t *err;
+ svn_opt_revision_t peg_revision;
+ const char *truefrom;
+ edit_baton_t eb = { 0 };
+
+ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
+ opt_state->targets,
+ ctx, FALSE, pool));
+
+ /* We want exactly 1 or 2 targets for this subcommand. */
+ if (targets->nelts < 1)
+ return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
+ if (targets->nelts > 2)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL);
+
+ /* The first target is the `from' path. */
+ from = APR_ARRAY_IDX(targets, 0, const char *);
+
+ /* Get the peg revision if present. */
+ SVN_ERR(svn_opt_parse_path(&peg_revision, &truefrom, from, pool));
+
+ if (opt_state->depth == svn_depth_unknown)
+ opt_state->depth = svn_depth_infinity;
+
+ /* Do the export. */
+ err = bench_null_export(NULL, truefrom, &peg_revision,
+ &(opt_state->start_revision),
+ opt_state->depth,
+ &eb,
+ ctx, opt_state->quiet, pool);
+
+ if (!opt_state->quiet)
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("%15s directories\n"
+ "%15s files\n"
+ "%15s bytes in files\n"
+ "%15s properties\n"
+ "%15s bytes in properties\n"),
+ svn__ui64toa_sep(eb.dir_count, ',', pool),
+ svn__ui64toa_sep(eb.file_count, ',', pool),
+ svn__ui64toa_sep(eb.byte_count, ',', pool),
+ svn__ui64toa_sep(eb.prop_count, ',', pool),
+ svn__ui64toa_sep(eb.prop_byte_count, ',', pool)));
+
+ return svn_error_trace(err);
+}