Author: stefan2
Date: Thu Nov 27 22:16:52 2014
New Revision: 1642242
URL: http://svn.apache.org/r1642242
Log:
On the svn-mergeinfo-normalizer branch: Commit initial code.
* tools/svn-mergeinfo-normalizer: New folder.
* tools/svn-mergeinfo-normalizer/mergeinfo-normalizer.h,
tools/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c: New tool main
files.
* tools/svn-mergeinfo-normalizer/analyze-cmd.c,
tools/svn-mergeinfo-normalizer/clear-obsolete-cmd.c,
tools/svn-mergeinfo-normalizer/combine-ranges-cmd.c,
tools/svn-mergeinfo-normalizer/help-cmd.c,
tools/svn-mergeinfo-normalizer/normalize-cmd.c: New sub-commands.
* tools/svn-mergeinfo-normalizer/log.c,
tools/svn-mergeinfo-normalizer/util.c,
tools/svn-mergeinfo-normalizer/wc_mergeinfo.c: New queries, utils and data
models.
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/analyze-cmd.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/clear-obsolete-cmd.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/combine-ranges-cmd.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/help-cmd.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/normalize-cmd.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/util.c
(with props)
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c
(with props)
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/analyze-cmd.c
URL:
http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/analyze-cmd.c?rev=1642242&view=auto
==============================================================================
---
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/analyze-cmd.c
(added)
+++
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/analyze-cmd.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,410 @@
+/*
+ * analyze-cmd.c -- Print which MI can be elided, which one can not and why
+ *
+ * ====================================================================
+ * 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_cmdline.h"
+#include "svn_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_path.h"
+#include "svn_pools.h"
+#include "svn_sorts.h"
+#include "private/svn_fspath.h"
+#include "private/svn_sorts_private.h"
+
+#include "mergeinfo-normalizer.h"
+
+#include "svn_private_config.h"
+
+
+/*** Code. ***/
+
+static svn_error_t *
+remove_obsolete_lines(svn_ra_session_t *session,
+ svn_mergeinfo_t mergeinfo,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_array_header_t *to_remove
+ = apr_array_make(scratch_pool, 16, sizeof(const char *));
+
+ int i;
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(scratch_pool, mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *path = apr_hash_this_key(hi);
+ svn_node_kind_t kind;
+
+ SVN_ERR_ASSERT(*path == '/');
+ SVN_ERR(svn_ra_check_path(session, path + 1, SVN_INVALID_REVNUM, &kind,
+ scratch_pool));
+ if (kind == svn_node_none)
+ APR_ARRAY_PUSH(to_remove, const char *) = path;
+ }
+
+ svn_sort__array(to_remove, svn_sort_compare_paths);
+ if (to_remove->nelts)
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" %d branches don't exist in HEAD:\n"),
+ to_remove->nelts));
+
+ for (i = 0; i < to_remove->nelts; ++i)
+ {
+ const char *path;
+ svn_pool_clear(iterpool);
+
+ path = APR_ARRAY_IDX(to_remove, i, const char *);
+ svn_hash_sets(mergeinfo, path, NULL);
+
+ SVN_ERR(svn_cmdline_printf(iterpool, _(" %s\n"), path));
+ }
+ }
+ else
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" All branches still exist in HEAD.\n")));
+ }
+
+ SVN_ERR(svn_cmdline_printf(iterpool, _("\n")));
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+static svn_rangelist_t *
+find_reverse_ranges(svn_rangelist_t *ranges,
+ apr_pool_t *result_pool)
+{
+ svn_rangelist_t *result = apr_array_make(result_pool, 0, ranges->elt_size);
+
+ int i;
+ for (i = 0; i < ranges->nelts; ++i)
+ {
+ const svn_merge_range_t *range
+ = APR_ARRAY_IDX(ranges, i, const svn_merge_range_t *);
+
+ if (range->start >= range->end)
+ APR_ARRAY_PUSH(result, const svn_merge_range_t *) = range;
+ }
+
+ return result;
+}
+
+static svn_error_t *
+print_ranges(svn_rangelist_t *ranges,
+ const char *title,
+ apr_pool_t *scratch_pool)
+{
+ svn_string_t *string;
+
+ SVN_ERR(svn_rangelist_to_string(&string, ranges, scratch_pool));
+ SVN_ERR(svn_cmdline_printf(scratch_pool, _(" %s%s\n"),
+ title, string->data));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+remove_lines(svn_min__log_t *log,
+ const char *relpath,
+ svn_mergeinfo_t parent_mergeinfo,
+ svn_mergeinfo_t subtree_mergeinfo,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool;
+ apr_hash_index_t *hi;
+ apr_hash_t *processed;
+ svn_boolean_t needs_header = TRUE;
+
+ if (apr_hash_count(subtree_mergeinfo) == 0)
+ return SVN_NO_ERROR;
+
+ iterpool = svn_pool_create(scratch_pool);
+ processed = apr_hash_make(scratch_pool);
+
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" Try to elide remaining branches:\n")));
+
+ for (hi = apr_hash_first(scratch_pool, parent_mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *parent_path, *subtree_path;
+ svn_rangelist_t *parent_ranges, *subtree_ranges, *reverse_ranges;
+ svn_rangelist_t *subtree_only, *parent_only;
+ svn_rangelist_t *operative_outside_subtree, *operative_in_subtree;
+
+ svn_pool_clear(iterpool);
+
+ parent_path = apr_hash_this_key(hi);
+ subtree_path = svn_fspath__join(parent_path, relpath, scratch_pool);
+ parent_ranges = apr_hash_this_val(hi);
+ subtree_ranges = svn_hash_gets(subtree_mergeinfo, subtree_path);
+
+ if (!subtree_ranges)
+ continue;
+
+ svn_hash_sets(processed, subtree_path, subtree_path);
+
+ reverse_ranges = find_reverse_ranges(subtree_ranges, iterpool);
+ if (reverse_ranges->nelts)
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" Reverse range(s) found for %s:\n"),
+ subtree_path));
+ SVN_ERR(print_ranges(reverse_ranges, "", iterpool));
+ continue;
+ }
+
+ SVN_ERR(svn_rangelist_diff(&parent_only, &subtree_only,
+ parent_ranges, subtree_ranges, TRUE,
+ iterpool));
+ subtree_only
+ = svn_min__operative(log, subtree_path, subtree_only, iterpool);
+
+ if (!subtree_only->nelts && !parent_only->nelts)
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" elide redundant branch %s\n"),
+ subtree_path));
+ svn_hash_sets(subtree_mergeinfo, subtree_path, NULL);
+ continue;
+ }
+
+ operative_outside_subtree
+ = svn_min__operative_outside_subtree(log, parent_path, subtree_path,
+ subtree_only, iterpool);
+ operative_in_subtree
+ = svn_min__operative(log, subtree_path, parent_only, iterpool);
+
+ if (operative_outside_subtree->nelts || operative_in_subtree->nelts)
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" CANNOT elide branch %s\n"),
+ subtree_path));
+ if (operative_outside_subtree->nelts)
+ SVN_ERR(print_ranges(operative_outside_subtree,
+ _("revisions not movable to parent: "),
+ iterpool));
+ if (operative_in_subtree->nelts)
+ SVN_ERR(print_ranges(operative_in_subtree,
+ _("revisions missing in sub-node: "),
+ iterpool));
+ }
+ else
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" elide branch %s\n"),
+ subtree_path));
+ if (subtree_only->nelts)
+ SVN_ERR(print_ranges(subtree_only,
+ _("revisions moved to parent: "),
+ iterpool));
+ if (parent_only->nelts)
+ SVN_ERR(print_ranges(parent_only,
+ _("revisions inoperative in sub-node: "),
+ iterpool));
+
+ SVN_ERR(svn_rangelist_merge2(parent_ranges, subtree_only,
+ parent_ranges->pool, iterpool));
+ svn_hash_sets(subtree_mergeinfo, subtree_path, NULL);
+ }
+ }
+
+
+ for (hi = apr_hash_first(scratch_pool, subtree_mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *path = apr_hash_this_key(hi);
+ svn_pool_clear(iterpool);
+
+ if (!svn_hash_gets(processed, path))
+ {
+ if (needs_header)
+ {
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _("\n Branches not mentioned in parent:\n")));
+ needs_header = FALSE;
+ }
+
+ SVN_ERR(svn_cmdline_printf(iterpool, (" %s\n"), path));
+ }
+ }
+
+ SVN_ERR(svn_cmdline_printf(iterpool, "\n"));
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+analyze(svn_ra_session_t *session,
+ apr_array_header_t *wc_mergeinfo,
+ svn_min__log_t *log,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ int i;
+ for (i = wc_mergeinfo->nelts - 1; i >= 0; --i)
+ {
+ const char *parent_path;
+ const char *relpath;
+ svn_mergeinfo_t parent_mergeinfo;
+ svn_mergeinfo_t subtree_mergeinfo;
+
+ if (svn_min__get_mergeinfo_pair(&parent_path, &relpath,
+ &parent_mergeinfo, &subtree_mergeinfo,
+ wc_mergeinfo, i))
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _("Trying to elide mergeinfo from path\n"
+ " %s\n"
+ " into mergeinfo at path\n"
+ " %s\n\n"),
+ svn_dirent_join(parent_path, relpath,
+ iterpool),
+ parent_path));
+ }
+ else
+ {
+ parent_mergeinfo = NULL;
+ subtree_mergeinfo = svn_min__get_mergeinfo(wc_mergeinfo, i);
+
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _("Trying to elide mergeinfo at path\n"
+ " %s\n\n"),
+ svn_min__get_mergeinfo_path(wc_mergeinfo,
+ i)));
+ }
+
+ svn_pool_clear(iterpool);
+
+ subtree_mergeinfo = svn_mergeinfo_dup(subtree_mergeinfo, iterpool);
+ SVN_ERR(remove_obsolete_lines(session, subtree_mergeinfo, iterpool));
+
+ if (parent_mergeinfo)
+ {
+ parent_mergeinfo = svn_mergeinfo_dup(parent_mergeinfo, iterpool);
+ SVN_ERR(remove_lines(log, relpath, parent_mergeinfo,
+ subtree_mergeinfo, iterpool));
+ }
+
+ if (apr_hash_count(subtree_mergeinfo))
+ {
+ apr_hash_index_t *hi;
+
+ if (parent_mergeinfo)
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" Sub-tree merge info cannot be elided due to "
+ "the following branches:\n")));
+ else
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" Merge info kept for the following branches:\n")));
+
+ for (hi = apr_hash_first(scratch_pool, subtree_mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *branch = apr_hash_this_key(hi);
+ SVN_ERR(svn_cmdline_printf(iterpool, _(" %s\n"), branch));
+ }
+
+ SVN_ERR(svn_cmdline_printf(iterpool, _("\n")));
+ }
+ else
+ {
+ SVN_ERR(svn_cmdline_printf(iterpool,
+ _(" All sub-tree mergeinfo can be elided.\n\n")));
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_min__analyze(apr_getopt_t *os,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_min__cmd_baton_t *cmd_baton = baton;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_pool_t *subpool = svn_pool_create(pool);
+
+ int i;
+ for (i = 0; i < cmd_baton->opt_state->targets->nelts; i++)
+ {
+ svn_ra_session_t *session;
+ apr_array_header_t *wc_mergeinfo;
+ svn_min__log_t *log;
+ const char *url;
+ const char *common_path;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_min__add_wc_info(baton, i, iterpool, subpool));
+ SVN_ERR(svn_client_open_ra_session2(&session, cmd_baton->repo_root,
+ NULL, cmd_baton->ctx, iterpool,
+ subpool));
+
+ /* scan working copy */
+ svn_pool_clear(subpool);
+ SVN_ERR(svn_cmdline_printf(subpool, _("Scanning working copy %s ...\n"),
+ cmd_baton->local_abspath));
+ SVN_ERR(svn_min__read_mergeinfo(&wc_mergeinfo, cmd_baton, iterpool,
+ subpool));
+ SVN_ERR(svn_min__print_mergeinfo_stats(wc_mergeinfo, subpool));
+
+ /* fetch log */
+ svn_pool_clear(subpool);
+ common_path = svn_min__common_parent(wc_mergeinfo, subpool, subpool);
+ SVN_ERR_ASSERT(*common_path == '/');
+
+ url = svn_path_url_add_component2(cmd_baton->repo_root,
+ common_path + 1,
+ subpool);
+ SVN_ERR(svn_cmdline_printf(subpool, _("Fetching log for %s ...\n"),
+ url));
+ SVN_ERR(svn_min__log(&log, url, cmd_baton, iterpool, subpool));
+ SVN_ERR(svn_min__print_log_stats(log, subpool));
+
+ /* actual analysis */
+ svn_pool_clear(subpool);
+ SVN_ERR(analyze(session, wc_mergeinfo, log, subpool));
+ }
+
+ svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
Propchange:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/analyze-cmd.c
------------------------------------------------------------------------------
svn:eol-style = native
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/clear-obsolete-cmd.c
URL:
http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/clear-obsolete-cmd.c?rev=1642242&view=auto
==============================================================================
---
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/clear-obsolete-cmd.c
(added)
+++
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/clear-obsolete-cmd.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,140 @@
+/*
+ * clear-obsolete-cmd.c -- Remove branches from MI that don't exist in HEAD.
+ *
+ * ====================================================================
+ * 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_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_path.h"
+#include "svn_pools.h"
+#include "private/svn_fspath.h"
+
+#include "mergeinfo-normalizer.h"
+
+#include "svn_private_config.h"
+#include <apr_poll.h>
+
+
+/*** Code. ***/
+
+static svn_error_t *
+remove_obsolete_lines(svn_ra_session_t *session,
+ svn_mergeinfo_t mergeinfo,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *to_remove
+ = apr_array_make(scratch_pool, 16, sizeof(const char *));
+
+ int i;
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(scratch_pool, mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *path = apr_hash_this_key(hi);
+ svn_node_kind_t kind;
+
+ SVN_ERR_ASSERT(*path == '/');
+ SVN_ERR(svn_ra_check_path(session, path + 1, SVN_INVALID_REVNUM, &kind,
+ scratch_pool));
+ if (kind == svn_node_none)
+ APR_ARRAY_PUSH(to_remove, const char *) = path;
+ }
+
+ for (i = 0; i < to_remove->nelts; ++i)
+ {
+ const char *path = APR_ARRAY_IDX(to_remove, i, const char *);
+ svn_hash_sets(mergeinfo, path, NULL);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+remove_obsoletes(apr_array_header_t *wc_mergeinfo,
+ svn_ra_session_t *session,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ int i;
+ for (i = 0; i < wc_mergeinfo->nelts; ++i)
+ {
+ svn_mergeinfo_t mergeinfo = svn_min__get_mergeinfo(wc_mergeinfo, i);
+ svn_pool_clear(iterpool);
+
+ /* Combine mergeinfo ranges */
+ SVN_ERR(remove_obsolete_lines(session, mergeinfo, iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_min__clear_obsolete(apr_getopt_t *os,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_min__cmd_baton_t *cmd_baton = baton;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_pool_t *subpool = svn_pool_create(pool);
+
+ int i;
+ for (i = 0; i < cmd_baton->opt_state->targets->nelts; i++)
+ {
+ svn_ra_session_t *session;
+ apr_array_header_t *wc_mergeinfo;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_min__add_wc_info(baton, i, iterpool, subpool));
+ SVN_ERR(svn_client_open_ra_session2(&session, cmd_baton->repo_root,
+ NULL, cmd_baton->ctx, iterpool,
+ subpool));
+
+ /* scan working copy */
+ svn_pool_clear(subpool);
+ SVN_ERR(svn_min__read_mergeinfo(&wc_mergeinfo, cmd_baton, iterpool,
+ subpool));
+
+ /* actual normalization */
+ svn_pool_clear(subpool);
+ SVN_ERR(remove_obsoletes(wc_mergeinfo, session, subpool));
+
+ /* write results to disk */
+ svn_pool_clear(subpool);
+ if (!cmd_baton->opt_state->dry_run)
+ SVN_ERR(svn_min__write_mergeinfo(cmd_baton, wc_mergeinfo, subpool));
+ }
+
+ svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
Propchange:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/clear-obsolete-cmd.c
------------------------------------------------------------------------------
svn:eol-style = native
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/combine-ranges-cmd.c
URL:
http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/combine-ranges-cmd.c?rev=1642242&view=auto
==============================================================================
---
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/combine-ranges-cmd.c
(added)
+++
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/combine-ranges-cmd.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,186 @@
+/*
+ * combine-ranges-cmd.c -- Combine revision ranges in MI if the gap between
+ * them is inoperative for the respective path.
+ *
+ * ====================================================================
+ * 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_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_path.h"
+#include "svn_pools.h"
+#include "private/svn_fspath.h"
+
+#include "mergeinfo-normalizer.h"
+
+#include "svn_private_config.h"
+
+
+/*** Code. ***/
+
+static svn_boolean_t
+all_positive_ranges(svn_rangelist_t *ranges)
+{
+ int i;
+ for (i = 0; i < ranges->nelts; ++i)
+ {
+ const svn_merge_range_t *range
+ = APR_ARRAY_IDX(ranges, i, const svn_merge_range_t *);
+
+ if (range->start > range->end)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static svn_boolean_t
+inoperative(svn_min__log_t *log,
+ const char *path,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ apr_pool_t *scratch_pool)
+{
+ svn_merge_range_t range = { 0 };
+ apr_array_header_t *ranges = apr_array_make(scratch_pool, 1, sizeof(&range));
+
+ range.start = start - 1;
+ range.end = end;
+ APR_ARRAY_PUSH(ranges, svn_merge_range_t *) = ⦥
+
+ return svn_min__operative(log, path, ranges, scratch_pool)->nelts == 0;
+}
+
+static svn_error_t *
+shorten_lines(apr_array_header_t *wc_mergeinfo,
+ svn_min__log_t *log,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_pool_t *iterpool2 = svn_pool_create(scratch_pool);
+
+ int i;
+ for (i = 0; i < wc_mergeinfo->nelts; ++i)
+ {
+ apr_hash_index_t *hi;
+ svn_mergeinfo_t mergeinfo = svn_min__get_mergeinfo(wc_mergeinfo, i);
+
+ svn_pool_clear(iterpool);
+
+ for (hi = apr_hash_first(iterpool, mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ int source, dest;
+ const char *path = apr_hash_this_key(hi);
+ svn_rangelist_t *ranges = apr_hash_this_val(hi);
+
+ if (ranges->nelts < 2 || !all_positive_ranges(ranges))
+ continue;
+
+ for (source = 1, dest = 0; source < ranges->nelts; ++source)
+ {
+ svn_merge_range_t *source_range
+ = APR_ARRAY_IDX(ranges, source, svn_merge_range_t *);
+ svn_merge_range_t *dest_range
+ = APR_ARRAY_IDX(ranges, dest, svn_merge_range_t *);
+
+ svn_pool_clear(iterpool2);
+
+ if ( (source_range->inheritable == dest_range->inheritable)
+ && inoperative(log, path, dest_range->end + 1,
+ source_range->start, iterpool2))
+ {
+ dest_range->end = source_range->end;
+ }
+ else
+ {
+ ++dest;
+ APR_ARRAY_IDX(ranges, dest, svn_merge_range_t *)
+ = source_range;
+ }
+ }
+
+ ranges->nelts = dest + 1;
+ }
+ }
+
+ svn_pool_destroy(iterpool2);
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_min__combine_ranges(apr_getopt_t *os,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_min__cmd_baton_t *cmd_baton = baton;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_pool_t *subpool = svn_pool_create(pool);
+
+ int i;
+ for (i = 0; i < cmd_baton->opt_state->targets->nelts; i++)
+ {
+ apr_array_header_t *wc_mergeinfo;
+ svn_min__log_t *log;
+ const char *url;
+ const char *common_path;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_min__add_wc_info(baton, i, iterpool, subpool));
+
+ /* scan working copy */
+ svn_pool_clear(subpool);
+ SVN_ERR(svn_min__read_mergeinfo(&wc_mergeinfo, cmd_baton, iterpool,
+ subpool));
+
+ /* fetch log */
+ svn_pool_clear(subpool);
+ common_path = svn_min__common_parent(wc_mergeinfo, subpool, subpool);
+ SVN_ERR_ASSERT(*common_path == '/');
+ url = svn_path_url_add_component2(cmd_baton->repo_root,
+ common_path + 1,
+ subpool);
+ SVN_ERR(svn_min__log(&log, url, cmd_baton, iterpool, subpool));
+
+ /* actual normalization */
+ svn_pool_clear(subpool);
+ SVN_ERR(shorten_lines(wc_mergeinfo, log, subpool));
+
+ /* write results to disk */
+ svn_pool_clear(subpool);
+ if (!cmd_baton->opt_state->dry_run)
+ SVN_ERR(svn_min__write_mergeinfo(cmd_baton, wc_mergeinfo, subpool));
+ }
+
+ svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
Propchange:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/combine-ranges-cmd.c
------------------------------------------------------------------------------
svn:eol-style = native
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/help-cmd.c
URL:
http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/help-cmd.c?rev=1642242&view=auto
==============================================================================
---
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/help-cmd.c
(added)
+++
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/help-cmd.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,190 @@
+/*
+ * help-cmd.c -- Provide help
+ *
+ * ====================================================================
+ * 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_hash.h"
+#include "svn_string.h"
+#include "svn_config.h"
+#include "svn_dirent_uri.h"
+#include "svn_error.h"
+#include "mergeinfo-normalizer.h"
+
+#include "svn_private_config.h"
+
+
+/*** Code. ***/
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_min__help(apr_getopt_t *os,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_min__opt_state_t *opt_state = NULL;
+ svn_stringbuf_t *version_footer = NULL;
+ const char *config_path;
+
+ char help_header[] =
+ N_("usage: svn <subcommand> [options] [args]\n"
+ "Subversion command-line client.\n"
+ "Type 'svn help <subcommand>' for help on a specific subcommand.\n"
+ "Type 'svn --version' to see the program version and RA modules\n"
+ " or 'svn --version --quiet' to see just the version number.\n"
+ "\n"
+ "Most subcommands take file and/or directory arguments, recursing\n"
+ "on the directories. If no arguments are supplied to such a\n"
+ "command, it recurses on the current directory (inclusive) by default.\n"
+ "\n"
+ "Available subcommands:\n");
+
+ char help_footer[] =
+ N_("Subversion is a tool for version control.\n"
+ "For additional information, see http://subversion.apache.org/\n");
+
+ const char *ra_desc_start
+ = _("The following repository access (RA) modules are available:\n\n");
+
+ if (baton)
+ {
+ svn_min__cmd_baton_t *const cmd_baton = baton;
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
+ /* Windows never actually stores plaintext passwords, it
+ encrypts the contents using CryptoAPI. ...
+
+ ... If CryptoAPI is available ... but it should be on all
+ versions of Windows that are even remotely interesting two
+ days before the scheduled end of the world, when this comment
+ is being written. */
+# ifndef WIN32
+ svn_boolean_t store_auth_creds =
+ SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
+ svn_boolean_t store_passwords =
+ SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
+ svn_boolean_t store_plaintext_passwords = FALSE;
+ svn_config_t *cfg;
+
+ if (cmd_baton->ctx->config)
+ {
+ cfg = svn_hash_gets(cmd_baton->ctx->config,
+ SVN_CONFIG_CATEGORY_CONFIG);
+ if (cfg)
+ {
+ SVN_ERR(svn_config_get_bool(cfg, &store_auth_creds,
+ SVN_CONFIG_SECTION_AUTH,
+ SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
+ store_auth_creds));
+ SVN_ERR(svn_config_get_bool(cfg, &store_passwords,
+ SVN_CONFIG_SECTION_AUTH,
+ SVN_CONFIG_OPTION_STORE_PASSWORDS,
+ store_passwords));
+ }
+ cfg = svn_hash_gets(cmd_baton->ctx->config,
+ SVN_CONFIG_CATEGORY_SERVERS);
+ if (cfg)
+ {
+ const char *value;
+ SVN_ERR(svn_config_get_yes_no_ask
+ (cfg, &value,
+ SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
+ SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS));
+ if (0 == svn_cstring_casecmp(value, SVN_CONFIG_TRUE))
+ store_plaintext_passwords = TRUE;
+ }
+ }
+
+ if (store_plaintext_passwords && store_auth_creds && store_passwords)
+ {
+ version_footer = svn_stringbuf_create(
+ _("WARNING: Plaintext password storage is enabled!\n\n"),
+ pool);
+ svn_stringbuf_appendcstr(version_footer, ra_desc_start);
+ }
+# endif /* !WIN32 */
+#endif /* !SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE */
+
+ opt_state = cmd_baton->opt_state;
+ }
+
+ if (!version_footer)
+ version_footer = svn_stringbuf_create(ra_desc_start, pool);
+ SVN_ERR(svn_ra_print_modules(version_footer, pool));
+
+ /*
+ * Show auth creds storage providers.
+ */
+ SVN_ERR(svn_config_get_user_config_path(&config_path,
+ opt_state ? opt_state->config_dir
+ : NULL,
+ NULL,
+ pool));
+ svn_stringbuf_appendcstr(version_footer,
+ _("\nThe following authentication credential caches
are available:\n\n"));
+
+ /*### There is no API to query available providers at run time. */
+#if (defined(WIN32) && !defined(__MINGW32__))
+ version_footer =
+ svn_stringbuf_create(apr_psprintf(pool, _("%s* Wincrypt cache in %s\n"),
+ version_footer->data,
+ svn_dirent_local_style(config_path,
+ pool)),
+ pool);
+#elif !defined(SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE)
+ version_footer =
+ svn_stringbuf_create(apr_psprintf(pool, _("%s* Plaintext cache in %s\n"),
+ version_footer->data,
+ svn_dirent_local_style(config_path,
+ pool)),
+ pool);
+#endif
+#ifdef SVN_HAVE_GNOME_KEYRING
+ svn_stringbuf_appendcstr(version_footer, "* Gnome Keyring\n");
+#endif
+#ifdef SVN_HAVE_GPG_AGENT
+ svn_stringbuf_appendcstr(version_footer, "* GPG-Agent\n");
+#endif
+#ifdef SVN_HAVE_KEYCHAIN_SERVICES
+ svn_stringbuf_appendcstr(version_footer, "* Mac OS X Keychain\n");
+#endif
+#ifdef SVN_HAVE_KWALLET
+ svn_stringbuf_appendcstr(version_footer, "* KWallet (KDE)\n");
+#endif
+
+ return svn_opt_print_help4(os,
+ "svn-mergeinfo-normalizer",
+ opt_state ? opt_state->version : FALSE,
+ opt_state ? opt_state->quiet : FALSE,
+ TRUE,
+ version_footer->data,
+ help_header, /* already gettext()'d */
+ svn_min__cmd_table,
+ svn_min__options,
+ svn_min__global_options,
+ _(help_footer),
+ pool);
+}
Propchange:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/help-cmd.c
------------------------------------------------------------------------------
svn:eol-style = native
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c
URL:
http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c?rev=1642242&view=auto
==============================================================================
---
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c
(added)
+++
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,371 @@
+/*
+ * log.c -- Fetch log data and implement the log queries
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ */
+
+#include "svn_cmdline.h"
+#include "svn_client.h"
+#include "svn_dirent_uri.h"
+#include "svn_string.h"
+#include "svn_path.h"
+#include "svn_error.h"
+#include "svn_sorts.h"
+#include "svn_pools.h"
+#include "svn_hash.h"
+
+#include "private/svn_subr_private.h"
+#include "private/svn_sorts_private.h"
+
+#include "mergeinfo-normalizer.h"
+
+#include "svn_private_config.h"
+
+
+/*** Code. ***/
+
+typedef struct log_entry_t
+{
+ svn_revnum_t revision;
+ const char *common_base;
+ apr_array_header_t *paths;
+} log_entry_t;
+
+struct svn_min__log_t
+{
+ apr_hash_t *unique_paths;
+
+ svn_revnum_t first_rev;
+ svn_revnum_t head_rev;
+ apr_array_header_t *entries;
+};
+
+static const char *
+internalize(apr_hash_t *unique_paths,
+ const char *path,
+ apr_ssize_t path_len)
+{
+ const char *result = apr_hash_get(unique_paths, path, path_len);
+ if (result == NULL)
+ {
+ result = apr_pstrmemdup(apr_hash_pool_get(unique_paths), path, path_len);
+ apr_hash_set(unique_paths, result, path_len, result);
+ }
+
+ return result;
+}
+
+static svn_error_t *
+log_entry_receiver(void *baton,
+ svn_log_entry_t *log_entry,
+ apr_pool_t *scratch_pool)
+{
+ svn_min__log_t *log = baton;
+ apr_pool_t *result_pool = log->entries->pool;
+ log_entry_t *entry;
+ apr_hash_index_t *hi;
+ const char *common_base;
+ int count;
+
+ if (!log_entry->changed_paths || !apr_hash_count(log_entry->changed_paths))
+ return SVN_NO_ERROR;
+
+ entry = apr_pcalloc(result_pool, sizeof(*entry));
+ entry->revision = log_entry->revision;
+ entry->paths = apr_array_make(result_pool,
+ apr_hash_count(log_entry->changed_paths),
+ sizeof(const char *));
+
+ for (hi = apr_hash_first(scratch_pool, log_entry->changed_paths);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *path = apr_hash_this_key(hi);
+ path = internalize(log->unique_paths, path, apr_hash_this_key_len(hi));
+ APR_ARRAY_PUSH(entry->paths, const char *) = path;
+ }
+
+ count = entry->paths->nelts;
+ if (count == 1)
+ {
+ entry->common_base = APR_ARRAY_IDX(entry->paths, 0, const char *);
+ }
+ else
+ {
+ svn_sort__array(entry->paths, svn_sort_compare_paths);
+
+ common_base = svn_dirent_get_longest_ancestor(
+ APR_ARRAY_IDX(entry->paths, 0, const char *),
+ APR_ARRAY_IDX(entry->paths, count - 1, const char *),
+ scratch_pool);
+ entry->common_base = internalize(log->unique_paths, common_base,
+ strlen(common_base));
+ }
+
+ APR_ARRAY_PUSH(log->entries, log_entry_t *) = entry;
+
+ log->first_rev = log_entry->revision;
+ if (log->head_rev == SVN_INVALID_REVNUM)
+ log->head_rev = log_entry->revision;
+
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_min__log(svn_min__log_t **log,
+ const char *url,
+ svn_min__cmd_baton_t *baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_client_ctx_t *ctx = baton->ctx;
+ svn_min__log_t *result;
+
+ apr_array_header_t *targets;
+ apr_array_header_t *revisions;
+ apr_array_header_t *revprops;
+ svn_opt_revision_t peg_revision = { svn_opt_revision_head };
+ svn_opt_revision_range_t range = { { svn_opt_revision_unspecified },
+ { svn_opt_revision_unspecified } };
+
+ targets = apr_array_make(scratch_pool, 1, sizeof(const char *));
+ APR_ARRAY_PUSH(targets, const char *) = url;
+
+ revisions = apr_array_make(scratch_pool, 1, sizeof(&range));
+ APR_ARRAY_PUSH(revisions, svn_opt_revision_range_t *) = ⦥
+
+ revprops = apr_array_make(scratch_pool, 0, sizeof(const char *));
+
+ result = apr_pcalloc(result_pool, sizeof(*result));
+ result->unique_paths = svn_hash__make(result_pool);
+ result->first_rev = SVN_INVALID_REVNUM;
+ result->head_rev = SVN_INVALID_REVNUM;
+ result->entries = apr_array_make(result_pool, 1024, sizeof(log_entry_t *));
+
+ SVN_ERR(svn_client_log5(targets,
+ &peg_revision,
+ revisions,
+ 0, /* no limit */
+ TRUE, /* verbose */
+ TRUE, /* stop-on-copy */
+ FALSE, /* merge history */
+ revprops,
+ log_entry_receiver,
+ result,
+ ctx,
+ scratch_pool));
+
+ svn_sort__array_reverse(result->entries, scratch_pool);
+ *log = result;
+
+ return SVN_NO_ERROR;
+}
+
+static void
+append_rev_to_ranges(svn_rangelist_t *ranges,
+ svn_revnum_t revision,
+ svn_boolean_t inheritable,
+ apr_pool_t *result_pool)
+{
+ svn_merge_range_t *range;
+ if (ranges->nelts)
+ {
+ range = APR_ARRAY_IDX(ranges, ranges->nelts - 1, svn_merge_range_t *);
+ if (range->end + 1 == revision && range->inheritable == inheritable)
+ {
+ range->end = revision;
+ return;
+ }
+ }
+
+ range = apr_pcalloc(result_pool, sizeof(*range));
+ range->start = revision - 1;
+ range->end = revision;
+ range->inheritable = inheritable;
+
+ APR_ARRAY_PUSH(ranges, svn_merge_range_t *) = range;
+}
+
+static int
+compare_rev_log_entry(const void *lhs,
+ const void *rhs)
+{
+ const log_entry_t *entry = *(const log_entry_t * const *)lhs;
+ svn_revnum_t revision = *(const svn_revnum_t *)rhs;
+
+ if (entry->revision < revision)
+ return -1;
+
+ return entry->revision == revision ? 0 : 1;
+}
+
+static void
+restrict_range(svn_min__log_t *log,
+ svn_merge_range_t *range,
+ svn_rangelist_t *ranges,
+ apr_pool_t *result_pool)
+{
+ if (range->start + 1 < log->first_rev)
+ {
+ svn_merge_range_t *new_range
+ = apr_pmemdup(result_pool, range, sizeof(*range));
+ new_range->end = MIN(new_range->end, log->first_rev - 1);
+
+ APR_ARRAY_PUSH(ranges, svn_merge_range_t *) = new_range;
+ range->start = new_range->end;
+ }
+
+ if (range->end > log->head_rev)
+ {
+ svn_merge_range_t *new_range
+ = apr_pmemdup(result_pool, range, sizeof(*range));
+ new_range->start = log->head_rev;
+
+ APR_ARRAY_PUSH(ranges, svn_merge_range_t *) = new_range;
+ range->end = new_range->start;
+ }
+}
+
+static svn_boolean_t
+is_relevant(const char *changed_path,
+ const char *path,
+ const void *baton)
+{
+ return svn_dirent_is_ancestor(changed_path, path)
+ || svn_dirent_is_ancestor(path, changed_path);
+}
+
+static svn_boolean_t
+below_path_outside_subtree(const char *changed_path,
+ const char *path,
+ const void *baton)
+{
+ const char *subtree = baton;
+
+ /* Is this a change _below_ PATH but not within SUBTREE? */
+ return !svn_dirent_is_ancestor(subtree, changed_path)
+ && svn_dirent_is_ancestor(path, changed_path)
+ && strcmp(path, changed_path);
+}
+
+static svn_rangelist_t *
+filter_ranges(svn_min__log_t *log,
+ const char *path,
+ svn_rangelist_t *ranges,
+ svn_boolean_t (*path_relavent)(const char*, const char *,
+ const void *),
+ const void *baton,
+ apr_pool_t *result_pool)
+{
+ svn_rangelist_t *result;
+ int i, k, l;
+
+ if (!SVN_IS_VALID_REVNUM(log->first_rev))
+ return svn_rangelist_dup(ranges, result_pool);
+
+ result = apr_array_make(result_pool, 0, ranges->elt_size);
+ for (i = 0; i < ranges->nelts; ++i)
+ {
+ svn_merge_range_t range
+ = *APR_ARRAY_IDX(ranges, i, const svn_merge_range_t *);
+ restrict_range(log, &range, result, result_pool);
+
+ ++range.start;
+ for (k = svn_sort__bsearch_lower_bound(log->entries, &range.start,
+ compare_rev_log_entry);
+ k < log->entries->nelts;
+ ++k)
+ {
+ const log_entry_t *entry = APR_ARRAY_IDX(log->entries, k,
+ const log_entry_t *);
+ if (entry->revision > range.end)
+ break;
+
+ if (!is_relevant(entry->common_base, path, NULL))
+ continue;
+
+ for (l = 0; l < entry->paths->nelts; ++l)
+ {
+ const char *changed_path
+ = APR_ARRAY_IDX(entry->paths, l, const char *);
+
+ /* Is this a change _below_ PATH but not within SUBTREE? */
+ if (path_relavent(changed_path, path, baton))
+ {
+ append_rev_to_ranges(result, entry->revision,
+ range.inheritable, result_pool);
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+svn_rangelist_t *
+svn_min__operative(svn_min__log_t *log,
+ const char *path,
+ svn_rangelist_t *ranges,
+ apr_pool_t *result_pool)
+{
+ return filter_ranges(log, path, ranges, is_relevant, NULL, result_pool);
+}
+
+svn_rangelist_t *
+svn_min__operative_outside_subtree(svn_min__log_t *log,
+ const char *path,
+ const char *subtree,
+ svn_rangelist_t *ranges,
+ apr_pool_t *result_pool)
+{
+ return filter_ranges(log, path, ranges, below_path_outside_subtree,
+ subtree, result_pool);
+}
+
+svn_error_t *
+svn_min__print_log_stats(svn_min__log_t *log,
+ apr_pool_t *scratch_pool)
+{
+ int change_count = 0;
+
+ int i;
+ for (i = 0; i < log->entries->nelts; ++i)
+ {
+ const log_entry_t *entry = APR_ARRAY_IDX(log->entries, i,
+ const log_entry_t *);
+ change_count += entry->paths->nelts;
+ }
+
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Received %d revisions from %ld to %ld.\n"),
+ log->entries->nelts, log->first_rev,
+ log->head_rev));
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Received %d path changes.\n"),
+ change_count));
+ SVN_ERR(svn_cmdline_printf(scratch_pool,
+ _(" Pool has %u different paths.\n\n"),
+ apr_hash_count(log->unique_paths)));
+
+ return SVN_NO_ERROR;
+}
Propchange:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/log.c
------------------------------------------------------------------------------
svn:eol-style = native
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
URL:
http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h?rev=1642242&view=auto
==============================================================================
---
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
(added)
+++
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,183 @@
+/*
+ * mergeinfo-normalizer.h: tool-global functions and structures.
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+#ifndef SVN_MERGEINFO_NORMALIZER_H
+#define SVN_MERGEINFO_NORMALIZER_H
+
+/*** Includes. ***/
+#include <apr_tables.h>
+#include <apr_getopt.h>
+
+#include "svn_client.h"
+#include "svn_opt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/*** Command dispatch. ***/
+
+/* Hold results of option processing that are shared by multiple
+ commands. */
+typedef struct svn_min__opt_state_t
+{
+ /* After option processing is done, reflects the switch actually
+ given on the command line, or svn_depth_unknown if none. */
+ svn_depth_t depth;
+
+ svn_boolean_t quiet; /* sssh...avoid unnecessary output */
+ svn_boolean_t version; /* print version information */
+ svn_boolean_t help; /* print usage message */
+ const char *auth_username; /* auth username */
+ const char *auth_password; /* auth password */
+ apr_array_header_t *targets;
+ svn_boolean_t no_auth_cache; /* do not cache authentication information */
+ svn_boolean_t dry_run; /* try operation but make no changes */
+ const char *config_dir; /* over-riding configuration directory */
+ apr_array_header_t *config_options; /* over-riding configuration options */
+
+ /* trust server SSL certs that would otherwise be rejected as "untrusted" */
+ svn_boolean_t trust_server_cert_unknown_ca;
+ svn_boolean_t trust_server_cert_cn_mismatch;
+ svn_boolean_t trust_server_cert_expired;
+ svn_boolean_t trust_server_cert_not_yet_valid;
+ svn_boolean_t trust_server_cert_other_failure;
+ svn_boolean_t allow_mixed_rev; /* Allow operation on mixed-revision WC */
+ svn_boolean_t non_interactive;
+} svn_min__opt_state_t;
+
+
+typedef struct svn_min__cmd_baton_t
+{
+ svn_min__opt_state_t *opt_state;
+ svn_client_ctx_t *ctx;
+
+ const char *local_abspath;
+ const char *wc_root;
+ const char *repo_root;
+} svn_min__cmd_baton_t;
+
+
+/* Declare all the command procedures */
+svn_opt_subcommand_t
+ svn_min__help,
+ svn_min__normalize,
+ svn_min__clear_obsolete,
+ svn_min__combine_ranges,
+ svn_min__analyze;
+
+/* See definition in svn.c for documentation. */
+extern const svn_opt_subcommand_desc2_t svn_min__cmd_table[];
+
+/* See definition in svn.c for documentation. */
+extern const int svn_min__global_options[];
+
+/* See definition in svn.c for documentation. */
+extern const apr_getopt_option_t svn_min__options[];
+
+
+/* Our cancellation callback. */
+svn_error_t *
+svn_min__check_cancel(void *baton);
+
+
+/*** Command-line output functions -- printing to the user. ***/
+
+svn_error_t *
+svn_min__add_wc_info(svn_min__cmd_baton_t* baton,
+ int idx,
+ apr_pool_t* result_pool,
+ apr_pool_t* scratch_pool);
+
+svn_error_t *
+svn_min__read_mergeinfo(apr_array_header_t **result,
+ svn_min__cmd_baton_t *baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+const char *
+svn_min__common_parent(apr_array_header_t *mergeinfo,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+svn_mergeinfo_t
+svn_min__get_mergeinfo(apr_array_header_t *mergeinfo,
+ int idx);
+
+const char *
+svn_min__get_mergeinfo_path(apr_array_header_t *mergeinfo,
+ int idx);
+
+svn_boolean_t
+svn_min__get_mergeinfo_pair(const char **parent_path,
+ const char **subtree_relpath,
+ svn_mergeinfo_t *parent_mergeinfo,
+ svn_mergeinfo_t *subtree_mergeinfo,
+ apr_array_header_t *mergeinfo,
+ int idx);
+
+svn_error_t *
+svn_min__write_mergeinfo(svn_min__cmd_baton_t *baton,
+ apr_array_header_t *mergeinfo,
+ apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_min__print_mergeinfo_stats(apr_array_header_t *wc_mergeinfo,
+ apr_pool_t *scratch_pool);
+
+typedef struct svn_min__log_t svn_min__log_t;
+
+svn_error_t *
+svn_min__log(svn_min__log_t **log,
+ const char *url,
+ svn_min__cmd_baton_t *baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+svn_rangelist_t *
+svn_min__operative(svn_min__log_t *log,
+ const char *path,
+ svn_rangelist_t *ranges,
+ apr_pool_t *result_pool);
+
+svn_rangelist_t *
+svn_min__operative_outside_subtree(svn_min__log_t *log,
+ const char *path,
+ const char *subtree,
+ svn_rangelist_t *ranges,
+ apr_pool_t *result_pool);
+
+svn_error_t *
+svn_min__print_log_stats(svn_min__log_t *log,
+ apr_pool_t *scratch_pool);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_MERGEINFO_NORMALIZER_H */
Propchange:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
------------------------------------------------------------------------------
svn:eol-style = native
Added:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/normalize-cmd.c
URL:
http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/normalize-cmd.c?rev=1642242&view=auto
==============================================================================
---
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/normalize-cmd.c
(added)
+++
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/normalize-cmd.c
Thu Nov 27 22:16:52 2014
@@ -0,0 +1,216 @@
+/*
+ * normalize-cmd.c -- Elide mergeinfo from sub-nodes
+ *
+ * ====================================================================
+ * 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_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_path.h"
+#include "svn_pools.h"
+#include "private/svn_fspath.h"
+
+#include "mergeinfo-normalizer.h"
+
+#include "svn_private_config.h"
+
+
+/*** Code. ***/
+
+static svn_boolean_t
+all_positive_ranges(svn_rangelist_t *ranges)
+{
+ int i;
+ for (i = 0; i < ranges->nelts; ++i)
+ {
+ const svn_merge_range_t *range
+ = APR_ARRAY_IDX(ranges, i, const svn_merge_range_t *);
+
+ if (range->start > range->end)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static svn_error_t *
+remove_lines(svn_min__log_t *log,
+ const char *relpath,
+ svn_mergeinfo_t parent_mergeinfo,
+ svn_mergeinfo_t subtree_mergeinfo,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(scratch_pool, parent_mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *parent_path, *subtree_path;
+ svn_rangelist_t *parent_ranges, *subtree_ranges;
+ svn_rangelist_t *operative_outside_subtree, *operative_in_subtree;
+
+ svn_pool_clear(iterpool);
+
+ parent_path = apr_hash_this_key(hi);
+ subtree_path = svn_fspath__join(parent_path, relpath, iterpool);
+ parent_ranges = apr_hash_this_val(hi);
+ subtree_ranges = svn_hash_gets(subtree_mergeinfo, subtree_path);
+
+ if (subtree_ranges && all_positive_ranges(subtree_ranges))
+ {
+ svn_rangelist_t *subtree_only;
+ svn_rangelist_t *parent_only;
+
+ SVN_ERR(svn_rangelist_diff(&parent_only, &subtree_only,
+ parent_ranges, subtree_ranges, FALSE,
+ iterpool));
+ subtree_only
+ = svn_min__operative(log, subtree_path, parent_only, iterpool);
+
+ operative_outside_subtree
+ = svn_min__operative_outside_subtree(log, parent_path,
subtree_path,
+ subtree_only, iterpool);
+ operative_in_subtree
+ = svn_min__operative(log, subtree_path, parent_only, iterpool);
+
+ /* This will also work when subtree_only is empty. */
+ if ( !operative_outside_subtree->nelts
+ && !operative_in_subtree->nelts)
+ {
+ SVN_ERR(svn_rangelist_merge2(parent_ranges, subtree_only,
+ parent_ranges->pool, iterpool));
+ svn_hash_sets(subtree_mergeinfo, subtree_path, NULL);
+ }
+ }
+ }
+
+ /* TODO: Move subtree ranges to parent even if the parent has no entry
+ * for the respective branches, yet. */
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+normalize(apr_array_header_t *wc_mergeinfo,
+ svn_min__log_t *log,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ int i;
+ for (i = wc_mergeinfo->nelts - 1; i >= 0; --i)
+ {
+ const char *parent_path;
+ const char *relpath;
+ svn_mergeinfo_t parent_mergeinfo;
+ svn_mergeinfo_t subtree_mergeinfo;
+
+ if (svn_min__get_mergeinfo_pair(&parent_path, &relpath,
+ &parent_mergeinfo, &subtree_mergeinfo,
+ wc_mergeinfo, i))
+ {
+ svn_mergeinfo_t parent_mergeinfo_copy;
+ svn_mergeinfo_t subtree_mergeinfo_copy;
+
+ svn_pool_clear(iterpool);
+ parent_mergeinfo_copy = svn_mergeinfo_dup(parent_mergeinfo,
+ iterpool);
+ subtree_mergeinfo_copy = svn_mergeinfo_dup(subtree_mergeinfo,
+ iterpool);
+
+ SVN_ERR(remove_lines(log, relpath, parent_mergeinfo_copy,
+ subtree_mergeinfo_copy, iterpool));
+
+ if (apr_hash_count(subtree_mergeinfo_copy) == 0)
+ {
+ SVN_ERR(svn_mergeinfo_merge2(parent_mergeinfo,
+ parent_mergeinfo_copy,
+ apr_hash_pool_get(parent_mergeinfo),
+ iterpool));
+ apr_hash_clear(subtree_mergeinfo);
+ }
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_min__normalize(apr_getopt_t *os,
+ void *baton,
+ apr_pool_t *pool)
+{
+ svn_min__cmd_baton_t *cmd_baton = baton;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_pool_t *subpool = svn_pool_create(pool);
+
+ int i;
+ for (i = 0; i < cmd_baton->opt_state->targets->nelts; i++)
+ {
+ apr_array_header_t *wc_mergeinfo;
+ svn_min__log_t *log;
+ const char *url;
+ const char *common_path;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_min__add_wc_info(baton, i, iterpool, subpool));
+
+ /* scan working copy */
+ svn_pool_clear(subpool);
+ SVN_ERR(svn_min__read_mergeinfo(&wc_mergeinfo, cmd_baton, iterpool,
+ subpool));
+
+ /* fetch log */
+ svn_pool_clear(subpool);
+ common_path = svn_min__common_parent(wc_mergeinfo, subpool, subpool);
+ SVN_ERR_ASSERT(*common_path == '/');
+ url = svn_path_url_add_component2(cmd_baton->repo_root,
+ common_path + 1,
+ subpool);
+ SVN_ERR(svn_min__log(&log, url, cmd_baton, iterpool, subpool));
+
+ /* actual normalization */
+ svn_pool_clear(subpool);
+ SVN_ERR(normalize(wc_mergeinfo, log, subpool));
+
+ /* write results to disk */
+ svn_pool_clear(subpool);
+ if (!cmd_baton->opt_state->dry_run)
+ SVN_ERR(svn_min__write_mergeinfo(cmd_baton, wc_mergeinfo, subpool));
+ }
+
+ svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
Propchange:
subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/normalize-cmd.c
------------------------------------------------------------------------------
svn:eol-style = native