You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/04/15 16:37:04 UTC
svn commit: r1673785 - in /subversion/trunk/subversion:
include/private/svn_client_private.h libsvn_client/client.h svnbench/cl.h
svnbench/null-blame-cmd.c svnbench/svnbench.c
Author: rhuijben
Date: Wed Apr 15 14:37:04 2015
New Revision: 1673785
URL: http://svn.apache.org/r1673785
Log:
Introduce a 'null-blame' command in svnbench.
Suggested by: jcorvel
* subversion/include/private/svn_client_private.h
(svn_client__get_revision_number): Declare function here.
* subversion/libsvn_client/client.h
(svn_client__get_revision_number): ... instead of here.
* subversion/svnbench/cl.h
(svn_cl__null_blame): New function.
* subversion/svnbench/null-blame-cmd.c
New file.
* subversion/svnbench/svnbench.c
(svn_cl__cmd_table): Declare null-bench.
Added:
subversion/trunk/subversion/svnbench/null-blame-cmd.c (with props)
Modified:
subversion/trunk/subversion/include/private/svn_client_private.h
subversion/trunk/subversion/libsvn_client/client.h
subversion/trunk/subversion/svnbench/cl.h
subversion/trunk/subversion/svnbench/svnbench.c
Modified: subversion/trunk/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1673785&r1=1673784&r2=1673785&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_client_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_client_private.h Wed Apr 15 14:37:04 2015
@@ -40,6 +40,51 @@ extern "C" {
#endif /* __cplusplus */
+/* Set *REVNUM to the revision number identified by REVISION.
+
+ If REVISION->kind is svn_opt_revision_number, just use
+ REVISION->value.number, ignoring LOCAL_ABSPATH and RA_SESSION.
+
+ Else if REVISION->kind is svn_opt_revision_committed,
+ svn_opt_revision_previous, or svn_opt_revision_base, or
+ svn_opt_revision_working, then the revision can be identified
+ purely based on the working copy's administrative information for
+ LOCAL_ABSPATH, so RA_SESSION is ignored. If LOCAL_ABSPATH is not
+ under revision control, return SVN_ERR_UNVERSIONED_RESOURCE, or if
+ LOCAL_ABSPATH is null, return SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED.
+
+ Else if REVISION->kind is svn_opt_revision_date or
+ svn_opt_revision_head, then RA_SESSION is used to retrieve the
+ revision from the repository (using REVISION->value.date in the
+ former case), and LOCAL_ABSPATH is ignored. If RA_SESSION is null,
+ return SVN_ERR_CLIENT_RA_ACCESS_REQUIRED.
+
+ Else if REVISION->kind is svn_opt_revision_unspecified, set
+ *REVNUM to SVN_INVALID_REVNUM.
+
+ If YOUNGEST_REV is non-NULL, it is an in/out parameter. If
+ *YOUNGEST_REV is valid, use it as the youngest revision in the
+ repository (regardless of reality) -- don't bother to lookup the
+ true value for HEAD, and don't return any value in *REVNUM greater
+ than *YOUNGEST_REV. If *YOUNGEST_REV is not valid, and a HEAD
+ lookup is required to populate *REVNUM, then also populate
+ *YOUNGEST_REV with the result. This is useful for making multiple
+ serialized calls to this function with a basically static view of
+ the repository, avoiding race conditions which could occur between
+ multiple invocations with HEAD lookup requests.
+
+ Else return SVN_ERR_CLIENT_BAD_REVISION.
+
+ Use SCRATCH_POOL for any temporary allocation. */
+svn_error_t *
+svn_client__get_revision_number(svn_revnum_t *revnum,
+ svn_revnum_t *youngest_rev,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_ra_session_t *ra_session,
+ const svn_opt_revision_t *revision,
+ apr_pool_t *scratch_pool);
+
/* Return true if KIND is a revision kind that is dependent on the working
* copy. Otherwise, return false. */
#define SVN_CLIENT__REVKIND_NEEDS_WC(kind) \
Modified: subversion/trunk/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/client.h?rev=1673785&r1=1673784&r2=1673785&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/client.h (original)
+++ subversion/trunk/subversion/libsvn_client/client.h Wed Apr 15 14:37:04 2015
@@ -73,52 +73,6 @@ typedef struct svn_client__private_ctx_t
svn_client__private_ctx_t *
svn_client__get_private_ctx(svn_client_ctx_t *ctx);
-
-/* Set *REVNUM to the revision number identified by REVISION.
-
- If REVISION->kind is svn_opt_revision_number, just use
- REVISION->value.number, ignoring LOCAL_ABSPATH and RA_SESSION.
-
- Else if REVISION->kind is svn_opt_revision_committed,
- svn_opt_revision_previous, or svn_opt_revision_base, or
- svn_opt_revision_working, then the revision can be identified
- purely based on the working copy's administrative information for
- LOCAL_ABSPATH, so RA_SESSION is ignored. If LOCAL_ABSPATH is not
- under revision control, return SVN_ERR_UNVERSIONED_RESOURCE, or if
- LOCAL_ABSPATH is null, return SVN_ERR_CLIENT_VERSIONED_PATH_REQUIRED.
-
- Else if REVISION->kind is svn_opt_revision_date or
- svn_opt_revision_head, then RA_SESSION is used to retrieve the
- revision from the repository (using REVISION->value.date in the
- former case), and LOCAL_ABSPATH is ignored. If RA_SESSION is null,
- return SVN_ERR_CLIENT_RA_ACCESS_REQUIRED.
-
- Else if REVISION->kind is svn_opt_revision_unspecified, set
- *REVNUM to SVN_INVALID_REVNUM.
-
- If YOUNGEST_REV is non-NULL, it is an in/out parameter. If
- *YOUNGEST_REV is valid, use it as the youngest revision in the
- repository (regardless of reality) -- don't bother to lookup the
- true value for HEAD, and don't return any value in *REVNUM greater
- than *YOUNGEST_REV. If *YOUNGEST_REV is not valid, and a HEAD
- lookup is required to populate *REVNUM, then also populate
- *YOUNGEST_REV with the result. This is useful for making multiple
- serialized calls to this function with a basically static view of
- the repository, avoiding race conditions which could occur between
- multiple invocations with HEAD lookup requests.
-
- Else return SVN_ERR_CLIENT_BAD_REVISION.
-
- Use SCRATCH_POOL for any temporary allocation. */
-svn_error_t *
-svn_client__get_revision_number(svn_revnum_t *revnum,
- svn_revnum_t *youngest_rev,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- svn_ra_session_t *ra_session,
- const svn_opt_revision_t *revision,
- apr_pool_t *scratch_pool);
-
/* Set *ORIGINAL_REPOS_RELPATH and *ORIGINAL_REVISION to the original location
that served as the source of the copy from which PATH_OR_URL at REVISION was
created, or NULL and SVN_INVALID_REVNUM (respectively) if PATH_OR_URL at
Modified: subversion/trunk/subversion/svnbench/cl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnbench/cl.h?rev=1673785&r1=1673784&r2=1673785&view=diff
==============================================================================
--- subversion/trunk/subversion/svnbench/cl.h (original)
+++ subversion/trunk/subversion/svnbench/cl.h Wed Apr 15 14:37:04 2015
@@ -109,6 +109,7 @@ typedef struct svn_cl__cmd_baton_t
/* Declare all the command procedures */
svn_opt_subcommand_t
svn_cl__help,
+ svn_cl__null_blame,
svn_cl__null_export,
svn_cl__null_list,
svn_cl__null_log,
Added: subversion/trunk/subversion/svnbench/null-blame-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnbench/null-blame-cmd.c?rev=1673785&view=auto
==============================================================================
--- subversion/trunk/subversion/svnbench/null-blame-cmd.c (added)
+++ subversion/trunk/subversion/svnbench/null-blame-cmd.c Wed Apr 15 14:37:04 2015
@@ -0,0 +1,284 @@
+/*
+ * null-blame-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_cmdline.h"
+#include "svn_error.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_pools.h"
+#include "svn_sorts.h"
+#include "cl.h"
+
+#include "svn_private_config.h"
+#include "private/svn_string_private.h"
+#include "private/svn_client_private.h"
+
+struct file_rev_baton {
+ apr_int64_t byte_count;
+ apr_int64_t delta_count;
+ apr_int64_t rev_count;
+};
+
+/* Implements svn_txdelta_window_handler_t */
+static svn_error_t *
+delta_handler(svn_txdelta_window_t *window, void *baton)
+{
+ struct file_rev_baton *frb = baton;
+
+ if (window != NULL)
+ frb->byte_count += window->tview_len;
+
+ return SVN_NO_ERROR;
+}
+
+/* Implementes svn_file_rev_handler_t */
+static svn_error_t *
+file_rev_handler(void *baton, const char *path, svn_revnum_t revnum,
+ apr_hash_t *rev_props,
+ svn_boolean_t merged_revision,
+ svn_txdelta_window_handler_t *content_delta_handler,
+ void **content_delta_baton,
+ apr_array_header_t *prop_diffs,
+ apr_pool_t *pool)
+{
+ struct file_rev_baton *frb = baton;
+
+ frb->rev_count++;
+
+ if (content_delta_handler)
+ {
+ *content_delta_handler = delta_handler;
+ *content_delta_baton = baton;
+ frb->delta_count++;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+bench_null_blame(const char *target,
+ const svn_opt_revision_t *peg_revision,
+ const svn_opt_revision_t *start,
+ const svn_opt_revision_t *end,
+ svn_boolean_t include_merged_revisions,
+ svn_boolean_t quiet,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ struct file_rev_baton frb = { 0, 0, 0};
+ svn_ra_session_t *ra_session;
+ svn_revnum_t start_revnum, end_revnum;
+ svn_boolean_t backwards;
+ const char *target_abspath_or_url;
+
+ if (start->kind == svn_opt_revision_unspecified
+ || end->kind == svn_opt_revision_unspecified)
+ return svn_error_create
+ (SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
+
+ if (svn_path_is_url(target))
+ target_abspath_or_url = target;
+ else
+ SVN_ERR(svn_dirent_get_absolute(&target_abspath_or_url, target, pool));
+
+
+ /* Get an RA plugin for this filesystem object. */
+ SVN_ERR(svn_client__ra_session_from_path2(&ra_session, NULL,
+ target, NULL, peg_revision,
+ peg_revision,
+ ctx, pool));
+
+ SVN_ERR(svn_client__get_revision_number(&start_revnum, NULL, ctx->wc_ctx,
+ target_abspath_or_url, ra_session,
+ start, pool));
+
+ SVN_ERR(svn_client__get_revision_number(&end_revnum, NULL, ctx->wc_ctx,
+ target_abspath_or_url, ra_session,
+ end, pool));
+
+ {
+ svn_client__pathrev_t *loc;
+ svn_opt_revision_t younger_end;
+ younger_end.kind = svn_opt_revision_number;
+ younger_end.value.number = MAX(start_revnum, end_revnum);
+
+ SVN_ERR(svn_client__resolve_rev_and_url(&loc, ra_session,
+ target, peg_revision,
+ &younger_end,
+ ctx, pool));
+
+ /* Make the session point to the real URL. */
+ SVN_ERR(svn_ra_reparent(ra_session, loc->url, pool));
+ }
+
+ backwards = (start_revnum > end_revnum);
+
+ /* Collect all blame information.
+ We need to ensure that we get one revision before the start_rev,
+ if available so that we can know what was actually changed in the start
+ revision. */
+ SVN_ERR(svn_ra_get_file_revs2(ra_session, "",
+ backwards ? start_revnum
+ : MAX(0, start_revnum-1),
+ end_revnum,
+ include_merged_revisions,
+ file_rev_handler, &frb, pool));
+
+ if (!quiet)
+ SVN_ERR(svn_cmdline_printf(pool,
+ _("%15s revisions\n"
+ "%15s deltas\n"
+ "%15s bytes in deltas\n"),
+ svn__ui64toa_sep(frb.rev_count, ',', pool),
+ svn__ui64toa_sep(frb.delta_count, ',', pool),
+ svn__ui64toa_sep(frb.byte_count, ',', pool)));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_cl__null_blame(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;
+ apr_pool_t *iterpool;
+ apr_array_header_t *targets;
+ int i;
+ svn_boolean_t end_revision_unspecified = FALSE;
+ svn_diff_file_options_t *diff_options = svn_diff_file_options_create(pool);
+ svn_boolean_t seen_nonexistent_target = FALSE;
+
+ SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
+ opt_state->targets,
+ ctx, FALSE, pool));
+
+ /* Blame needs a file on which to operate. */
+ if (! targets->nelts)
+ return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
+
+ if (opt_state->end_revision.kind == svn_opt_revision_unspecified)
+ {
+ if (opt_state->start_revision.kind != svn_opt_revision_unspecified)
+ {
+ /* In the case that -rX was specified, we actually want to set the
+ range to be -r1:X. */
+
+ opt_state->end_revision = opt_state->start_revision;
+ opt_state->start_revision.kind = svn_opt_revision_number;
+ opt_state->start_revision.value.number = 1;
+ }
+ else
+ end_revision_unspecified = TRUE;
+ }
+
+ if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
+ {
+ opt_state->start_revision.kind = svn_opt_revision_number;
+ opt_state->start_revision.value.number = 1;
+ }
+
+ /* The final conclusion from issue #2431 is that blame info
+ is client output (unlike 'svn cat' which plainly cats the file),
+ so the EOL style should be the platform local one.
+ */
+ iterpool = svn_pool_create(pool);
+
+ if (opt_state->extensions)
+ {
+ apr_array_header_t *opts;
+ opts = svn_cstring_split(opt_state->extensions, " \t\n\r", TRUE, pool);
+ SVN_ERR(svn_diff_file_options_parse(diff_options, opts, pool));
+ }
+
+ for (i = 0; i < targets->nelts; i++)
+ {
+ svn_error_t *err;
+ const char *target = APR_ARRAY_IDX(targets, i, const char *);
+ const char *parsed_path;
+ svn_opt_revision_t peg_revision;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
+
+ /* Check for a peg revision. */
+ SVN_ERR(svn_opt_parse_path(&peg_revision, &parsed_path, target,
+ iterpool));
+
+ if (end_revision_unspecified)
+ {
+ if (peg_revision.kind != svn_opt_revision_unspecified)
+ opt_state->end_revision = peg_revision;
+ else if (svn_path_is_url(target))
+ opt_state->end_revision.kind = svn_opt_revision_head;
+ else
+ opt_state->end_revision.kind = svn_opt_revision_working;
+ }
+
+ err = bench_null_blame(parsed_path,
+ &peg_revision,
+ &opt_state->start_revision,
+ &opt_state->end_revision,
+ opt_state->use_merge_history,
+ opt_state->quiet,
+ ctx,
+ iterpool);
+
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
+ err->apr_err == SVN_ERR_ENTRY_NOT_FOUND ||
+ err->apr_err == SVN_ERR_FS_NOT_FILE ||
+ err->apr_err == SVN_ERR_FS_NOT_FOUND)
+ {
+ svn_handle_warning2(stderr, err, "svn: ");
+ svn_error_clear(err);
+ err = NULL;
+ seen_nonexistent_target = TRUE;
+ }
+ else
+ {
+ return svn_error_trace(err);
+ }
+ }
+ }
+ svn_pool_destroy(iterpool);
+
+ if (seen_nonexistent_target)
+ return svn_error_create(
+ SVN_ERR_ILLEGAL_TARGET, NULL,
+ _("Could not perform blame on all targets because some "
+ "targets don't exist"));
+ else
+ return SVN_NO_ERROR;
+}
Propchange: subversion/trunk/subversion/svnbench/null-blame-cmd.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/trunk/subversion/svnbench/svnbench.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnbench/svnbench.c?rev=1673785&r1=1673784&r2=1673785&view=diff
==============================================================================
--- subversion/trunk/subversion/svnbench/svnbench.c (original)
+++ subversion/trunk/subversion/svnbench/svnbench.c Wed Apr 15 14:37:04 2015
@@ -219,6 +219,26 @@ const svn_opt_subcommand_desc2_t svn_cl_
{0} },
/* This command is also invoked if we see option "--help", "-h" or "-?". */
+ { "null-blame", svn_cl__null_blame, {0}, N_
+ ("Fetch all versions of a file in a batch.\n"
+ "usage: null-blame [-rM:N] TARGET[@REV]...\n"
+ "\n"
+ " With no revision range (same as -r0:REV), or with '-r M:N' where M < N,\n"
+ " annotate each line that is present in revision N of the file, with\n"
+ " the last revision at or before rN that changed or added the line,\n"
+ " looking back no further than rM.\n"
+ "\n"
+ " With a reverse revision range '-r M:N' where M > N,\n"
+ " annotate each line that is present in revision N of the file, with\n"
+ " the next revision after rN that changed or deleted the line,\n"
+ " looking forward no further than rM.\n"
+ "\n"
+ " If specified, REV determines in which revision the target is first\n"
+ " looked up.\n"
+ "\n"
+ " Write the annotated result to standard output.\n"),
+ {'r', 'g'} },
+
{ "null-export", svn_cl__null_export, {0}, N_
("Create an unversioned copy of a tree.\n"
"usage: null-export [-r REV] URL[@PEGREV]\n"