Author: rhuijben
Date: Thu Jan 24 23:52:07 2013
New Revision: 1438270
URL: http://svn.apache.org/viewvc?rev=1438270&view=rev
Log:
Following up on r1438264, make libsvn_client's repository diff handler drive a
diff processor instead of the old diff callbacks. Provide a state handler for
the merge support handling.
* subversion/libsvn_client/merge.c
(merge_dir_opened): Suppress further calls afster marking a tree conflict.
The old processing relied on the tree_conflicted value to imly skip.
* subversion/libsvn_client/repos_diff.c
(edit_baton): Store processor instead of callbacks.
(dir_baton,
file_baton): Keep processor batons and left and right source.
(get_file_mime_types): Remove now unneeded function.
(open_root): Initialize left and right source.
(diff_deleted_file,
diff_deleted_dir,
delete_entry,
add_directory,
open_directory,
add_file,
open_file,
close_file.
close_directory): Drive the diff tree processor instead of the callbacks.
Extract alle notification handling into ...
(diff_state_handle): ... this new function. (Yes I know this code is ugly!)
(diff_state_close): New function. Handling directory closure.
(svn_client__get_diff_editor): Initialize the diff processor.
Modified:
subversion/trunk/subversion/libsvn_client/merge.c
subversion/trunk/subversion/libsvn_client/repos_diff.c
Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1438270&r1=1438269&r2=1438270&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Thu Jan 24 23:52:07 2013
@@ -2557,6 +2557,7 @@ merge_dir_opened(svn_boolean_t *tree_con
SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_dir,
svn_wc_conflict_action_edit, reason));
*tree_conflicted = TRUE;
+ *skip = TRUE;
*skip_children = TRUE;
}
}
Modified: subversion/trunk/subversion/libsvn_client/repos_diff.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/repos_diff.c?rev=1438270&r1=1438269&r2=1438270&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/repos_diff.c Thu Jan 24 23:52:07
2013
@@ -56,10 +56,8 @@ struct edit_baton {
/* The passed depth */
svn_depth_t depth;
- /* The callback and calback argument that implement the file comparison
- function */
- const svn_wc_diff_callbacks4_t *diff_callbacks;
- void *diff_cmd_baton;
+ /* The result processor */
+ svn_diff_tree_processor_t *processor;
/* RA_SESSION is the open session for making requests to the RA layer */
svn_ra_session_t *ra_session;
@@ -147,6 +145,11 @@ struct dir_baton {
/* Boolean indicating whether a node property was changed */
svn_boolean_t has_propchange;
+ /* Baton for svn_diff_tree_processor_t */
+ void *pdb;
+ svn_diff_source_t *left_source;
+ svn_diff_source_t *right_source;
+
/* The pool passed in by add_dir, open_dir, or open_root.
Also, the pool this dir baton is allocated in. */
apr_pool_t *pool;
@@ -206,6 +209,11 @@ struct file_baton {
/* Boolean indicating whether a node property was changed */
svn_boolean_t has_propchange;
+ /* Baton for svn_diff_tree_processor_t */
+ void *pfb;
+ svn_diff_source_t *left_source;
+ svn_diff_source_t *right_source;
+
/* The pool passed in by add_file or open_file.
Also, the pool this file_baton is allocated in. */
apr_pool_t *pool;
@@ -269,49 +277,6 @@ make_file_baton(const char *path,
return file_baton;
}
-/* Helper function: return up to two svn:mime-type values buried
- * within a file baton. Set *MIMETYPE1 to the value within the file's
- * pristine properties, or NULL if not available. Set *MIMETYPE2 to
- * the value within the "new" file's propchanges, or NULL if not
- * available.
- */
-static void
-get_file_mime_types(const char **mimetype1,
- const char **mimetype2,
- struct file_baton *fb)
-{
- /* Defaults */
- *mimetype1 = NULL;
- *mimetype2 = NULL;
-
- if (fb->pristine_props)
- {
- svn_string_t *pristine_val;
- pristine_val = apr_hash_get(fb->pristine_props, SVN_PROP_MIME_TYPE,
- strlen(SVN_PROP_MIME_TYPE));
- if (pristine_val)
- *mimetype2 = *mimetype1 = pristine_val->data;
- }
-
- if (fb->propchanges)
- {
- int i;
- svn_prop_t *propchange;
-
- for (i = 0; i < fb->propchanges->nelts; i++)
- {
- propchange = &APR_ARRAY_IDX(fb->propchanges, i, svn_prop_t);
- if (strcmp(propchange->name, SVN_PROP_MIME_TYPE) == 0)
- {
- if (propchange->value)
- *mimetype2 = propchange->value->data;
- break;
- }
- }
- }
-}
-
-
/* Get revision FB->base_revision of the file described by FB from the
* repository, through FB->edit_baton->ra_session.
*
@@ -507,6 +472,9 @@ open_root(void *edit_baton,
struct dir_baton *db = make_dir_baton("", NULL, eb, FALSE, base_revision,
pool);
+ db->left_source = svn_diff__source_create(eb->revision, db->pool);
+ db->right_source = svn_diff__source_create(eb->target_revision, db->pool);
+
*root_baton = db;
return SVN_NO_ERROR;
}
@@ -515,53 +483,41 @@ open_root(void *edit_baton,
*/
static svn_error_t *
diff_deleted_file(const char *path,
+ void *ppdb,
struct edit_baton *eb,
apr_pool_t *scratch_pool)
{
struct file_baton *fb = make_file_baton(path, FALSE, eb, scratch_pool);
-/* struct edit_baton *eb = fb->edit_baton;*/
- const char *mimetype1, *mimetype2;
- svn_boolean_t tree_conflicted = FALSE;
- svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
- svn_wc_notify_action_t action = svn_wc_notify_skip;
+ svn_boolean_t skip = FALSE;
+ svn_diff_source_t *left_source = svn_diff__source_create(eb->revision,
+ scratch_pool);
if (eb->cancel_func)
SVN_ERR(eb->cancel_func(eb->cancel_baton));
- if (eb->text_deltas)
- SVN_ERR(get_file_from_ra(fb, FALSE, scratch_pool));
- else
- SVN_ERR(get_empty_file(eb, &fb->path_start_revision));
- SVN_ERR(get_empty_file(eb, &fb->path_end_revision));
- get_file_mime_types(&mimetype1, &mimetype2, fb);
-
- SVN_ERR(eb->diff_callbacks->file_deleted(&state, &tree_conflicted,
- fb->path,
- fb->path_start_revision,
- fb->path_end_revision,
- mimetype1, mimetype2,
- fb->pristine_props,
- eb->diff_cmd_baton,
- scratch_pool));
-
- if ((state != svn_wc_notify_state_missing)
- && (state != svn_wc_notify_state_obstructed)
- && !tree_conflicted)
- {
- action = svn_wc_notify_update_delete;
- }
+ SVN_ERR(eb->processor->file_opened(&fb->pfb, &skip, path,
+ left_source,
+ NULL /* right_source */,
+ NULL /* copyfrom_source */,
+ ppdb,
+ eb->processor,
+ scratch_pool, scratch_pool));
- if (eb->notify_func)
- {
- const char *deleted_path = apr_pstrdup(eb->pool, path);
- deleted_path_notify_t *dpn = apr_pcalloc(eb->pool, sizeof(*dpn));
+ if (eb->cancel_func)
+ SVN_ERR(eb->cancel_func(eb->cancel_baton));
- dpn->kind = svn_node_dir;
- dpn->action = tree_conflicted ? svn_wc_notify_tree_conflict : action;
- dpn->state = state;
- dpn->tree_conflicted = tree_conflicted;
- apr_hash_set(eb->deleted_paths, deleted_path, APR_HASH_KEY_STRING, dpn);
- }
+ if (skip)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(get_file_from_ra(fb, ! eb->text_deltas, scratch_pool));
+
+ SVN_ERR(eb->processor->file_deleted(fb->path,
+ left_source,
+ fb->path_start_revision,
+ fb->pristine_props,
+ fb->pfb,
+ eb->processor,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -577,25 +533,42 @@ diff_deleted_file(const char *path,
/* ### TODO: Handle depth. */
static svn_error_t *
diff_deleted_dir(const char *path,
+ void *ppdb,
struct edit_baton *eb,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- svn_boolean_t tree_conflicted = FALSE;
svn_boolean_t skip = FALSE;
svn_boolean_t skip_children = FALSE;
+ apr_hash_t *dirents = NULL;
+ apr_hash_t *left_props = NULL;
+ svn_diff_source_t *left_source = svn_diff__source_create(eb->revision,
+ scratch_pool);
+ void *pdb;
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(eb->revision));
if (eb->cancel_func)
SVN_ERR(eb->cancel_func(eb->cancel_baton));
-
- SVN_ERR(eb->diff_callbacks->dir_opened(&tree_conflicted, &skip,
- &skip_children, path,
- eb->revision,
- eb->diff_cmd_baton,
- iterpool));
+ SVN_ERR(eb->processor->dir_opened(&pdb, &skip, &skip_children,
+ path,
+ left_source,
+ NULL /* right_source */,
+ NULL /* copyfrom_source */,
+ ppdb,
+ eb->processor,
+ scratch_pool, iterpool));
+
+ if (!skip || !skip_children)
+ SVN_ERR(svn_ra_get_dir2(eb->ra_session,
+ skip_children ? NULL : &dirents,
+ NULL,
+ skip ? NULL : &left_props,
+ path,
+ eb->revision,
+ SVN_DIRENT_KIND,
+ scratch_pool));
/* The "old" dir will be skipped by the repository report. If required,
* crawl it recursively, diffing each file against the empty file. This
@@ -604,15 +577,6 @@ diff_deleted_dir(const char *path,
if (! skip_children && eb->walk_deleted_repos_dirs)
{
apr_hash_index_t *hi;
- apr_hash_t *dirents;
-
- SVN_ERR(svn_ra_get_dir2(eb->ra_session,
- &dirents,
- NULL, NULL,
- path,
- eb->revision,
- SVN_DIRENT_KIND,
- scratch_pool));
for (hi = apr_hash_first(scratch_pool, dirents); hi;
hi = apr_hash_next(hi))
@@ -627,45 +591,23 @@ diff_deleted_dir(const char *path,
if (dirent->kind == svn_node_file)
{
- SVN_ERR(diff_deleted_file(child_path, eb, iterpool));
+ SVN_ERR(diff_deleted_file(child_path, pdb, eb, iterpool));
}
else if (dirent->kind == svn_node_dir)
{
- SVN_ERR(diff_deleted_dir(child_path, eb, iterpool));
+ SVN_ERR(diff_deleted_dir(child_path, pdb, eb, iterpool));
}
}
}
if (! skip)
{
- svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
- svn_wc_notify_action_t action = svn_wc_notify_skip;
-
- SVN_ERR(send_delete_notify(eb, path, iterpool));
-
- /* ### Sorry, no way to hand over the properties */
- SVN_ERR(eb->diff_callbacks->dir_deleted(&state, &tree_conflicted,
- path, eb->diff_cmd_baton,
- iterpool));
-
- if ((state != svn_wc_notify_state_missing)
- && (state != svn_wc_notify_state_obstructed)
- && !tree_conflicted)
- {
- action = svn_wc_notify_update_delete;
- }
-
- if (eb->notify_func)
- {
- const char *deleted_path = apr_pstrdup(eb->pool, path);
- deleted_path_notify_t *dpn = apr_pcalloc(eb->pool, sizeof(*dpn));
-
- dpn->kind = svn_node_dir;
- dpn->action = tree_conflicted ? svn_wc_notify_tree_conflict : action;
- dpn->state = state;
- dpn->tree_conflicted = tree_conflicted;
- apr_hash_set(eb->deleted_paths, deleted_path, APR_HASH_KEY_STRING,
dpn);
- }
+ SVN_ERR(eb->processor->dir_deleted(path,
+ left_source,
+ left_props,
+ pdb,
+ eb->processor,
+ scratch_pool));
}
svn_pool_destroy(iterpool);
@@ -698,12 +640,12 @@ delete_entry(const char *path,
{
case svn_node_file:
{
- SVN_ERR(diff_deleted_file(path, eb, scratch_pool));
+ SVN_ERR(diff_deleted_file(path, pb->pdb, eb, scratch_pool));
break;
}
case svn_node_dir:
{
- SVN_ERR(diff_deleted_dir(path, eb, scratch_pool));
+ SVN_ERR(diff_deleted_dir(path, pb->pdb, eb, scratch_pool));
break;
}
default:
@@ -727,7 +669,6 @@ add_directory(const char *path,
struct dir_baton *pb = parent_baton;
struct edit_baton *eb = pb->edit_baton;
struct dir_baton *db;
- svn_wc_notify_state_t state;
/* ### TODO: support copyfrom? */
@@ -743,64 +684,19 @@ add_directory(const char *path,
return SVN_NO_ERROR;
}
+ db->right_source = svn_diff__source_create(eb->target_revision,
+ db->pool);
- SVN_ERR(eb->diff_callbacks->dir_added(
- &state, &db->tree_conflicted,
- &db->skip, &db->skip_children, db->path,
- eb->target_revision, copyfrom_path, copyfrom_revision,
- eb->diff_cmd_baton, pool));
-
- /* Notifications for directories are done at close_directory time.
- * But for paths at which the editor drive adds directories, we make an
- * exception to this rule, so that the path appears in the output before
- * any children of the newly added directory. Since a deletion at this path
- * must have happened before this addition, we can safely notify about
- * replaced directories here, too. */
- if (eb->notify_func)
- {
- deleted_path_notify_t *dpn;
- svn_wc_notify_t *notify;
- svn_wc_notify_action_t action;
- svn_node_kind_t kind = svn_node_dir;
-
- /* Find out if a pending delete notification for this path is
- * still around. */
- dpn = apr_hash_get(eb->deleted_paths, db->path, APR_HASH_KEY_STRING);
- if (dpn)
- {
- /* If any was found, we will handle the pending 'deleted path
- * notification' (DPN) here. Remove it from the list. */
- apr_hash_set(eb->deleted_paths, db->path,
- APR_HASH_KEY_STRING, NULL);
-
- /* the pending delete might be on a different node kind. */
- kind = dpn->kind;
- state = dpn->state;
- }
-
- /* Determine what the notification (ACTION) should be.
- * In case of a pending 'delete', this might become a 'replace'. */
- if (db->tree_conflicted)
- action = svn_wc_notify_tree_conflict;
- else if (dpn)
- {
- if (dpn->action == svn_wc_notify_update_delete)
- action = svn_wc_notify_update_replace;
- else
- /* Note: dpn->action might be svn_wc_notify_tree_conflict */
- action = dpn->action;
- }
- else if (state == svn_wc_notify_state_missing ||
- state == svn_wc_notify_state_obstructed)
- action = svn_wc_notify_skip;
- else
- action = svn_wc_notify_update_add;
-
- notify = svn_wc_create_notify(db->path, action, pool);
- notify->kind = kind;
- notify->content_state = notify->prop_state = state;
- (*eb->notify_func)(eb->notify_baton, notify, pool);
- }
+ SVN_ERR(eb->processor->dir_opened(&db->pdb,
+ &db->skip,
+ &db->skip_children,
+ db->path,
+ NULL,
+ db->right_source,
+ NULL /* copyfrom_source */,
+ pb->pdb,
+ eb->processor,
+ db->pool, db->pool));
return SVN_NO_ERROR;
}
@@ -829,10 +725,18 @@ open_directory(const char *path,
return SVN_NO_ERROR;
}
- SVN_ERR(eb->diff_callbacks->dir_opened(
- &db->tree_conflicted, &db->skip,
- &db->skip_children, db->path, base_revision,
- eb->diff_cmd_baton, pool));
+ db->left_source = svn_diff__source_create(eb->revision, db->pool);
+ db->right_source = svn_diff__source_create(eb->target_revision, db->pool);
+
+ SVN_ERR(eb->processor->dir_opened(&db->pdb,
+ &db->skip, &db->skip_children,
+ path,
+ db->left_source,
+ db->right_source,
+ NULL /* copyfrom */,
+ pb ? pb->pdb : NULL,
+ eb->processor,
+ db->pool, db->pool));
return SVN_NO_ERROR;
}
@@ -848,6 +752,7 @@ add_file(const char *path,
void **file_baton)
{
struct dir_baton *pb = parent_baton;
+ struct edit_baton *eb = pb->edit_baton;
struct file_baton *fb;
/* ### TODO: support copyfrom? */
@@ -864,6 +769,18 @@ add_file(const char *path,
fb->pristine_props = pb->edit_baton->empty_hash;
+ fb->right_source = svn_diff__source_create(eb->target_revision, fb->pool);
+
+ SVN_ERR(eb->processor->file_opened(&fb->pfb,
+ &fb->skip,
+ path,
+ NULL,
+ fb->right_source,
+ NULL /* copy source */,
+ pb->pdb,
+ eb->processor,
+ fb->pool, fb->pool));
+
return SVN_NO_ERROR;
}
@@ -890,9 +807,18 @@ open_file(const char *path,
fb->base_revision = base_revision;
- SVN_ERR(eb->diff_callbacks->file_opened(
- &fb->tree_conflicted, &fb->skip,
- fb->path, base_revision, eb->diff_cmd_baton, pool));
+ fb->left_source = svn_diff__source_create(eb->revision, fb->pool);
+ fb->right_source = svn_diff__source_create(eb->target_revision, fb->pool);
+
+ SVN_ERR(eb->processor->file_opened(&fb->pfb,
+ &fb->skip,
+ path,
+ fb->left_source,
+ fb->right_source,
+ NULL /* copy source */,
+ pb->pdb,
+ eb->processor,
+ fb->pool, fb->pool));
return SVN_NO_ERROR;
}
@@ -1013,8 +939,6 @@ close_file(void *file_baton,
{
struct file_baton *fb = file_baton;
struct edit_baton *eb = fb->edit_baton;
- svn_wc_notify_state_t content_state = svn_wc_notify_state_unknown;
- svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown;
apr_pool_t *scratch_pool;
/* Skip *everything* within a newly tree-conflicted directory. */
@@ -1042,9 +966,9 @@ close_file(void *file_baton,
fb->path));
}
- if (fb->path_end_revision || fb->has_propchange)
+ if (fb->added || fb->path_end_revision || fb->has_propchange)
{
- const char *mimetype1, *mimetype2;
+ apr_hash_t *right_props;
if (!fb->added && !fb->pristine_props)
{
@@ -1056,85 +980,35 @@ close_file(void *file_baton,
if (fb->pristine_props)
remove_non_prop_changes(fb->pristine_props, fb->propchanges);
- get_file_mime_types(&mimetype1, &mimetype2, fb);
-
+ right_props = svn_prop__patch(fb->pristine_props, fb->propchanges,
+ fb->pool);
if (fb->added)
- SVN_ERR(eb->diff_callbacks->file_added(
- &content_state, &prop_state, &fb->tree_conflicted,
- fb->path,
- fb->path_end_revision ? fb->path_start_revision : NULL,
- fb->path_end_revision,
- 0,
- eb->target_revision,
- mimetype1, mimetype2,
- NULL, SVN_INVALID_REVNUM,
- fb->propchanges, fb->pristine_props,
- eb->diff_cmd_baton,
- scratch_pool));
+ SVN_ERR(eb->processor->file_added(fb->path,
+ NULL /* copyfrom_src */,
+ fb->right_source,
+ NULL /* copyfrom_file */,
+ fb->path_end_revision,
+ NULL /* copyfrom_props */,
+ right_props,
+ fb->pfb,
+ eb->processor,
+ fb->pool));
else
- SVN_ERR(eb->diff_callbacks->file_changed(
- &content_state, &prop_state,
- &fb->tree_conflicted, fb->path,
- fb->path_end_revision ? fb->path_start_revision : NULL,
- fb->path_end_revision,
- eb->revision,
- eb->target_revision,
- mimetype1, mimetype2,
- fb->propchanges, fb->pristine_props,
- eb->diff_cmd_baton,
- scratch_pool));
- }
-
-
- if (eb->notify_func)
- {
- deleted_path_notify_t *dpn;
- svn_wc_notify_t *notify;
- svn_wc_notify_action_t action;
- svn_node_kind_t kind = svn_node_file;
-
- /* Find out if a pending delete notification for this path is
- * still around. */
- dpn = apr_hash_get(eb->deleted_paths, fb->path, APR_HASH_KEY_STRING);
- if (dpn)
- {
- /* If any was found, we will handle the pending 'deleted path
- * notification' (DPN) here. Remove it from the list. */
- apr_hash_set(eb->deleted_paths, fb->path,
- APR_HASH_KEY_STRING, NULL);
-
- /* the pending delete might be on a different node kind. */
- kind = dpn->kind;
- content_state = prop_state = dpn->state;
- }
-
- /* Determine what the notification (ACTION) should be.
- * In case of a pending 'delete', this might become a 'replace'. */
- if (fb->tree_conflicted)
- action = svn_wc_notify_tree_conflict;
- else if (dpn)
- {
- if (dpn->action == svn_wc_notify_update_delete
- && fb->added)
- action = svn_wc_notify_update_replace;
- else
- /* Note: dpn->action might be svn_wc_notify_tree_conflict */
- action = dpn->action;
- }
- else if ((content_state == svn_wc_notify_state_missing)
- || (content_state == svn_wc_notify_state_obstructed))
- action = svn_wc_notify_skip;
- else if (fb->added)
- action = svn_wc_notify_update_add;
- else
- action = svn_wc_notify_update_update;
-
- notify = svn_wc_create_notify(fb->path, action, scratch_pool);
- notify->kind = kind;
- notify->content_state = content_state;
- notify->prop_state = prop_state;
- (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ SVN_ERR(eb->processor->file_changed(fb->path,
+ fb->left_source,
+ fb->right_source,
+ fb->path_end_revision
+ ? fb->path_start_revision
+ : NULL,
+ fb->path_end_revision,
+ fb->pristine_props,
+ right_props,
+ (fb->path_end_revision != NULL),
+ fb->propchanges,
+ fb->pfb,
+ eb->processor,
+ fb->pool));
}
svn_pool_destroy(fb->pool); /* Destroy file and scratch pool */
@@ -1155,15 +1029,13 @@ close_directory(void *dir_baton,
{
struct dir_baton *db = dir_baton;
struct edit_baton *eb = db->edit_baton;
- svn_wc_notify_state_t content_state = svn_wc_notify_state_unknown;
- svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown;
- svn_boolean_t skipped = FALSE;
apr_pool_t *scratch_pool;
apr_hash_t *pristine_props;
+ svn_boolean_t send_changed = FALSE;
scratch_pool = db->pool;
- if (db->has_propchange && !db->skip)
+ if ((db->has_propchange || db->added) && !db->skip)
{
if (db->added)
{
@@ -1180,63 +1052,49 @@ close_directory(void *dir_baton,
remove_non_prop_changes(pristine_props, db->propchanges);
}
- if (db->propchanges->nelts > 0)
+ if (db->propchanges->nelts > 0 || db->added)
{
- svn_boolean_t tree_conflicted = FALSE;
- SVN_ERR(eb->diff_callbacks->dir_props_changed(
- &prop_state, &tree_conflicted,
- db->path, db->added,
- db->propchanges, pristine_props,
- eb->diff_cmd_baton, scratch_pool));
- if (tree_conflicted)
- db->tree_conflicted = TRUE;
+ apr_hash_t *right_props;
+
+ right_props = svn_prop__patch(pristine_props, db->propchanges,
+ scratch_pool);
- if (prop_state == svn_wc_notify_state_obstructed
- || prop_state == svn_wc_notify_state_missing)
+ if (db->added)
{
- content_state = prop_state;
- skipped = TRUE;
+ SVN_ERR(eb->processor->dir_added(db->path,
+ NULL /* copyfrom */,
+ db->right_source,
+ NULL /* copyfrom props */,
+ right_props,
+ db->pdb,
+ eb->processor,
+ db->pool));
+ }
+ else
+ {
+ SVN_ERR(eb->processor->dir_changed(db->path,
+ db->left_source,
+ db->right_source,
+ pristine_props,
+ right_props,
+ db->propchanges,
+ db->pdb,
+ eb->processor,
+ db->pool));
}
- }
- }
-
- SVN_ERR(eb->diff_callbacks->dir_closed(NULL, NULL, NULL,
- db->path, db->added,
- eb->diff_cmd_baton,
- scratch_pool));
- /* Notify about any deleted paths within this directory that have not
- * already been notified. */
- if (!skipped && !db->added && eb->notify_func)
- {
- SVN_ERR(send_delete_notify(eb, db->path, scratch_pool));
+ send_changed = TRUE; /* Skip dir_closed */
+ }
}
- /* Notify about this directory itself (unless it was added, in which
- * case the notification was done at that time). */
- if (!db->added && eb->notify_func && !db->skip)
+ if (! db->skip && !send_changed)
{
- svn_wc_notify_t *notify;
- svn_wc_notify_action_t action;
-
- if (db->tree_conflicted)
- action = svn_wc_notify_tree_conflict;
- else if (skipped)
- action = svn_wc_notify_skip;
- else
- action = svn_wc_notify_update_update;
-
- notify = svn_wc_create_notify(db->path, action, pool);
- notify->kind = svn_node_dir;
-
- /* In case of a tree conflict during merge, the diff callback
- * sets content_state appropriately. So copy the state into the
- * notify_t to make sure conflicts get displayed. */
- notify->content_state = content_state;
-
- notify->prop_state = prop_state;
- notify->lock_state = svn_wc_notify_lock_state_inapplicable;
- (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ SVN_ERR(eb->processor->dir_closed(db->path,
+ db->left_source,
+ db->right_source,
+ db->pdb,
+ eb->processor,
+ db->pool));
}
svn_pool_destroy(db->pool); /* Destroy baton and scratch_pool */
@@ -1470,6 +1328,224 @@ fetch_base_func(const char **filename,
return SVN_NO_ERROR;
}
+/** Callback for the svn_diff_tree_processor_t wrapper, to allow handling
+ * notifications like how the repos diff in libsvn_client does.
+ *
+ * Probably only necessary while transitioning to svn_diff_tree_processor_t
+ */
+static svn_error_t *
+diff_state_handle(svn_boolean_t tree_conflicted,
+ svn_wc_notify_state_t *state,
+ svn_wc_notify_state_t *prop_state,
+ const char *relpath,
+ svn_kind_t kind,
+ svn_boolean_t before_operation,
+ svn_boolean_t for_add,
+ svn_boolean_t for_delete,
+ void *state_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = state_baton;
+ svn_wc_notify_action_t action = svn_wc_notify_skip;
+
+ if (! eb->notify_func)
+ return SVN_NO_ERROR;
+
+ /* This code is copy & pasted from different functions in this file.
+ It is only used from the merge api, and should really be integrated
+ there.
+ */
+
+ if (for_delete)
+ {
+ const char *deleted_path;
+ deleted_path_notify_t *dpn;
+
+ if (before_operation && !tree_conflicted)
+ return SVN_NO_ERROR;
+
+ deleted_path = apr_pstrdup(eb->pool, relpath);
+ dpn = apr_pcalloc(eb->pool, sizeof(*dpn));
+
+ if (!tree_conflicted
+ && state
+ && (*state != svn_wc_notify_state_missing)
+ && (*state != svn_wc_notify_state_obstructed))
+ {
+ action = svn_wc_notify_update_delete;
+ }
+
+ dpn->kind = (kind == svn_kind_dir) ? svn_node_dir : svn_node_file;
+ dpn->action = tree_conflicted ? svn_wc_notify_tree_conflict : action;
+ dpn->state = state ? *state : svn_wc_notify_state_inapplicable;
+ dpn->tree_conflicted = tree_conflicted;
+ apr_hash_set(eb->deleted_paths, deleted_path, APR_HASH_KEY_STRING, dpn);
+
+ return SVN_NO_ERROR;
+ }
+ else if (kind == svn_kind_file)
+ {
+ deleted_path_notify_t *dpn;
+ svn_wc_notify_t *notify;
+ svn_wc_notify_action_t action;
+ svn_node_kind_t kind = svn_node_file;
+
+ /* Find out if a pending delete notification for this path is
+ * still around. */
+ dpn = apr_hash_get(eb->deleted_paths, relpath, APR_HASH_KEY_STRING);
+ if (dpn)
+ {
+ /* If any was found, we will handle the pending 'deleted path
+ * notification' (DPN) here. Remove it from the list. */
+ apr_hash_set(eb->deleted_paths, relpath,
+ APR_HASH_KEY_STRING, NULL);
+
+ /* the pending delete might be on a different node kind. */
+ kind = dpn->kind;
+ *state = *prop_state = dpn->state;
+ }
+
+ /* Determine what the notification (ACTION) should be.
+ * In case of a pending 'delete', this might become a 'replace'. */
+ if (tree_conflicted)
+ action = svn_wc_notify_tree_conflict;
+ else if (dpn)
+ {
+ if (dpn->action == svn_wc_notify_update_delete
+ && for_add)
+ action = svn_wc_notify_update_replace;
+ else
+ /* Note: dpn->action might be svn_wc_notify_tree_conflict */
+ action = dpn->action;
+ }
+ else if ((*state == svn_wc_notify_state_missing)
+ || (*state == svn_wc_notify_state_obstructed))
+ action = svn_wc_notify_skip;
+ else if (for_add)
+ action = svn_wc_notify_update_add;
+ else
+ action = svn_wc_notify_update_update;
+
+ notify = svn_wc_create_notify(relpath, action, scratch_pool);
+ notify->kind = kind;
+ notify->content_state = *state;
+ notify->prop_state = *prop_state;
+ (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ }
+ else if (for_add)
+ {
+ /* Notifications for directories are done at close_directory time.
+ * But for paths at which the editor drive adds directories, we make an
+ * exception to this rule, so that the path appears in the output before
+ * any children of the newly added directory. Since a deletion at this
path
+ * must have happened before this addition, we can safely notify about
+ * replaced directories here, too. */
+
+ deleted_path_notify_t *dpn;
+ svn_wc_notify_t *notify;
+ svn_wc_notify_action_t action;
+ svn_node_kind_t kind = svn_node_dir;
+
+ if (!before_operation && !tree_conflicted)
+ return SVN_NO_ERROR;
+
+ /* Find out if a pending delete notification for this path is
+ * still around. */
+ dpn = apr_hash_get(eb->deleted_paths, relpath, APR_HASH_KEY_STRING);
+ if (dpn)
+ {
+ /* If any was found, we will handle the pending 'deleted path
+ * notification' (DPN) here. Remove it from the list. */
+ apr_hash_set(eb->deleted_paths, relpath, APR_HASH_KEY_STRING, NULL);
+
+ /* the pending delete might be on a different node kind. */
+ kind = dpn->kind;
+ if (state)
+ *state = dpn->state;
+ }
+
+ /* Determine what the notification (ACTION) should be.
+ * In case of a pending 'delete', this might become a 'replace'. */
+ if (tree_conflicted)
+ action = svn_wc_notify_tree_conflict;
+ else if (dpn)
+ {
+ if (dpn->action == svn_wc_notify_update_delete)
+ action = svn_wc_notify_update_replace;
+ else
+ /* Note: dpn->action might be svn_wc_notify_tree_conflict */
+ action = dpn->action;
+ }
+ else if (state
+ && (*state == svn_wc_notify_state_missing
+ || *state == svn_wc_notify_state_obstructed))
+ {
+ action = svn_wc_notify_skip;
+ }
+ else
+ action = svn_wc_notify_update_add;
+
+ notify = svn_wc_create_notify(relpath, action, scratch_pool);
+ notify->kind = (kind == svn_kind_dir) ? svn_node_dir : svn_node_file;
+ notify->prop_state = state ? *state : svn_wc_notify_state_inapplicable;
+ notify->content_state = notify->prop_state;
+ (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ }
+ else /* Normal modification */
+ {
+ svn_wc_notify_t *notify;
+ svn_wc_notify_action_t action;
+ svn_wc_notify_state_t content_state;
+
+ content_state = state ? *state : svn_wc_notify_state_inapplicable;
+
+ if (tree_conflicted)
+ action = svn_wc_notify_tree_conflict;
+ else
+ action = svn_wc_notify_update_update;
+
+ if (prop_state
+ && (*prop_state == svn_wc_notify_state_obstructed
+ || *prop_state == svn_wc_notify_state_missing))
+ {
+ content_state = *prop_state;
+ if (action == svn_wc_notify_update_update)
+ action = svn_wc_notify_skip;
+ }
+
+
+ /* Dir modified */
+
+ notify = svn_wc_create_notify(relpath, action, scratch_pool);
+ notify->kind = svn_node_dir;
+
+ /* In case of a tree conflict during merge, the diff callback
+ * sets content_state appropriately. So copy the state into the
+ * notify_t to make sure conflicts get displayed. */
+ notify->content_state = content_state;
+
+ notify->prop_state = prop_state ? *prop_state
+ : svn_wc_notify_state_inapplicable;
+
+ notify->lock_state = svn_wc_notify_lock_state_inapplicable;
+ (*eb->notify_func)(eb->notify_baton, notify, scratch_pool);
+ }
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+diff_state_close(const char *relpath,
+ svn_kind_t kind,
+ void *state_baton,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = state_baton;
+ SVN_ERR(send_delete_notify(eb, relpath, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
/* Create a repository diff editor and baton. */
svn_error_t *
svn_client__get_diff_editor(const svn_delta_editor_t **editor,
@@ -1495,8 +1571,14 @@ svn_client__get_diff_editor(const svn_de
eb->pool = editor_pool;
eb->depth = depth;
- eb->diff_callbacks = diff_callbacks;
- eb->diff_cmd_baton = diff_cmd_baton;
+
+ SVN_ERR(svn_wc__wrap_diff_callbacks(&eb->processor,
+ diff_callbacks, diff_cmd_baton,
+ diff_state_handle,
+ diff_state_close,
+ eb,
+ result_pool, result_pool));
+
eb->ra_session = ra_session;
eb->revision = revision;