summaryrefslogtreecommitdiff
path: root/subversion/libsvn_client/diff_summarize.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_client/diff_summarize.c')
-rw-r--r--subversion/libsvn_client/diff_summarize.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/subversion/libsvn_client/diff_summarize.c b/subversion/libsvn_client/diff_summarize.c
new file mode 100644
index 0000000..df0911b
--- /dev/null
+++ b/subversion/libsvn_client/diff_summarize.c
@@ -0,0 +1,317 @@
+/*
+ * repos_diff_summarize.c -- The diff callbacks for summarizing
+ * the differences of two repository versions
+ *
+ * ====================================================================
+ * 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_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_props.h"
+#include "svn_pools.h"
+
+#include "client.h"
+
+
+/* Diff callbacks baton. */
+struct summarize_baton_t {
+ /* The target path of the diff, relative to the anchor; "" if target == anchor. */
+ const char *target;
+
+ /* The summarize callback passed down from the API */
+ svn_client_diff_summarize_func_t summarize_func;
+
+ /* Is the diff handling reversed? (add<->delete) */
+ svn_boolean_t reversed;
+
+ /* The summarize callback baton */
+ void *summarize_func_baton;
+
+ /* Which paths have a prop change. Key is a (const char *) path; the value
+ * is any non-null pointer to indicate that this path has a prop change. */
+ apr_hash_t *prop_changes;
+};
+
+
+/* Call B->summarize_func with B->summarize_func_baton, passing it a
+ * summary object composed from PATH (but made to be relative to the target
+ * of the diff), SUMMARIZE_KIND, PROP_CHANGED (or FALSE if the action is an
+ * add or delete) and NODE_KIND. */
+static svn_error_t *
+send_summary(struct summarize_baton_t *b,
+ const char *path,
+ svn_client_diff_summarize_kind_t summarize_kind,
+ svn_boolean_t prop_changed,
+ svn_node_kind_t node_kind,
+ apr_pool_t *scratch_pool)
+{
+ svn_client_diff_summarize_t *sum = apr_pcalloc(scratch_pool, sizeof(*sum));
+
+ SVN_ERR_ASSERT(summarize_kind != svn_client_diff_summarize_kind_normal
+ || prop_changed);
+
+ if (b->reversed)
+ {
+ switch(summarize_kind)
+ {
+ case svn_client_diff_summarize_kind_added:
+ summarize_kind = svn_client_diff_summarize_kind_deleted;
+ break;
+ case svn_client_diff_summarize_kind_deleted:
+ summarize_kind = svn_client_diff_summarize_kind_added;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* PATH is relative to the anchor of the diff, but SUM->path needs to be
+ relative to the target of the diff. */
+ sum->path = svn_relpath_skip_ancestor(b->target, path);
+ sum->summarize_kind = summarize_kind;
+ if (summarize_kind == svn_client_diff_summarize_kind_modified
+ || summarize_kind == svn_client_diff_summarize_kind_normal)
+ sum->prop_changed = prop_changed;
+ sum->node_kind = node_kind;
+
+ SVN_ERR(b->summarize_func(sum, b->summarize_func_baton, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+/* Are there any changes to relevant (normal) props in PROPCHANGES? */
+static svn_boolean_t
+props_changed(const apr_array_header_t *propchanges,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *props;
+
+ svn_error_clear(svn_categorize_props(propchanges, NULL, NULL, &props,
+ scratch_pool));
+ return (props->nelts != 0);
+}
+
+
+static svn_error_t *
+cb_dir_deleted(svn_wc_notify_state_t *state,
+ svn_boolean_t *tree_conflicted,
+ const char *path,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct summarize_baton_t *b = diff_baton;
+
+ SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted,
+ FALSE, svn_node_dir, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_file_deleted(svn_wc_notify_state_t *state,
+ svn_boolean_t *tree_conflicted,
+ const char *path,
+ const char *tmpfile1,
+ const char *tmpfile2,
+ const char *mimetype1,
+ const char *mimetype2,
+ apr_hash_t *originalprops,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct summarize_baton_t *b = diff_baton;
+
+ SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_deleted,
+ FALSE, svn_node_file, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_dir_added(svn_wc_notify_state_t *state,
+ svn_boolean_t *tree_conflicted,
+ svn_boolean_t *skip,
+ svn_boolean_t *skip_children,
+ const char *path,
+ svn_revnum_t rev,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_dir_opened(svn_boolean_t *tree_conflicted,
+ svn_boolean_t *skip,
+ svn_boolean_t *skip_children,
+ const char *path,
+ svn_revnum_t rev,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_dir_closed(svn_wc_notify_state_t *contentstate,
+ svn_wc_notify_state_t *propstate,
+ svn_boolean_t *tree_conflicted,
+ const char *path,
+ svn_boolean_t dir_was_added,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct summarize_baton_t *b = diff_baton;
+ svn_boolean_t prop_change;
+
+ if (! svn_relpath_skip_ancestor(b->target, path))
+ return SVN_NO_ERROR;
+
+ prop_change = svn_hash_gets(b->prop_changes, path) != NULL;
+ if (dir_was_added || prop_change)
+ SVN_ERR(send_summary(b, path,
+ dir_was_added ? svn_client_diff_summarize_kind_added
+ : svn_client_diff_summarize_kind_normal,
+ prop_change, svn_node_dir, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_file_added(svn_wc_notify_state_t *contentstate,
+ svn_wc_notify_state_t *propstate,
+ svn_boolean_t *tree_conflicted,
+ const char *path,
+ const char *tmpfile1,
+ const char *tmpfile2,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
+ const char *mimetype1,
+ const char *mimetype2,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_revision,
+ const apr_array_header_t *propchanges,
+ apr_hash_t *originalprops,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct summarize_baton_t *b = diff_baton;
+
+ SVN_ERR(send_summary(b, path, svn_client_diff_summarize_kind_added,
+ props_changed(propchanges, scratch_pool),
+ svn_node_file, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_file_opened(svn_boolean_t *tree_conflicted,
+ svn_boolean_t *skip,
+ const char *path,
+ svn_revnum_t rev,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_file_changed(svn_wc_notify_state_t *contentstate,
+ svn_wc_notify_state_t *propstate,
+ svn_boolean_t *tree_conflicted,
+ const char *path,
+ const char *tmpfile1,
+ const char *tmpfile2,
+ svn_revnum_t rev1,
+ svn_revnum_t rev2,
+ const char *mimetype1,
+ const char *mimetype2,
+ const apr_array_header_t *propchanges,
+ apr_hash_t *originalprops,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct summarize_baton_t *b = diff_baton;
+ svn_boolean_t text_change = (tmpfile2 != NULL);
+ svn_boolean_t prop_change = props_changed(propchanges, scratch_pool);
+
+ if (text_change || prop_change)
+ SVN_ERR(send_summary(b, path,
+ text_change ? svn_client_diff_summarize_kind_modified
+ : svn_client_diff_summarize_kind_normal,
+ prop_change, svn_node_file, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cb_dir_props_changed(svn_wc_notify_state_t *propstate,
+ svn_boolean_t *tree_conflicted,
+ const char *path,
+ svn_boolean_t dir_was_added,
+ const apr_array_header_t *propchanges,
+ apr_hash_t *original_props,
+ void *diff_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct summarize_baton_t *b = diff_baton;
+
+ if (props_changed(propchanges, scratch_pool))
+ svn_hash_sets(b->prop_changes, path, path);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__get_diff_summarize_callbacks(
+ svn_wc_diff_callbacks4_t **callbacks,
+ void **callback_baton,
+ const char *target,
+ svn_boolean_t reversed,
+ svn_client_diff_summarize_func_t summarize_func,
+ void *summarize_baton,
+ apr_pool_t *pool)
+{
+ svn_wc_diff_callbacks4_t *cb = apr_palloc(pool, sizeof(*cb));
+ struct summarize_baton_t *b = apr_palloc(pool, sizeof(*b));
+
+ b->target = target;
+ b->summarize_func = summarize_func;
+ b->summarize_func_baton = summarize_baton;
+ b->prop_changes = apr_hash_make(pool);
+ b->reversed = reversed;
+
+ cb->file_opened = cb_file_opened;
+ cb->file_changed = cb_file_changed;
+ cb->file_added = cb_file_added;
+ cb->file_deleted = cb_file_deleted;
+ cb->dir_deleted = cb_dir_deleted;
+ cb->dir_opened = cb_dir_opened;
+ cb->dir_added = cb_dir_added;
+ cb->dir_props_changed = cb_dir_props_changed;
+ cb->dir_closed = cb_dir_closed;
+
+ *callbacks = cb;
+ *callback_baton = b;
+
+ return SVN_NO_ERROR;
+}