/**
* @copyright
* ====================================================================
* 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.
* ====================================================================
* @endcopyright
*
* @file svn_diff_tree.h
* @brief Generic diff handler. Replacing the old svn_wc_diff_callbacks4_t
* infrastructure
*/
#ifndef SVN_DIFF_TREE_H
#define SVN_DIFF_TREE_H
#include "svn_types.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* About the diff tree processor.
*
* Subversion uses two kinds of editors to describe changes. One to
* describe changes on how to *exactly* transform one tree to another tree,
* as efficiently as possible and one to describe the difference between trees
* in order to review the changes, or to allow applying them on a third tree
* which is similar to those other trees.
*
* The first case was originally handled by svn_delta_editor_t and might be
* replaced by svn_editor_t in a future version. This diff processor handles
* the other case and as such forms the layer below our diff and merge
* handling.
*
* The major difference between this and the other editors is that this diff
* always provides access to the full text and/or properties in the left and
* right tree when applicable to allow processor implementers to decide how
* to interpret changes.
*
* Originally this diff processor was not formalized explicitly, but
* informally handled by the working copy diff callbacks. These callbacks just
* provided the information to drive a unified diff and a textual merge. To go
* one step further and allow full tree conflict detection we needed a better
* defined diff handling. Instead of adding yet a few more functions and
* arguments to the already overloaded diff callbacks the api was completely
* redesigned with a few points in mind.
*
* * It must be able to drive the old callbacks interface without users
* noticing the difference (100% compatible).
* (Implemented as svn_wc__wrap_diff_callbacks())
*
* * It should provide the information that was missing in the old interface,
* but required to close existing issues.
*
* E.g. - properties and children on deleted directories.
* - revision numbers and copyfrom information on directories.
*
* To cleanup the implementation and make it easier on diff processors to
* handle the results I also added the following constraints.
*
* * Diffs should be fully reversable: anything that is deleted should be
* available, just like something that is added.
* (Proven via svn_diff__tree_processor_reverse_create)
* ### Still in doubt if *_deleted() needs a copy_to argument, for the
* ### 99% -> 100%.
*
* * Diff processors should have an easy way to communicate that they are
* not interrested in certain expensive to obtain results.
*
* * Directories should have clear open and close events to allow adding them
* before their children, but still allowing property changes to have
* defined behavior.
*
* * Files and directories should be handled as similar as possible as in
* many cases they are just nodes in a tree.
*
* * It should be easy to create diff wrappers to apply certain transforms.
*
* During the creation an additional requirement of knowing about 'some
* absent' nodes was added, to allow the merge to work on just this processor
* api.
*
* The api describes a clean open-close walk through a tree, depending on the
* driver multiple siblings can be described at the same time, but when a
* directory is closed all descendants are done.
*
* Note that it is possible for nodes to be described as a delete followed by
* an add at the same place within one parent. (Iff the diff is reversed you
* can see an add followed by a delete!)
* ### "An add followed by a delete" sounds wrong.
*
* The directory batons live between the open and close events of a directory
* and are thereby guaranteed to outlive the batons of their descendants.
*/
/* Describes the source of a merge */
/* ### You mean a diff?
* ### How come many users don't set the 'repos_relpath' field? */
typedef struct svn_diff_source_t
{
/* Always available
In case of copyfrom: the revision copied from
*/
svn_revnum_t revision;
/* In case of copyfrom: the repository relative path copied from.
NULL if the node wasn't copied or moved, or when the driver doesn't
have this information */
const char *repos_relpath;
/* In case of copyfrom: the relative path of source location before the
move. This path is relative WITHIN THE DIFF. The repository path is
typically in repos_relpath
NULL if the node wasn't moved or if the driver doesn't have this
information. */
const char *moved_from_relpath;
} svn_diff_source_t;
/**
* A callback vtable invoked by our diff-editors, as they receive diffs
* from the server. 'svn diff' and 'svn merge' implement their own versions
* of this vtable.
*
* All callbacks receive the processor and at least a parent baton. Forwarding
* the processor allows future extensions to call into the old functions without
* revving the entire API.
*
* Users must call svn_diff__tree_processor_create() to allow adding new
* callbacks later. (E.g. when we decide how to add move support) These
* extensions can then just call into other callbacks.
*
* @since New in 1.8.
*/
typedef struct svn_diff_tree_processor_t
{
/** The value passed to svn_diff__tree_processor_create() as BATON.
*/
void *baton; /* To avoid an additional in some places
* ### What? */
/* Called before a directory's children are processed.
*
* Set *SKIP_CHILDREN to TRUE, to skip calling callbacks for all
* children.
*
* Set *SKIP to TRUE to skip calling the added, deleted, changed
* or closed callback for this node only.
*/
svn_error_t *
(*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);
/* Called after a directory and all its children are added
*/
svn_error_t *
(*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);
/* Called after all children of this node are reported as deleted.
*
* The default implementation calls dir_closed().
*/
svn_error_t *
(*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);
/* Called instead of dir_closed() if the properties on the directory
* were modified.
*
* The default implementation calls dir_closed().
*/
svn_error_t *
(*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);
/* Called when a directory is closed without applying changes to
* the directory itself.
*
* When dir_changed or dir_deleted are handled by the default implementation
* they call dir_closed()
*/
svn_error_t *
(*dir_closed)(const char *relpath,
const svn_diff_source_t *left_source,
const svn_diff_source_t *right_source,
void *dir_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool);
/* Called before file_added(), file_deleted(), file_changed() and
file_closed()
*/
svn_error_t *
(*file_opened)(void **new_file_baton,
svn_boolean_t *skip,
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 *dir_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
/* Called after file_opened() for newly added and copied files */
svn_error_t *
(*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);
/* Called after file_opened() for deleted or moved away files */
svn_error_t *
(*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);
/* Called after file_opened() for changed files */
svn_error_t *
(*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);
/* Called after file_opened() for unmodified files */
svn_error_t *
(*file_closed)(const char *relpath,
const svn_diff_source_t *left_source,
const svn_diff_source_t *right_source,
void *file_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool);
/* Called when encountering a marker for an absent file or directory */
svn_error_t *
(*node_absent)(const char *relpath,
void *dir_baton,
const struct svn_diff_tree_processor_t *processor,
apr_pool_t *scratch_pool);
} svn_diff_tree_processor_t;
/**
* Create a new svn_diff_tree_processor_t instance with all functions
* set to a callback doing nothing but copying the parent baton to
* the new baton.
*
* @since New in 1.8.
*/
svn_diff_tree_processor_t *
svn_diff__tree_processor_create(void *baton,
apr_pool_t *result_pool);
/**
* Create a new svn_diff_tree_processor_t instance with all functions setup
* to call into another svn_diff_tree_processor_t processor, but with all
* adds and deletes inverted.
*
* @since New in 1.8.
*/ /* Used by libsvn clients repository diff */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor,
apr_pool_t *result_pool);
/**
* Create a new svn_diff_tree_processor_t instance with all functions setup
* to call into processor for all paths equal to and below prefix_relpath.
*
* @since New in 1.8.
*/ /* Used by libsvn clients repository diff */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t *processor,
const char *prefix_relpath,
apr_pool_t *result_pool);
/**
* Create a new svn_diff_tree_processor_t instance with all function setup
* to call into processor with all adds with copyfrom information transformed
* to simple node changes.
*
* @since New in 1.8.
*/ /* Used by libsvn_wc diff editor */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_copy_as_changed_create(
const svn_diff_tree_processor_t *processor,
apr_pool_t *result_pool);
/**
* Create a new svn_diff_tree_processor_t instance with all functions setup
* to first call into processor1 and then processor2.
*
* This function is mostly a debug and migration helper.
*
* @since New in 1.8.
*/ /* Used by libsvn clients repository diff */
const svn_diff_tree_processor_t *
svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1,
const svn_diff_tree_processor_t *processor2,
apr_pool_t *result_pool);
svn_diff_source_t *
svn_diff__source_create(svn_revnum_t revision,
apr_pool_t *result_pool);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SVN_DIFF_TREE_H */