/** * @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_wc.h * @brief Generic diff handler. Replacing the old svn_wc_diff_callbacks4_t * infrastructure */ #ifndef SVN_DIFF_PROCESSOR_H #define SVN_DIFF_PROCESSOR_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!) * * 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 */ typedef struct svn_diff_source_t { /* Always available */ svn_revnum_t revision; /* Depending on the driver available for copyfrom */ const char *repos_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 */ /* Called before a directories 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, const char *prefix_relpath, 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 instace 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_PROCESSOR_H */