You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2012/11/19 20:10:11 UTC
svn commit: r1411356 - in /subversion/branches/tree-read-api/subversion:
include/svn_tree.h libsvn_subr/tree.c
Author: julianfoad
Date: Mon Nov 19 19:10:10 2012
New Revision: 1411356
URL: http://svn.apache.org/viewvc?rev=1411356&view=rev
Log:
On the 'tree-read-api' branch:
Add a 'walk_singleton_dirs' option to the two-trees walker.
* subversion/include/svn_tree.h
(svn_tree_walk_two): Add a 'walk_singleton_dirs' option. Improve docs.
* subversion/libsvn_subr/tree.c
(get_child): New function.
(walk_two_trees, svn_tree_walk_two): Add and implement the
'walk_singleton_dirs' option.
Modified:
subversion/branches/tree-read-api/subversion/include/svn_tree.h
subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c
Modified: subversion/branches/tree-read-api/subversion/include/svn_tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/include/svn_tree.h?rev=1411356&r1=1411355&r2=1411356&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/svn_tree.h (original)
+++ subversion/branches/tree-read-api/subversion/include/svn_tree.h Mon Nov 19 19:10:10 2012
@@ -146,23 +146,37 @@ typedef svn_error_t *(*svn_tree_walk_two
void *walk_baton,
apr_pool_t *scratch_pool);
-/** Walk the two generic trees @a tree1 and @a tree2, simultaneously,
- * recursing to @a depth.
+/** Walk the two generic trees @a tree1 and @a tree2, simultaneously.
+ * Recurse as far as @a depth in each tree.
*
* Call @a walk_func for each node, passing @a walk_baton and the tree
* node object.
*
+ * When a directory appears in just one of the trees, visit it, and if @a
+ * walk_singleton_dirs is TRUE, then also walk its contents, passing NULL
+ * as the node on the other side. The walk recurses only as far as @a
+ * depth, interpreted relative to the root of @a tree1 and @a tree2.
+ *
* If @a cancel_func is not null, call it with @a cancel_baton to check for
- * cancellation.
+ * cancellation, approximately once per directory.
+ *
+ * @note This function provides no information on the historical ancestry
+ * or versioning relationship between a pair of nodes. Nodes at the same
+ * relative path are visited together regardless of whether they are, at one
+ * extreme, different kinds of node within entirely unrelated trees, or, at
+ * the other extreme, references to exactly the same node in two instances
+ * of the same tree.
*
- * TODO: Visit nodes with the same id at the same time, thus tracking moves.
+ * TODO: Make another walker that visits nodes with the same id at the same
+ * time, regardless of their relative paths, thus tracking moves?
* TODO: Let the callback determine the order of walking sub-nodes,
- * especially with respect to far-moves (moves into or out of a directory).
+ * especially with respect to far-moves (moves into or out of a directory)?
*/
svn_error_t *
svn_tree_walk_two(svn_tree_t *tree1,
svn_tree_t *tree2,
svn_depth_t depth,
+ svn_boolean_t walk_singleton_dirs,
const svn_tree_walk_two_func_t walk_func,
void *walk_baton,
svn_cancel_func_t cancel_func,
Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c?rev=1411356&r1=1411355&r2=1411356&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c Mon Nov 19 19:10:10 2012
@@ -254,18 +254,53 @@ svn_tree_walk(svn_tree_t *tree,
return SVN_NO_ERROR;
}
-/* Walk two trees, rooted at NODE1 and NODE2, simultaneously, driving the
- * CALLBACKS.
+/* Get the child node named NAME from CHILDREN, if it falls within the
+ * requested DEPTH.
*
- * Currently visits nodes with the same relpath at the same time; see TODO
- * notes on svn_tree_walk_two().
+ * CHILDREN maps (const char *) names to (svn_tree_node_t *) child nodes.
+ * DEPTH is relative to the parent node of CHILDREN and is at least 'files'.
*
- * TODO: allow recursing into a singleton directory (that is, on one side)?
+ * If NAME is not present in CHILDREN, or DEPTH is 'files' and the child
+ * node is not a file, then set *CHILD to NULL.
+ */
+static svn_error_t *
+get_child(svn_tree_node_t **child,
+ apr_hash_t *children,
+ const char *name,
+ svn_depth_t depth,
+ apr_pool_t *scratch_pool)
+{
+ /* We shouldn't be called for depth less than 'files'. */
+ assert(depth >= svn_depth_files);
+
+ *child = apr_hash_get(children, name, APR_HASH_KEY_STRING);
+
+ /* If we want to omit directory children, do so now. */
+ if (*child && depth == svn_depth_files)
+ {
+ svn_node_kind_t kind;
+
+ SVN_ERR(tree_node_get_kind_or_unknown(&kind, *child, scratch_pool));
+ if (kind == svn_node_dir)
+ *child = NULL;
+ }
+ return SVN_NO_ERROR;
+}
+
+/* Walk two trees, rooted at NODE1 and NODE2, in parallel, visiting nodes
+ * with the same relpath at the same time.
+ *
+ * Call the WALK_FUNC with WALK_BATON for each visited pair of nodes.
+ * Recurse as far as DEPTH. When a directory appears at a given path only
+ * in one of the trees, recurse into it only if WALK_SINGLETON_DIRS is true.
+ *
+ * Use CANCEL_FUNC with CANCEL_BATON for cancellation.
*/
static svn_error_t *
walk_two_trees(svn_tree_node_t *node1,
svn_tree_node_t *node2,
svn_depth_t depth,
+ svn_boolean_t walk_singleton_dirs,
const svn_tree_walk_two_func_t walk_func,
void *walk_baton,
svn_cancel_func_t cancel_func,
@@ -299,27 +334,28 @@ walk_two_trees(svn_tree_node_t *node1,
SVN_ERR(walk_func(node1, node2, walk_baton, scratch_pool));
- SVN_DBG(("walk_two_trees: kind %d/%d, '%s'\n",
- kind1, kind2, relpath1 ? relpath1 : relpath2));
-
- /* Recurse, if it's a directory on BOTH sides. (If it's a directory on
- * just one side (it's a replacement), we want to treat that just the same
- * as a deleted or added directory: it's up to the callback to traverse
- * the singleton if it wants to.) */
- if (node1 && node2
- && kind1 == svn_node_dir
- && kind2 == svn_node_dir
- && depth >= svn_depth_files)
+ /* Recurse, if it's a directory on BOTH sides or if we're walking
+ * singleton directories. */
+ if (depth >= svn_depth_files
+ && ((kind1 == svn_node_dir && kind2 == svn_node_dir)
+ || ((kind1 == svn_node_dir || kind2 == svn_node_dir)
+ && walk_singleton_dirs)))
{
apr_hash_t *children1, *children2;
apr_hash_t *all_children;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_hash_index_t *hi;
- SVN_ERR(svn_tree_node_read_dir(node1, &children1, NULL,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_tree_node_read_dir(node2, &children2, NULL,
- scratch_pool, scratch_pool));
+ if (kind1 == svn_node_dir)
+ SVN_ERR(svn_tree_node_read_dir(node1, &children1, NULL,
+ scratch_pool, scratch_pool));
+ else
+ children1 = apr_hash_make(scratch_pool);
+ if (kind2 == svn_node_dir)
+ SVN_ERR(svn_tree_node_read_dir(node2, &children2, NULL,
+ scratch_pool, scratch_pool));
+ else
+ children2 = apr_hash_make(scratch_pool);
all_children = apr_hash_overlay(scratch_pool, children1, children2);
SVN_DBG(("Recursing (%d||%d=%d children) in '%s'\n",
@@ -327,26 +363,23 @@ walk_two_trees(svn_tree_node_t *node1,
apr_hash_count(all_children),
relpath1));
+ /* Iterate through the children in parallel, pairing them up by name. */
for (hi = apr_hash_first(scratch_pool, all_children); hi;
hi = apr_hash_next(hi))
{
- const char *relpath = svn__apr_hash_index_key(hi);
- svn_tree_node_t *child1 = apr_hash_get(children1, relpath,
- APR_HASH_KEY_STRING);
- svn_tree_node_t *child2 = apr_hash_get(children2, relpath,
- APR_HASH_KEY_STRING);
- svn_node_kind_t child_kind;
+ const char *name = svn__apr_hash_index_key(hi);
+ svn_tree_node_t *child1, *child2;
svn_pool_clear(iterpool);
- SVN_ERR(tree_node_get_kind_or_unknown(&child_kind,
- child1 ? child1 : child2,
- iterpool));
- if (depth >= svn_depth_immediates || child_kind == svn_node_file)
+ SVN_ERR(get_child(&child1, children1, name, depth, iterpool));
+ SVN_ERR(get_child(&child2, children2, name, depth, iterpool));
+
+ if (child1 || child2)
{
SVN_ERR(walk_two_trees(child1, child2,
depth == svn_depth_infinity ? depth
- : svn_depth_empty,
+ : svn_depth_empty, walk_singleton_dirs,
walk_func, walk_baton,
cancel_func, cancel_baton,
iterpool));
@@ -362,6 +395,7 @@ svn_error_t *
svn_tree_walk_two(svn_tree_t *tree1,
svn_tree_t *tree2,
svn_depth_t depth,
+ svn_boolean_t walk_singleton_dirs,
const svn_tree_walk_two_func_t walk_func,
void *walk_baton,
svn_cancel_func_t cancel_func,
@@ -374,7 +408,7 @@ svn_tree_walk_two(svn_tree_t *tree1,
SVN_ERR(svn_tree_get_root_node(&node2, tree2, scratch_pool, scratch_pool));
SVN_ERR(walk_two_trees(node1, node2,
- depth,
+ depth, walk_singleton_dirs,
walk_func, walk_baton,
cancel_func, cancel_baton,
scratch_pool));