[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[RFC] API for reading trees from repo or WC

From: Julian Foad <julian.foad_at_wandisco.com>
Date: Fri, 07 Oct 2011 14:56:42 +0100

This is a Request For Comments on the creation of an API for reading a
tree of dirs and files from an arbitrary source via a common API.

RATIONALE

1.

I want to re-write svn_client_diff() so that it can diff any tree
against any other tree, where a tree is any of:

  * versioned (rooted at URL_at_REV in a repository)

  * WC base (rooted at a local abspath in a WC)

  * WC working (rooted at a local abspath in a WC)

  * unversioned on disk (rooted at a local abspath)

and potentially other sources.

I envisage two main code paths:

  diff_two_trees(tree1, tree2)

    Takes two references to trees, and reads directories and files from
tree1 and tree2 as required to find differences and present a unidiff
(or whatever kind of output).

  diff_tree_with_delta(tree1, delta)

    Takes a reference to a base tree, and an svn_delta_editor_t type
delta based on tree1, and reads dirs and files from tree1 as necessary
to present the delta as a unidiff (or whatever kind of output).

2.

It's the right way to design software. Witness how successful the
pluggable RA system and the delta_editor interfaces have been. (Note
that the need for editor v2 does not mean the editor was a bad idea.)

3.

I want to re-write all our libsvn_client read-from-tree APIs such as
'cat', 'propget', 'export' etc. so that they use a common "pull from a
tree" API, in order to reduce complexity and unintended differences and
bugs in those implementations.

4.

I want other people to be able to write such functions/features easily.

DESIGN

I'm thinking something like this for a start.

/* Present as a tree:
 * an unversioned disk tree;
 * a WC base tree
 * a WC working tree
 * a repository tree
 *
 * The consumer "pulls" parts of the tree and can omit unwanted parts.
 * Consumer can pull any subtree "recursively" for efficient streaming.
 */

/**
 * A readable tree. This object is used to perform read requests to a
 * repository tree or a working-copy (base or working) tree or any other
 * readable tree.
 *
 * @since New in 1.8.
 */
typedef struct svn_client_tree_t svn_client_tree_t;

/* */
typedef svn_io_dirent2_t svn_client_tree_dirent_t;

/* V-table for #svn_client_tree_t.
 *
 * Paths are relpaths, relative to the tree root.
 * Revision numbers and repository ids are #SVN_INVALID_REVNUM and NULL
 * for an unversioned node (including a node that is a local add/copy/move
 * in a WC working tree).
 */
typedef struct svn_client_tree__vtable_t
{
  /* Fetch the node kind of the node at @a relpath.
   * (### and other metadata? revnum? props?)
   *
   * Set @a *kind to the node kind.
   */
  svn_error_t *(*get_kind)(svn_client_tree_t *tree,
                           svn_node_kind_t *kind,
                           const char *relpath,
                           apr_pool_t *scratch_pool);

  /* Fetch the contents and properties of the file at @a relpath.
   *
   * If @a stream is non-NULL, set @a *stream to a readable stream yielding
   * the contents of the file at @a relpath. (### ? The stream
   * handlers for @a stream may not perform any operations on @a tree.)
   *
   * If @a props is non-NULL, set @a *props to contain the regular
   * versioned properties of the file (not 'wcprops', 'entryprops', etc.).
   * The hash maps (const char *) names to (#svn_string_t *) values.
   */
  svn_error_t *(*get_file)(svn_client_tree_t *tree,
                           svn_stream_t **stream,
                           apr_hash_t **props,
                           const char *relpath,
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool);

  /* Fetch the entries and properties of the directory at @a relpath.
   *
   * If @a dirents is non-NULL, set @a *dirents to contain all the entries
   * of directory @a relpath. The keys will be (<tt>const char *</tt>)
   * entry names, and the values (#svn_client_tree_dirent_t *) dirents.
   * Only the @c kind and @c filesize fields are filled in.
   * ### @c special would be useful too.
   *
   * If @a props is non-NULL, set @a *props to contain the regular
   * versioned properties of the file (not 'wcprops', 'entryprops', etc.).
   * The hash maps (const char *) names to (#svn_string_t *) values.
   */
  svn_error_t *(*get_dir)(svn_client_tree_t *tree,
                          apr_hash_t **dirents,
                          apr_hash_t **props,
                          const char *relpath,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool);

  /* Push a sub-tree into an editor, as a delta against an empty tree.
   * This is useful for efficiency when streaming a (sub-)tree from a
   * remote source. */
  svn_error_t *(*push_as_delta_edit)(svn_client_tree_t *tree,
                                     const char *relpath,
                                     svn_delta_editor_t *editor,
                                     void *edit_baton,
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool)
} svn_client_tree__vtable_t;

/* */
struct svn_client_tree_t
{
  const svn_client_tree__vtable_t *vtable;

  /* Pool used to manage this session. */
  apr_pool_t *pool;

  /* Private data for the tree implementation. */
  void *priv;
};

It will no doubt need a bit more sophistication, which I'll discover
when I try to implement and use it.

Thoughts and comments so far? Any objection to me starting such a thing
in trunk if it sounds like a good idea?

- Julian
Received on 2011-10-07 15:57:19 CEST

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.