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/16 21:04:32 UTC
svn commit: r1410554 - in /subversion/branches/tree-read-api/subversion:
include/svn_tree.h libsvn_subr/tree.c
Author: julianfoad
Date: Fri Nov 16 20:04:31 2012
New Revision: 1410554
URL: http://svn.apache.org/viewvc?rev=1410554&view=rev
Log:
On the 'tree-read-api' branch: Change the tree traversal method to
per-directory visiting -- similar to Python's os.walk() function. This
inreases efficiency and flexibility. We provide a per-node walker built
on top of it.
* subversion/include/svn_tree.h
(svn_tree_dir_visit_func_t, svn_tree_walk_dirs): New function type and
function for per-directory walking.
(svn_tree_walk_func_t): Remove the TODO comment relating to this change.
* subversion/libsvn_subr/tree.c
(walk_dirs): Renamed from 'walk_tree' and adapted to walk only directories.
(svn_tree_walk_dirs): New function.
(per_dir_to_per_node_baton_t, per_dir_to_per_node_cb): New callback baton
and function.
(svn_tree_walk): Re-implement using walk_dirs() and the per_dir_to_per_node
callback.
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=1410554&r1=1410553&r2=1410554&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/svn_tree.h (original)
+++ subversion/branches/tree-read-api/subversion/include/svn_tree.h Fri Nov 16 20:04:31 2012
@@ -58,13 +58,51 @@ svn_tree_get_node_by_relpath(svn_tree_no
/** A tree-walker callback.
*
+ * The callback receives one directory node being visited, @a dir_node, and
+ * the closure @a dir_visit_baton. It also receives two lists of nodes
+ * which together contain all the children to be visited. The
+ * subdirectories are in @a subdirs, and the non-directory children in @a
+ * files.
+ *
+ * This is modeled on Python's 'os.walk' function.
+ *
+ * ### TODO? "The callback may modify the list of subdirs (in place) in
+ * order to influence the order and scope of traversal: the walker will
+ * recurse into the subdirs that are in the list when the callback returns."
+ *
+ * @a scratch_pool is available for use within the function until it returns.
+ */
+typedef svn_error_t *
+(*svn_tree_dir_visit_func_t)(svn_tree_node_t *dir_node,
+ apr_array_header_t *subdirs,
+ apr_array_header_t *files,
+ void *dir_visit_baton,
+ apr_pool_t *scratch_pool);
+
+/** Walk a subdirectory of a generic tree, starting at @a root_dir_node.
+ *
+ * ...
+ *
+ * Call @a dir_visit_func for each visited node, passing @a dir_visit_baton
+ * and the tree node object.
+ *
+ * If @a cancel_func is not null, call it with @a cancel_baton to check for
+ * cancellation.
+ */
+svn_error_t *
+svn_tree_walk_dirs(svn_tree_node_t *root_dir_node,
+ svn_depth_t depth,
+ svn_tree_dir_visit_func_t dir_visit_func,
+ void *dir_visit_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool);
+
+/** A tree-walker callback.
+ *
* This callback presents one tree node object being visited, @a node,
* and the closure @a walk_baton.
*
- * ### TODO: Consider re-modelling, more like Python's OS tree walker
- * that passes a list of subdirs and a list of non-dir children,
- * and lets the list of subdirs be modified before it recurses into them.
- *
* @a scratch_pool is available for use within the function until it returns.
*/
typedef svn_error_t *(*svn_tree_walk_func_t)(svn_tree_node_t *node,
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=1410554&r1=1410553&r2=1410554&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c Fri Nov 16 20:04:31 2012
@@ -87,40 +87,48 @@ tree_node_get_kind_or_unknown(svn_node_k
return svn_error_trace(err);
}
-/* The body of svn_tree_walk(), which see.
+/* The body of svn_tree_walk_dirs(), which see.
*/
static svn_error_t *
-walk_tree(svn_tree_node_t *node,
+walk_dirs(svn_tree_node_t *dir_node,
svn_depth_t depth,
- svn_tree_walk_func_t walk_func,
+ svn_tree_dir_visit_func_t walk_func,
void *walk_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- svn_node_kind_t kind;
+ apr_array_header_t *dirs
+ = apr_array_make(scratch_pool, 1, sizeof(svn_tree_node_t *));
+ apr_array_header_t *files
+ = apr_array_make(scratch_pool, 1, sizeof(svn_tree_node_t *));
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ int i;
+
+#ifdef SVN_DEBUG
+ {
+ svn_node_kind_t kind;
+
+ SVN_ERR(tree_node_get_kind_or_unknown(&kind, dir_node, scratch_pool));
+ assert(kind == svn_node_dir);
+ }
+#endif
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
- SVN_ERR(tree_node_get_kind_or_unknown(&kind, node, scratch_pool));
-
- SVN_ERR(walk_func(node, walk_baton, scratch_pool));
-
- /* Recurse */
- if (kind == svn_node_dir && depth >= svn_depth_files)
+ if (depth >= svn_depth_files)
{
apr_hash_t *children;
apr_array_header_t *children_sorted;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- int i;
- SVN_ERR(svn_tree_node_read_dir(node, &children, NULL /* props */,
+ SVN_ERR(svn_tree_node_read_dir(dir_node, &children, NULL /* props */,
scratch_pool, scratch_pool));
children_sorted = svn_sort__hash(children,
svn_sort_compare_items_lexically,
scratch_pool);
+ /* Categorize the children into dirs and non-dirs */
for (i = 0; i < children_sorted->nelts; i++)
{
const svn_sort__item_t *item
@@ -130,17 +138,87 @@ walk_tree(svn_tree_node_t *node,
svn_pool_clear(iterpool);
SVN_ERR(tree_node_get_kind_or_unknown(&child_kind, child, iterpool));
- if (depth >= svn_depth_immediates || child_kind == svn_node_file)
+ if (child_kind == svn_node_dir)
{
- SVN_ERR(walk_tree(child,
- depth == svn_depth_infinity ? depth
- : svn_depth_empty,
- walk_func, walk_baton,
- cancel_func, cancel_baton, iterpool));
+ APR_ARRAY_PUSH(dirs, svn_tree_node_t *) = child;
+ }
+ else
+ {
+ if (depth >= svn_depth_immediates)
+ APR_ARRAY_PUSH(files, svn_tree_node_t *) = child;
}
}
- svn_pool_destroy(iterpool);
}
+
+ /* Call the visitor callback */
+ SVN_ERR(walk_func(dir_node, dirs, files, walk_baton, scratch_pool));
+
+ /* Recurse */
+ for (i = 0; i < dirs->nelts; i++)
+ {
+ const svn_sort__item_t *item
+ = &APR_ARRAY_IDX(dirs, i, svn_sort__item_t);
+ svn_tree_node_t *child = item->value;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(walk_dirs(child,
+ depth == svn_depth_infinity ? depth
+ : svn_depth_empty,
+ walk_func, walk_baton,
+ cancel_func, cancel_baton, iterpool));
+ }
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_tree_walk_dirs(svn_tree_node_t *root_dir_node,
+ svn_depth_t depth,
+ svn_tree_dir_visit_func_t dir_visit_func,
+ void *dir_visit_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR(walk_dirs(root_dir_node, depth, dir_visit_func, dir_visit_baton,
+ cancel_func, cancel_baton, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Baton for per_dir_to_per_node_cb() */
+typedef struct per_dir_to_per_node_baton_t
+{
+ svn_tree_walk_func_t node_walk_func;
+ void *node_walk_baton;
+} per_dir_to_per_node_baton_t;
+
+/* A dir-walk callback that calls a per-node callback. */
+static svn_error_t *
+per_dir_to_per_node_cb(svn_tree_node_t *dir_node,
+ apr_array_header_t *subdirs,
+ apr_array_header_t *files,
+ void *dir_visit_baton,
+ apr_pool_t *scratch_pool)
+{
+ per_dir_to_per_node_baton_t *b = dir_visit_baton;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ int i;
+
+ /* Visit this dir */
+ SVN_ERR(b->node_walk_func(dir_node, b->node_walk_baton, scratch_pool));
+
+ /* Visit the non-directory children */
+ for (i = 0; i < files->nelts; i++)
+ {
+ svn_tree_node_t *child_node = APR_ARRAY_IDX(files, i, svn_tree_node_t *);
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(b->node_walk_func(child_node, b->node_walk_baton, iterpool));
+ }
+ svn_pool_destroy(iterpool);
+
return SVN_NO_ERROR;
}
@@ -154,11 +232,25 @@ svn_tree_walk(svn_tree_t *tree,
apr_pool_t *scratch_pool)
{
svn_tree_node_t *node;
+ svn_node_kind_t kind;
SVN_ERR(svn_tree_get_root_node(&node, tree, scratch_pool, scratch_pool));
- SVN_ERR(walk_tree(node, depth,
- walk_func, walk_baton,
- cancel_func, cancel_baton, scratch_pool));
+ SVN_ERR(svn_tree_node_get_kind(node, &kind, scratch_pool));
+
+ if (kind == svn_node_dir)
+ {
+ per_dir_to_per_node_baton_t b;
+
+ b.node_walk_func = walk_func;
+ b.node_walk_baton = walk_baton;
+ SVN_ERR(walk_dirs(node, depth, per_dir_to_per_node_cb, &b,
+ cancel_func, cancel_baton, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(walk_func(node, walk_baton, scratch_pool));
+ }
+
return SVN_NO_ERROR;
}