$ tar zxvf subversion-1.3.2.tar.gz $ cd subversion-1.3.2 $ ./configure --prefix=/usr/local/subversion $ make $ # optionally, make check to run the tests $ make install
libsvn_fslibsvn_ralibsvn_fssvn_thingy becomes svn_thingy2
libsvn_subr - Random utility functions for
Subversion
libsvn_delta - Code for calculating/applying deltas
libsvn_delta - Code for diffing and mergeing files
const char *find_interesting_string(apr_pool_t *pool) {
const char *interesting = NULL, *temp;
apr_pool_t *subpool;
int i;
apr_pool_create (&subpool, pool);
for (i = 0; i < 100; ++i) {
apr_pool_clear(subpool);
function_that_uses_temp_memory(&temp, subpool);
if (retval_is_interesting(temp)) {
interesting = apr_pstrdup(pool, temp);
break;
}
}
apr_pool_destroy(subpool);
return interesting;
}
apr_status_t valueserrno plus other special values
apr_status_t some_function(apr_pool_t *pool) {
apr_status_t err;
apr_file_t *fp;
err = apr_file_open(&fp, "the-file-name", APR_READ,
APR_OS_DEFAULT, pool);
if (APR_STATUS_IS_SUCCESS(err)) {
/* read from the file... */
} else if (APR_STATUS_IS_ENOENT(err)) {
/* ok, the file wasn't found. do something useful
* here. */
return err;
} else {
return err;
}
return APR_SUCCESS;
}
svn_error_t) are built
on top of apr_status_t
svn_error_create or
svn_error_createf
svn_error_clear, since they're
not associated with a pool.
apr_err member
of the svn_error_t
SVN_ERR macro, which
checks for errors and returns them to the caller
svn_error_t *contrived_example(apr_pool_t *pool)
{
apr_pool_t *subpool;
int count, idx;
SVN_ERR(how_many(&count, pool));
subpool = svn_pool_create(pool);
for (idx = 0; idx < count; ++idx) {
svn_error_t *err;
svn_pool_clear(subpool);
err = can_fail(apr_psprintf(subpool, "file-%d", idx), subpool);
if (err && APR_STATUS_IS_ENOENT(err->apr_err))
svn_error_clear(err);
else if (err)
return err;
else
break;
}
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
svn_string.h has two string types in it:
svn_string_t - Constant stringsvn_stringbuf_t - Modifiable stringconst char *
strings, but you should know about the counted alternatives.
svn_path_canonicalizesvn_utf_cstring_to_utf8
svn_utf_cstring_to_utf8_ex2
svn_stream_tsvn_error_t *cat(apr_file_t *file, apr_pool_t *pool) {
svn_stream_t *stream = svn_stream_from_aprfile2(file, FALSE, pool);
apr_pool_t *subpool = svn_pool_create(pool);
svn_boolean_t eof = FALSE;
while (! eof) {
svn_stringbuf_t *line;
svn_pool_clear(subpool);
SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, subpool));
printf("%s\n", line->data);
}
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
svn_stream_from_aprfile2
source_text = "abcde"
target_text = "abXde"
stream = Svn::Delta::TextDeltaStream.new(source, target)
apply_source = StringIO.new(source_text)
apply_result = StringIO.new("")
handler, digest = Svn::Delta.apply(apply_source, apply_result)
handler.send(stream)
apply_result.rewind
print apply_result.read
source_text to
target_text
target_textlibsvn_diff
tools/diff/diff.c is a simple unified diff program using
libsvn_diff's diff code
svn_diff_file_diff to build a
svn_diff_t object representing difference
between two files
svn_diff_contains_diffssvn_diff_file_output_unified
void * in Csvn_delta_editor_t interface
open_root - Opens the root of the treeopen_directory - Opens a new subdirectoryadd_directory - Adds a new directoryadd_file - Adds a new fileopen_file - Opens a file for writingapply_textdelta - Modify an open fileclose_file - Closes a fileclose_directory - Closes a directoryabort_edit - Signals that an error has occurredsvn_delta.h for details===================================================================
--- subversion/libsvn_client/diff.c (revision 20226)
+++ subversion/libsvn_client/diff.c (working copy)
@@ -40,6 +40,8 @@
#include "client.h"
#include <assert.h>
+#include "../libsvn_delta/debug_editor.h"
+
#include "svn_private_config.h"
/*
@@ -2065,6 +2067,10 @@
ctx->cancel_func, ctx->cancel_baton,
&diff_editor, &diff_edit_baton, pool));
+ SVN_ERR(svn_delta__get_debug_editor(&diff_editor, &diff_edit_baton,
+ diff_editor, diff_edit_baton,
+ pool));
+
/* We want to switch our txn into URL2 */
SVN_ERR(svn_ra_do_diff2
(drr.ra_session, &reporter, &report_baton, drr.rev2, drr.target1,
$ svn diff -r 13:14 http://svn.collab.net/repos/svn/trunk > /dev/null set_target_revision : 15 open_root : 14 change_dir_prop : svn:wc:ra_dav:version-url open_directory : 'www':14 change_dir_prop : svn:wc:ra_dav:version-url open_file : 'www/index.html':14 change_file_prop : svn:wc:ra_dav:version-url apply_textdelta : a01ce64bbb32748a3a93ccc97404f408 change_file_prop : svn:entry:committed-rev change_file_prop : svn:entry:committed-date change_file_prop : svn:entry:last-author close_file : d1ddd0260510e9f014c2716d06835362 change_dir_prop : svn:entry:committed-rev change_dir_prop : svn:entry:committed-date change_dir_prop : svn:entry:last-author close_directory change_dir_prop : svn:entry:committed-rev change_dir_prop : svn:entry:committed-date change_dir_prop : svn:entry:last-author close_directory close_edit
svn_fs_root_t objects
--------- --------- --------- ---------
| rev 0 |<-| rev 1 |<------| rev 2 |<---------| rev 3 |
--------- --------- --------- ---------
| --------- | --------- | ---------
\-| trunk |<---\-| trunk |<----------\-| trunk |
| --------- | --------- \ | ---------
| | | --------- | |
| | \-| foo.c | | |
| | --------- | |
| --------- | -------- | | ---------
\-| tags |<---\--| tags |<-----|----\-| tags |
--------- -------- | ---------
| | ---------------
\-------\-| version_0.1 |
---------------
svn_fs_opensvn_fs_revision_rootsvn_fs_dir_entries and
svn_fs_file_contents to get the data
svn_error_t *ls(svn_fs_root_t *root, const char *path,
apr_pool_t *pool) {
svn_node_kind_t kind;
SVN_ERR(svn_fs_check_path(&kind, root, path, pool));
if (kind == svn_node_file) {
printf("%s\n", path);
} else if (kind == svn_node_dir) {
apr_hash_index_t *hi;
apr_hash_t *entries;
apr_pool_t *subpool;
printf("%s/\n", path);
SVN_ERR(svn_fs_dir_entries(&entries, root, path, pool));
subpool = svn_pool_create(pool);
for (hi = apr_hash_first(entries, pool); hi;
hi = apr_hash_next(hi)) {
const void *key;
void *val;
apr_hash_this(hi, &key, NULL, &val);
SVN_ERR(ls(root, key, subpool));
}
svn_pool_destroy(subpool);
}
return SVN_NO_ERROR;
}
ls returns svn_error_t, so we can use
SVN_ERR
apr_hash_tsvn_fs_node_history opens a node's history objectsvn_fs_history_prev in a loop, moving
back in time
subversion/libsvn_repos/log.c:get_historymy $repos = SVN::Repos::create("/path/to/fs", undef, undef, undef,
undef);
my $txn = $repos->fs->begin_txn($fs->youngest_rev);
$txn->root->make_dir("trunk");
$txn->root->make_dir("tags");
$txn->root->make_dir("branches");
$txn->root->make_file('README');
my $stream = $txn->root->apply_text('README', undef);
print $stream <<EOF;
This repository now has trunk, tags, and branches directories
EOF
close $stream;
$txn->commit;
SVN::Pool->new_default and
SVN::Pool->new_default_sub
use SVN::Core;
# create a root pool and set it as default pool for later use
my $pool = SVN::Pool->new_default;
sub something {
# create a subpool of the current default pool
my $subpool = SVN::Pool->new_default_sub;
for (1..10) {
$subpool->clear;
# some svn operations...
}
# $subpool gets destroyed and the previous default pool
# is restored when $subpool's lexical scope ends
}
libsvn_fs via
libsvn_repos
start-commit - Runs before txn is createdpre-commit - After txn is create, but before commit occurs
post-commit - After commit is finishedpre-lock - Before a lock occurspost-lock - After a lock occurspre-unlock - Before an unlock occurspost-unlock - After an unlock occurspre-revprop-change - Before the change occurrspost-revprop-change - After a change happenspost-commit-hook pings them, via email or xmlrpcpost-commit-hook script.
svnlook for simplicityPATH or
LD_LIBRARY_PATH)
libsvn_delta holds the routines that calculate
differences between trees
svn_delta_dir_delta - Compares arbitrary trees
(used in mod_dav_svn)
svn_repos_begin_report - Compares arbitrary
trees (used in svnserve)
svn_delta_replay - Gets the delta associated
with a single revision (used in svnadmin dump)
tools/examples/svnlook.pySVNLook._print_tree uses dir_delta to
do various things
tools/examples/svnlook.rb for a Ruby examplelibsvn_repos also holds the code for dumping and
loading Subversion repositories
svn_repos_parse_dumpstream2svn_repos_get_fs_build_parser2svn_repos_parse_fns2_tsvndumpfilter and
svndumptool.py for ways to work with
dumpfiles
svndumptool.pycopy_dump_file to let it take a
mapping from old to new usernames and to allow setting of author
revprops
libsvn_ra_local - Direct access to a local reposlibsvn_ra_svn - Accesses a remote repository
through a custom protocol and network server
libsvn_ra_dav - Access a
mod_dav_svn server via the Neon WebDAV client
library
libsvn_ra_serf - Experimental alternate implementaiton
of the WebDAV client side using the Serf library
set_path - I've got this version of this pathdelete_path - I deleted this pathlink_path - I've got this version of this switched path
finish_report - I'm done, run the editorabort_report - An error occurredcontrib/client-side/mucc.c is the solutionsvnedit.c$EDITOR on itsvn_error_t list(svn_ra_session_t *session, const char *dir,
svn_revnum_t rev, apr_pool_t *pool) {
apr_pool_t *subpool = svn_pool_create(pool);
apr_hash_index_t *hi;
apr_hash_t *dents;
SVN_ERR(svn_ra_get_dir2(session, dir, rev, SVN_DIRENT_ALL, &dents,
pool));
for (hi = apr_hash_first(dents, pool); hi; hi = apr_hash_next(hi)) {
const char *name, *fpath;
svn_dirent_t *dent;
svn_pool_clear(subpool);
apr_hash_this(hi, &name, APR_HASH_KEY_STRING, &dent);
fpath = apr_psprintf(subpool, "%s/%s", dir, name);
printf("%s%s\n", fpath, dent->kind == svn_node_dir ? "/" : "");
if (dent->kind == svn_node_dir)
SVN_ERR(list(session, fpath, rev, subpool));
}
return SVN_NO_ERROR;
}
svn_ra_get_locationssvn_ra_get_log
svn_error_t *reciever(void *baton, apr_hash_t *changed_paths,
svn_revnum_t revision, const char *author,
const char *date, const char *message,
apr_pool_t *pool) {
printf("%s committed %ld on %s\n", author, revnum, date);
return SVN_NO_ERROR;
}
svn_error_t *print_log(svn_ra_session_t *session, const char *path,
svn_revnum_t start, svn_revnum_t end,
apr_pool_t *pool) {
apr_array_header_t *paths = apr_array_make(pool, 10, sizeof(char *));
APR_ARRAY_PUSH(paths, const char *) = path;
return svn_ra_get_log(session, paths, start, end, 0, FALSE, TRUE,
receiver, NULL, pool);
}
libsvn_ra use editorssvn_error_t *do_diff(svn_ra_session_t *session,
svn_revnum_t start, svn_revnum_t end,
apr_pool_t *pool) {
svn_ra_reporter2_t *reporter;
svn_delta_editor_t *editor = svn_delta_default_editor(pool);
void *edit_baton, *report_baton;
const char *url;
svn_delta__get_debug_editor(&editor, &edit_baton, editor, NULL,
pool);
SVN_ERR(svn_ra_get_repos_root(session, &url, pool));
SVN_ERR(svn_ra_do_diff2(session, &reporter, &report_baton, end, "",
TRUE, FALSE, TRUE, url, editor, edit_baton,
pool));
SVN_ERR(reporter->set_path(report_baton, "", start, FALSE, NULL,
pool));
SVN_ERR(reporter->finish_report(report_baton, pool));
return SVN_NO_ERROR;
}
libsvn_wc uses opaque structures called "Access Batons"libsvn_wc needs a batonsvn_wc_entry_t is the data structuresvn info lives here
svn_wc_entry or
svn_wc_entries_read to get them
svn_error_t *print_info(const char *path, apr_pool_t *pool) {
svn_wc_adm_access_t *adm_access;
svn_wc_entry_t *entry;
SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, path, FALSE, 0, NULL,
NULL, pool));
SVN_ERR(svn_wc_entry(&entry, path, adm_access, TRUE, pool));
printf("name: %s\n", entry->name);
printf("revision: %ld\n", entry->revision);
printf("url: %s\n", entry->url);
printf("author: %s\n", entry->cmt_author);
printf("commit date: %s\n", entry->cmt_date);
printf("last changed rev: %ld\n", entry->cmt_rev);
return SVN_NO_ERROR;
}
svn_wc_walk_entries2
svn status -u use
svn_wc_get_status_editor2 to get an editor, plus
svn_ra_do_status and
svn_wc_crawl_revisions2 to drive it
libsvn_wc works with libsvn_ra for
most of the interesting operations
svn command line tool is a thin wrapper around
this library
svn_client_ctx_t structure as an argument
svn_client_create_context
tools/examples/minimal_client.csvn_client_ctx_tsvn_client_ls as the minimalist client callrequire 'svn/client'
client = Svn::Client::Context.new
def list_dir(url)
client.list(url, "HEAD") do |path, dirent, lock, abs_path|
if dirent.directory?
print "#{path}/\n"
list_dir("#{url}/#{path}", "HEAD")
else
print "#{path}\n"
end
end
end
list_dir("http://svn.collab.net/repos/svn/")
mod_dav_svn based serversdav_svn_split_uri to figure out what part of
the repository is being accessed
svn_repos_authz_check_access to figure out accesssvn provides a great example for libsvn_client
subversion/svn or
subversion/clients/cmdline depending on what
version of Subversion you've got
svnant project (part of Subclipse) may provide
easier to digest examples
Any Questions?