#include "svn_dirent_uri.h"
#include "svn_props.h"
#include "svn_pools.h"
#include "client.h"
struct summarize_baton_t {
const char *target;
svn_client_diff_summarize_func_t summarize_func;
void *summarize_func_baton;
apr_hash_t *prop_changes;
};
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 = 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;
}
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));
if (state)
*state = svn_wc_notify_state_inapplicable;
if (tree_conflicted)
*tree_conflicted = FALSE;
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));
if (state)
*state = svn_wc_notify_state_inapplicable;
if (tree_conflicted)
*tree_conflicted = FALSE;
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)
{
if (tree_conflicted)
*tree_conflicted = FALSE;
if (skip)
*skip = FALSE;
if (skip_children)
*skip_children = FALSE;
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)
{
if (tree_conflicted)
*tree_conflicted = FALSE;
if (skip)
*skip = FALSE;
if (skip_children)
*skip_children = FALSE;
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;
prop_change = apr_hash_get(b->prop_changes, path, APR_HASH_KEY_STRING) != 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));
if (contentstate)
*contentstate = svn_wc_notify_state_inapplicable;
if (propstate)
*propstate = svn_wc_notify_state_inapplicable;
if (tree_conflicted)
*tree_conflicted = FALSE;
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));
if (contentstate)
*contentstate = svn_wc_notify_state_inapplicable;
if (propstate)
*propstate = svn_wc_notify_state_inapplicable;
if (tree_conflicted)
*tree_conflicted = FALSE;
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)
{
if (tree_conflicted)
*tree_conflicted = FALSE;
if (skip)
*skip = FALSE;
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));
if (contentstate)
*contentstate = svn_wc_notify_state_inapplicable;
if (propstate)
*propstate = svn_wc_notify_state_inapplicable;
if (tree_conflicted)
*tree_conflicted = FALSE;
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))
apr_hash_set(b->prop_changes, path, APR_HASH_KEY_STRING, path);
if (propstate)
*propstate = svn_wc_notify_state_inapplicable;
if (tree_conflicted)
*tree_conflicted = FALSE;
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_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);
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;
}