Subversion needs a consistent API for storing and retrieving tree changes. The same API should push and pull changes:
- into and out of the repository,
- into and out of the main WC storage,
- into and out of a shelf.
These improvements are not just to benefit shelving. In the longer term, if we are to make a major improvement like supporting moves/renames properly, in my opinion we need to do it starting from a baseline where we consistently and cleanly use APIs that encode the current semantics of versioned changes. Each upgrade of the semantics can then be accomplished by writing backward compatibility code once and inserting it into every usage of that API.
At the moment we have different APIs, some of them abstract interfaces (such as svn_delta_editor_t) that are implemented on more than one place, but still not everywhere; and others that are tied to their single implementation (such as most of the WC API).
The coverage of this API can be considered in three main areas:
- the base state (of the WC, or of a commit, etc.)
- the committable changes
- the uncommittable WC state (conflicts, changelists, etc.)
For (1) the base, svn_ra_reporter3_t is the minimal required interface. It is sufficient for commits. An interface to represent a full WC base state would include a few more fields (repos-lock, 'incomplete', last-modified). Implementations to both update the WC base layer and read (report) the base layer through this API exist.
For (2) committable changes, the "delta editor" is the right API, by definition, being used for commits from the client library through the RA (network) layers into the repository library. Recently implementations of this API have been created for getting changes into and out of the WC (svn_client__wc_editor and svn_client__wc_replay).
For (3) uncommittable changes, an interface definition doesn't even exist. My shelving design doesn't attempt to support part 3, largely because I knew the API didn't exist. If it did, it would be relatively easy for shelving to support it.
With these interfaces in place it would be straightforward to implement the logic of shelving. (The storage for it is another matter.)
My task is to put those interfaces in places, uncoupling and extracting the ones that already partly exist and writing the new ones.
Upgrade to write to the WC through wc_editor:
Probably all of the client operations that modify the WC – listed below – should do so through a standard WC editor API. However, the delta-editor API by itself is not enough for some of these, as some of these require read access as well to decide how to modify it. For those, we will need the "WC read-write editor" which does not yet exist.
- unshelve – done
- svn_client_copy7(), svn_client_move7() – repos-to-WC done, WC-to-WC TODO
Many client functions have different semantics for URLs and WC paths, being implemented as:
We can gain consistency and reduce complexity by rewriting as:
A Read-Write Editor
The svn_delta_editor_t API provides write-only semantics. Some operations require read-write semantics. For example, the semantics of "svn copy A B" includes "if B is an existing directory then copy A to B/(basename of A)" which requires querying the existence and type of path B.
This API should be based on:
- a BaseTree (definition supplied or implied),
- querying the BaseTree
- applying changes to create a TargetTree
- (?) querying the TargetTree (only possible, in general, at Sequence Points in the applying changes)
Parts of this API might be extracted from the RA session API.
Testing the WC editor
Here is a possible way to test that the WC-editor correctly handles every committable change.
In the test suite, make every commit be shadowed in a tmp repo:
- checkout a tmp WC based on previous rev,
- replay the commit to a temp WC,
- create a tmp repo which is a clone of the real repo up to the previous rev,
- commit the tmp WC to the tmp repo,
- check repos for equality.