blob: f4972a39e19471f0ada87301e44d8712012e4a6c [file] [log] [blame]
/*
* 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_path.h"
#include "svn_props.h"
#include "svn_pools.h"
#include "private/svn_wc_private.h"
#include "client.h"
/* Diff callbacks baton. */
struct summarize_baton_t {
/* The summarize callback passed down from the API */
svn_client_diff_summarize_func_t summarize_func;
/* The summarize callback baton */
void *summarize_func_baton;
};
/* Call B->summarize_func with B->summarize_func_baton, passing it a
* summary object composed from PATH, 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);
sum->path = 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 PROPS? */
static svn_boolean_t
props_changed_hash(apr_hash_t *props,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
if (!props)
return FALSE;
for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
{
const char *name = apr_hash_this_key(hi);
if (svn_property_kind2(name) == svn_prop_regular_kind)
{
return TRUE;
}
}
return FALSE;
}
/* 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);
}
/* svn_diff_tree_processor_t callback */
static svn_error_t *
diff_dir_opened(void **new_dir_baton,
svn_boolean_t *skip,
svn_boolean_t *skip_children,
const char *relpath,
const svn_diff_source_t *left_source,
const svn_diff_source_t *right_source,
const svn_diff_source_t *copyfrom_source,
void *parent_dir_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
/* struct summarize_baton_t *b = processor->baton; */
/* ### Send here instead of from dir_added() ? */
/*if (!left_source)
{
SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added,
FALSE, svn_node_dir, scratch_pool));
}*/
return SVN_NO_ERROR;
}
/* svn_diff_tree_processor_t callback */
static svn_error_t *
diff_dir_changed(const char *relpath,
const svn_diff_source_t *left_source,
const svn_diff_source_t *right_source,
/*const*/ apr_hash_t *left_props,
/*const*/ apr_hash_t *right_props,
const apr_array_header_t *prop_changes,
void *dir_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool)
{
struct summarize_baton_t *b = processor->baton;
SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_normal,
TRUE, svn_node_dir, scratch_pool));
return SVN_NO_ERROR;
}
/* svn_diff_tree_processor_t callback */
static svn_error_t *
diff_dir_added(const char *relpath,
const svn_diff_source_t *copyfrom_source,
const svn_diff_source_t *right_source,
/*const*/ apr_hash_t *copyfrom_props,
/*const*/ apr_hash_t *right_props,
void *dir_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool)
{
struct summarize_baton_t *b = processor->baton;
/* ### Send from dir_opened without prop info? */
SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added,
props_changed_hash(right_props, scratch_pool),
svn_node_dir, scratch_pool));
return SVN_NO_ERROR;
}
/* svn_diff_tree_processor_t callback */
static svn_error_t *
diff_dir_deleted(const char *relpath,
const svn_diff_source_t *left_source,
/*const*/ apr_hash_t *left_props,
void *dir_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool)
{
struct summarize_baton_t *b = processor->baton;
SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_deleted,
FALSE, svn_node_dir, scratch_pool));
return SVN_NO_ERROR;
}
/* svn_diff_tree_processor_t callback */
static svn_error_t *
diff_file_added(const char *relpath,
const svn_diff_source_t *copyfrom_source,
const svn_diff_source_t *right_source,
const char *copyfrom_file,
const char *right_file,
/*const*/ apr_hash_t *copyfrom_props,
/*const*/ apr_hash_t *right_props,
void *file_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool)
{
struct summarize_baton_t *b = processor->baton;
SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_added,
props_changed_hash(right_props, scratch_pool),
svn_node_file, scratch_pool));
return SVN_NO_ERROR;
}
/* svn_diff_tree_processor_t callback */
static svn_error_t *
diff_file_changed(const char *relpath,
const svn_diff_source_t *left_source,
const svn_diff_source_t *right_source,
const char *left_file,
const char *right_file,
/*const*/ apr_hash_t *left_props,
/*const*/ apr_hash_t *right_props,
svn_boolean_t file_modified,
const apr_array_header_t *prop_changes,
void *file_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool)
{
struct summarize_baton_t *b = processor->baton;
SVN_ERR(send_summary(b, relpath,
file_modified ? svn_client_diff_summarize_kind_modified
: svn_client_diff_summarize_kind_normal,
props_changed(prop_changes, scratch_pool),
svn_node_file, scratch_pool));
return SVN_NO_ERROR;
}
/* svn_diff_tree_processor_t callback */
static svn_error_t *
diff_file_deleted(const char *relpath,
const svn_diff_source_t *left_source,
const char *left_file,
/*const*/ apr_hash_t *left_props,
void *file_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool)
{
struct summarize_baton_t *b = processor->baton;
SVN_ERR(send_summary(b, relpath, svn_client_diff_summarize_kind_deleted,
FALSE, svn_node_file, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_client__get_diff_summarize_callbacks(
svn_diff_tree_processor_t **diff_processor,
svn_client_diff_summarize_func_t summarize_func,
void *summarize_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_diff_tree_processor_t *dp;
struct summarize_baton_t *b = apr_pcalloc(result_pool, sizeof(*b));
b->summarize_func = summarize_func;
b->summarize_func_baton = summarize_baton;
dp = svn_diff__tree_processor_create(b, result_pool);
/*dp->file_opened = diff_file_opened;*/
dp->file_added = diff_file_added;
dp->file_deleted = diff_file_deleted;
dp->file_changed = diff_file_changed;
dp->dir_opened = diff_dir_opened;
dp->dir_changed = diff_dir_changed;
dp->dir_deleted = diff_dir_deleted;
dp->dir_added = diff_dir_added;
*diff_processor = dp;
return SVN_NO_ERROR;
}
svn_client_diff_summarize_t *
svn_client_diff_summarize_dup(const svn_client_diff_summarize_t *diff,
apr_pool_t *pool)
{
svn_client_diff_summarize_t *dup_diff = apr_palloc(pool, sizeof(*dup_diff));
*dup_diff = *diff;
if (diff->path)
dup_diff->path = apr_pstrdup(pool, diff->path);
return dup_diff;
}