automating subversion with bindings n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Automating Subversion with Bindings PowerPoint Presentation
Download Presentation
Automating Subversion with Bindings

Loading in 2 Seconds...

play fullscreen
1 / 139

Automating Subversion with Bindings - PowerPoint PPT Presentation


  • 82 Views
  • Uploaded on

Automating Subversion with Bindings. @ BenReser http:// svn.ms / autosvnslides. About Ben. Subversion Committer working at WANdisco since 2012.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Automating Subversion with Bindings' - brian


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
automating subversion with bindings

Automating Subversion with Bindings

@BenReser

http://svn.ms/autosvnslides

about ben
About Ben

Automating Subversion with Bindings

Subversion Committer working at WANdisco since 2012.

Started working on Perl Bindings in 2003 to automate Subversion as a replacement for CVS. Never finished the project that inspired the work and ended up working on Subversion itself.

My work isn’t limited to bindings anymore and has expanded across the different parts of Subversion including acting as the Release Manager.

what is subversion
What is Subversion…

Automating Subversion with Bindings

An implementation of a Version Control System?

what is subversion1
What is Subversion…

Automating Subversion with Bindings

An implementation of a Version Control System?

Libraries that implement a Version Control System.

what is subversion2
What is Subversion…

Automating Subversion with Bindings

  • An implementation of a Version Control System?
  • Libraries that implement a Version Control System.
    • Written in C
layered library design
Layered Library Design

Automating Subversion with Bindings

layered library design client
Layered Library Design - Client

Automating Subversion with Bindings

  • Client
    • Implements the basic functions of a client. Knows about working copies and uses the…
layered library design client1
Layered Library Design - Client

Automating Subversion with Bindings

  • Client
    • Implements the basic functions of a client. Knows about working copies and uses the…
  • WC (Working Copy)
    • Implements the working copy
layered library design client2
Layered Library Design - Client

Automating Subversion with Bindings

  • Client
    • Implements the basic functions of a client. Knows about working copies and uses the…
  • WC (Working Copy)
    • Implements the working copy
  • RA (Repository Access)
    • Implements protocol to talk to (possibly remote) repository
      • Local (file://)
      • Neon (http(s):// 1.7.x and older was called DAV in 1.4.x and older, gone in 1.8.x)
      • Serf (http(s):// 1.5.x and newer)
      • SVN (svn://)
layered library design server
Layered Library Design - Server

Automating Subversion with Bindings

  • Repos
    • Repository interface which implements high level repository functionality and uses…
layered library design server1
Layered Library Design - Server

Automating Subversion with Bindings

  • Repos
    • Repository interface which implements high level repository functionality and uses…
  • FS
    • File system implementation to store a repository
      • FS_Base (Berkeley DB)
      • FS_FS (non database implementation)
layered library design misc
Layered Library Design – Misc.

Automating Subversion with Bindings

  • Subr
    • Miscellaneous subroutines
layered library design misc1
Layered Library Design – Misc.

Automating Subversion with Bindings

  • Subr
    • Miscellaneous subroutines
  • Delta
    • Tree and byte-stream differencing routines
layered library design misc2
Layered Library Design – Misc.

Automating Subversion with Bindings

  • Subr
    • Miscellaneous subroutines
  • Delta
    • Tree and byte-stream differencing routines
  • Diff
    • Contextual differencing and merge routines
what are bindings1
What are Bindings?

Automating Subversion with Bindings

  • Access Subversion C APIs from other Higher Level Programming Languages
what are bindings2
What are Bindings?

Automating Subversion with Bindings

  • Access Subversion C APIs from other Higher Level Programming Languages
  • Somewhat easier to use than C
what are bindings3
What are Bindings?

Automating Subversion with Bindings

  • Access Subversion C APIs from other Higher Level Programming Languages
  • Somewhat easier to use than C
  • Provide an interface that somewhat matches the Higher Level Language’s idioms
what are bindings4
What are Bindings?

Automating Subversion with Bindings

  • Access Subversion C APIs from other Higher Level Programming Languages
  • Somewhat easier to use than C
  • Provide an interface that somewhat matches the Higher Level Language’s idioms
  • May even hide some annoying details from using the libraries
can t i just script the client
Can’t I Just Script The Client?

Automating Subversion with Bindings

  • The client tries to have machine readable formats
can t i just script the client1
Can’t I Just Script The Client?

Automating Subversion with Bindings

  • The client tries to have machine readable formats
  • I recently used something like this to try and find a bug in diff –summarize:

(svn log $URL | grep -Eo '^r[0-9]+ \| ' | sed 's/[^0-9]//g') | while read rev; do svn diff --summarize $URL -c $rev; done

can t i just script the client2
Can’t I Just Script The Client?

Automating Subversion with Bindings

  • It worked great until it ran into this output:

svn log –c 933481 https://svn.apache.org/repos/asf/subversion/trunk

------------------------------------------------------------------------

r933481 | gstein | 2010-04-12 21:20:50 -0700 (Mon, 12 Apr 2010) | 27 lines

Add some new methods to the Sandbox class for performing simple,

unverified operations.

Also introduce deep magic with svntest.main.make_log_msg() to produce log

messages that show the source of the command invocation. These automated

log messages look like:

----

r2 | jrandom | 2010-04-12 23:57:10 -0400 (Mon, 12 Apr 2010) | 1 line

File './schedule_tests.py', line 543, in status_add_deleted_directory

----

what about xml
What about XML?

Automating Subversion with Bindings

  • The client supports XML output with --xml on most commands.
what about xml1
What about XML?

Automating Subversion with Bindings

  • The client supports XML output with --xml on most commands.
  • XML is hard to parse correctly
    • Regexps aren’t reliable
    • XSLT is a pain to write
    • XML parsers are far from easy to drive
command behavior changes
Command behavior changes

Automating Subversion with Bindings

  • We try to avoid changing the output and behavior of commands.
command behavior changes1
Command behavior changes

Automating Subversion with Bindings

  • We try to avoid changing the output and behavior of commands.
command behavior changes2
Command behavior changes

Automating Subversion with Bindings

  • We try to avoid changing the output and behavior of commands.
  • svnmergeinfo prior to 1.8.0 behaved as though --show-revs=merged was passed if no --show-revs option was passed. In 1.8.x this shows a graph.
greater capabilities
Greater capabilities

Automating Subversion with Bindings

  • We can implement functionality that the command line client doesn’t have.
  • Examples:
    • ViewVC
    • Subclipse
    • control-chars.py hook-script
why not use bindings
Why not use Bindings?

Automating Subversion with Bindings

  • Poor documentation
why not use bindings1
Why not use Bindings?

Automating Subversion with Bindings

  • Poor documentation
  • Need to install them
why not use bindings2
Why not use Bindings?

Automating Subversion with Bindings

  • Poor documentation
  • Need to install them
  • Expose internal details that may be hard to understand
why not use bindings3
Why not use Bindings?

Automating Subversion with Bindings

  • Poor documentation
  • Need to install them
  • Expose internal details that may be hard to understand
  • Not always updated for the latest features
what bindings are available
What Bindings Are Available

Automating Subversion with Bindings

  • SWIG
    • Python
    • Perl
    • Ruby
  • JavaHL
  • ctypes-python
  • SVNKit
  • pySVN
what is swig
What is SWIG?

Automating Subversion with Bindings

  • Simplified Wrapper and Interface Generator
what is swig1
What is SWIG?

Automating Subversion with Bindings

  • Simplified Wrapper and Interface Generator
    • Partly automated generator
what is swig2
What is SWIG?

Automating Subversion with Bindings

  • Simplified Wrapper and Interface Generator
    • Partly automated generator
    • Acts like a specialized C compiler
what is swig3
What is SWIG?

Automating Subversion with Bindings

  • Simplified Wrapper and Interface Generator
    • Partly automated generator
    • Acts like a specialized C compiler
  • Only needed at interface generation time
how to install bindings
How To Install Bindings

Automating Subversion with Bindings

Windows

Mac

RedHat based Linux

Debian based Linux

Other

windows
Windows

Automating Subversion with Bindings

  • WANdisco installer
    • Provides swig-python (for Python 2.7.2) and JavaHL
  • Alagazam.net
    • Provides swig-python, swig-perl, swig-ruby, and JavaHL
redhat based linux
RedHat based Linux

Automating Subversion with Bindings

  • WANdisco packages
    • subversion-python (SWIG)
    • subversion-ruby (subversion 1.8.x only)
    • subversion-perl
    • subversion-javahl
  • OS Packages
    • Older but usually available and named same as above.
debian based linux
Debian based Linux

Automating Subversion with Bindings

  • WANdisco packages
    • python-subversion (SWIG)
    • libsvn-ruby (and libsvn-ruby1.8 for Ruby 1.8)
    • libsvn-perl
    • libsvn-java (JavaHL)
  • OS Packages
    • Older but usually available and named same as above.
slide44
Mac

Automating Subversion with Bindings

  • WANdisco installer
    • Provides swig-python, swig-perl, swig-ruby and JavaHL
  • MacPorts
    • subversion-javahlbindings
    • subversion-perlbindings-5.16 (number is perl version)
    • subversion-python27bindings (number is python version)
    • subversion-rubybindings
  • Homebrew
    • can provide JavaHL, swig-perl, swig-python, and swig-ruby
  • Xcode
    • Command line tools
    • old but includes swig-python, swig-perl and swig-ruby
other
Other

Automating Subversion with Bindings

  • WANdisco packages should have Bindings for most OSes
  • *NIX platforms build it yourself by:
    • [usual Subversion build instructions]
    • make $binding
    • make check-$binding
    • make install-$binding

where $binding can be:

javahl swig-pl swig-py swig-rb

Don’t use do parallel builds of bindings (-j option to make)

build it yourself swig
Build It Yourself - SWIG

Automating Subversion with Bindings

  • On the Mac you need to do this before the normal Subversion instructions due to a bug in our API that makes the bindings fail to compile (requires SWIG, libtool and autoconf):
    • make extraclean
    • ./autogen.sh
build it yourself swig1
Build It Yourself - SWIG

Automating Subversion with Bindings

  • On the Mac you need to do this before the normal Subversion instructions due to a bug in our API that makes the bindings fail to compile (requires SWIG, libtool and autoconf):
    • make extraclean
    • ./autogen.sh
  • May need the same instructions on other platforms if you get an error about an undeclared symbol starting with SVN_AUTH
build it yourself swig2
Build It Yourself - SWIG

Automating Subversion with Bindings

  • On the Mac you need to do this before the normal Subversion instructions due to a bug in our API that makes the bindings fail to compile (requires SWIG, libtool and autoconf):
    • make extraclean
    • ./autogen.sh
  • May need the same instructions on other platforms if you get an error about an undeclared symbol starting with SVN_AUTH
  • To use Ruby 1.9 need Subversion 1.8.x
build it yourself swig3
Build It Yourself - SWIG

Automating Subversion with Bindings

  • On the Mac you need to do this before the normal Subversion instructions due to a bug in our API that makes the bindings fail to compile (requires SWIG, libtool and autoconf):
    • make extraclean
    • ./autogen.sh
  • May need the same instructions on other platforms if you get an error about an undeclared symbol starting with SVN_AUTH
  • To use Ruby 1.9 need Subversion 1.8.x
  • Python 3 doesn’t work
build it yourself javahl
Build It Yourself - JavaHL

Automating Subversion with Bindings

  • Need --enable-javahl passed to configure
build it yourself javahl1
Build It Yourself - JavaHL

Automating Subversion with Bindings

  • Need --enable-javahl passed to configure
  • Need JUnit, specify where it is by passing this to configure (make sure this is an absolute path):

--with-junit=/usr/share/java/junit.jar

build it yourself javahl2
Build It Yourself - JavaHL

Automating Subversion with Bindings

  • Need --enable-javahl passed to configure
  • Need JUnit, specify where it is by passing this to configure (make sure this is an absolute path):

--with-junit=/usr/share/java/junit.jar

  • Can specify which JDK to use by passing this to configure:

--with-jdk=/usr/lib/jvm/java-6-openjdk-amd64

swig bindings
SWIG Bindings

Automating Subversion with Bindings

  • Thin layer over C API
swig bindings1
SWIG Bindings

Automating Subversion with Bindings

  • Thin layer over C API
  • Perl and Ruby have more syntactic sugar to make it feel more like a normal Perl or Ruby program
swig bindings2
SWIG Bindings

Automating Subversion with Bindings

  • Thin layer over C API
  • Perl and Ruby have more syntactic sugar to make it feel more like a normal Perl or Ruby program
  • Python has very little syntactic sugar but is more complete
swig bindings3
SWIG Bindings

Automating Subversion with Bindings

  • Thin layer over C API
  • Perl and Ruby have more syntactic sugar to make it feel more like a normal Perl or Ruby program
  • Python has very little syntactic sugar but is more complete
  • Not every language has everything completely wrapped.
swig modules
SWIG Modules

Automating Subversion with Bindings

  • Core
    • The things that don’t fit anywhere else, includes APR functions that are needed and libsvn_subr.
  • Client
  • Wc
  • Diff
  • Delta
  • Ra
  • Repos
  • Fs
apr pools
APR Pools

Automating Subversion with Bindings

  • APR is Apache Portable Runtime
apr pools1
APR Pools

Automating Subversion with Bindings

  • APR is Apache Portable Runtime
  • Pools are used for memory management.
apr pools2
APR Pools

Automating Subversion with Bindings

  • APR is Apache Portable Runtime
  • Pools are used for memory management.
  • Pools have a lifetime. Lifetime ends when pool or its parent is destroyed.
apr pools3
APR Pools

Automating Subversion with Bindings

  • APR is Apache Portable Runtime
  • Pools are used for memory management.
  • Pools have a lifetime. Lifetime ends when pool or its parent is destroyed.
  • Pools can be cleared to free memory and reuse the same pool (iteration)
apr pools4
APR Pools

Automating Subversion with Bindings

  • APR is Apache Portable Runtime
  • Pools are used for memory management.
  • Pools have a lifetime. Lifetime ends when pool or its parent is destroyed.
  • Pools can be cleared to free memory and reuse the same pool (iteration)
  • SWIG bindings largely let you ignore pools by defaulting to a single global pool
apr pools5
APR Pools

Automating Subversion with Bindings

  • APR is Apache Portable Runtime
  • Pools are used for memory management.
  • Pools have a lifetime. Lifetime ends when pool or its parent is destroyed.
  • Pools can be cleared to free memory and reuse the same pool (iteration)
  • SWIG bindings largely let you ignore pools by defaulting to a single global pool
  • You can still use pools and may want to in some cases (iteration, long running programs)
callbacks and batons
Callbacks and Batons

Automating Subversion with Bindings

  • C API uses a lot of callbacks, so SWIG does as well
callbacks and batons1
Callbacks and Batons

Automating Subversion with Bindings

  • C API uses a lot of callbacks, so SWIG does as well
  • Callback args are func, baton.
callbacks and batons2
Callbacks and Batons

Automating Subversion with Bindings

  • C API uses a lot of callbacks, so SWIG does as well
  • Callback args are func, baton.
  • You can provide a binding language function for the callback.
callbacks and batons3
Callbacks and Batons

Automating Subversion with Bindings

  • C API uses a lot of callbacks, so SWIG does as well
  • Callback args are func, baton.
  • You can provide a binding language function for the callback.
  • Batons are a way of passing data through to the callback that you provide.
callbacks and batons4
Callbacks and Batons

Automating Subversion with Bindings

  • C API uses a lot of callbacks, so SWIG does as well
  • Callback args are func, baton.
  • You can provide a binding language function for the callback.
  • Batons are a way of passing data through to the callback that you provide.
  • SWIG doesn’t support batons so use closures/lambdas.
swig types
SWIG Types

Automating Subversion with Bindings

  • SWIG wraps the C types for you
swig types1
SWIG Types

Automating Subversion with Bindings

  • SWIG wraps the C types for you
  • Structs have getters and setters (type_field_get/type_field_set), but syntactic sugar allows you to use structs like objects in binding language
swig types2
SWIG Types

Automating Subversion with Bindings

  • SWIG wraps the C types for you
  • Structs have getters and setters (type_field_get/type_field_set), but syntactic sugar allows you to use structs like objects in binding language
  • Structs can be allocated and freed (new_type/delete_type) e.g. new_svn_opt_revision_t()
swig types3
SWIG Types

Automating Subversion with Bindings

  • SWIG wraps the C types for you
  • Structs have getters and setters (type_field_get/type_field_set), but syntactic sugar allows you to use structs like objects in binding language
  • Structs can be allocated and freed (new_type/delete_type) e.g. new_svn_opt_revision_t()
  • Ints, Hashes and Arrays are mapped to the binding languages equivalent types
swig types4
SWIG Types

Automating Subversion with Bindings

  • SWIG wraps the C types for you
  • Structs have getters and setters (type_field_get/type_field_set), but syntactic sugar allows you to use structs like objects in binding language
  • Structs can be allocated and freed (new_type/delete_type) e.g. new_svn_opt_revision_t()
  • Ints, Hashes and Arrays are mapped to the binding languages equivalent types
  • If a type hasn’t been mapped in SWIG you may have trouble using it
canonicalization
Canonicalization

Automating Subversion with Bindings

  • C API requires that paths be UTF-8 and canonical
canonicalization1
Canonicalization

Automating Subversion with Bindings

  • C API requires that paths be UTF-8 and canonical
  • There are 3 types of paths
    • URL or URI
    • Dirent (path on local fileystem)
    • Relpath (unrooted relative path)
canonicalization2
Canonicalization

Automating Subversion with Bindings

  • C API requires that paths be UTF-8 and canonical
  • There are 3 types of paths
    • URL or URI
    • Dirent (path on local fileystem)
    • Relpath (unrooted relative path)
  • Use svn_path_is_url() and context to determine which you have
canonicalization3
Canonicalization

Automating Subversion with Bindings

  • C API requires that paths be UTF-8 and canonical
  • There are 3 types of paths
    • URL or URI
    • Dirent (path on local fileystem)
    • Relpath (unrooted relative path)
  • Use svn_path_is_url() and context to determine which you have
  • Use svn_uri_canonicalize(), svn_dirent_canonicalize() or svn_relpath_canonicalize() to canonicalize a path.
canonicalization4
Canonicalization

Automating Subversion with Bindings

  • C API requires that paths be UTF-8 and canonical
  • There are 3 types of paths
    • URL or URI
    • Dirent (path on local fileystem)
    • Relpath (unrooted relative path)
  • Use svn_path_is_url() and context to determine which you have
  • Use svn_uri_canonicalize(), svn_dirent_canonicalize() or svn_relpath_canonicalize() to canonicalize a path.
  • Not doing this will cause assertions or crashes.
error handling
Error Handling

Automating Subversion with Bindings

Python and Ruby have exceptions so errors are handled via that mechanism

error handling1
Error Handling

Automating Subversion with Bindings

  • Python and Ruby have exceptions so errors are handled via that mechanism
  • Perl does not have exceptions
    • Uses an error handler callback $SVN::Error::handler
    • Default callback croaks with message provided by libraries.
    • See perldoc SVN::Core and read the documentation on SVN::Error for details
error handling2
Error Handling

Automating Subversion with Bindings

  • Python and Ruby have exceptions so errors are handled via that mechanism
  • Perl does not have exceptions
    • Uses an error handler callback $SVN::Error::handler
    • Default callback croaks with message provided by libraries.
    • See perldoc SVN::Core and read the documentation on SVN::Error for details
  • All have access to data from Subversion’s error structsvn_error_t
    • Errors can be chained, next error is in child field
    • apr_err is a numeric code for the error
    • message is a human readable string
python example cat
Python Example - Cat

Automating Subversion with Bindings

import sys

from svn import core, client

ctx = client.create_context()

cfg = core.svn_config_get_config(None)

cfg_config = cfg[core.SVN_CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = core.svn_cmdline_create_auth_baton(False, #non_interactive

None, #username

None, #password

None, #config_dir

False, #no_auth_cache

False, #trust_server_cert

cfg_config, #config category

None, #cancel_func

None) #cancel_baton

rev = core.svn_opt_revision_t()

rev.kind = core.svn_opt_revision_head

if core.svn_path_is_url(sys.argv[1]):

target = core.svn_uri_canonicalize(sys.argv[1])

else:

target = core.svn_dirent_canonicalize(sys.argv[1])

client.cat(sys.stdout, # output file handle

target,

rev, # revision

ctx) #client context

python example cat1
Python Example - Cat

Automating Subversion with Bindings

import sys

from svn import core, client

ctx = client.create_context()

cfg = core.svn_config_get_config(None)

cfg_config = cfg[core.SVN_CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = core.svn_cmdline_create_auth_baton(False, #non_interactive

None, #username

None, #password

None, #config_dir

False, #no_auth_cache

False, #trust_server_cert

cfg_config, #config category

None, #cancel_func

None) #cancel_baton

rev = core.svn_opt_revision_t()

rev.kind = core.svn_opt_revision_head

if core.svn_path_is_url(sys.argv[1]):

target = core.svn_uri_canonicalize(sys.argv[1])

else:

target = core.svn_dirent_canonicalize(sys.argv[1])

client.cat(sys.stdout, # output file handle

target,

rev, # revision

ctx) #client context

python example cat2
Python Example - Cat

Automating Subversion with Bindings

import sys

from svn import core, client

ctx = client.create_context()

cfg = core.svn_config_get_config(None)

cfg_config = cfg[core.SVN_CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = core.svn_cmdline_create_auth_baton(False, #non_interactive

None, #username

None, #password

None, #config_dir

False, #no_auth_cache

False, #trust_server_cert

cfg_config, #config category

None, #cancel_func

None) #cancel_baton

rev = core.svn_opt_revision_t()

rev.kind = core.svn_opt_revision_head

if core.svn_path_is_url(sys.argv[1]):

target = core.svn_uri_canonicalize(sys.argv[1])

else:

target = core.svn_dirent_canonicalize(sys.argv[1])

client.cat(sys.stdout, # output file handle

target,

rev, # revision

ctx) #client context

python example cat3
Python Example - Cat

Automating Subversion with Bindings

import sys

from svn import core, client

ctx = client.create_context()

cfg = core.svn_config_get_config(None)

cfg_config = cfg[core.SVN_CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = core.svn_cmdline_create_auth_baton(False, #non_interactive

None, #username

None, #password

None, #config_dir

False, #no_auth_cache

False, #trust_server_cert

cfg_config, #config category

None, #cancel_func

None) #cancel_baton

rev = core.svn_opt_revision_t()

rev.kind = core.svn_opt_revision_head

if core.svn_path_is_url(sys.argv[1]):

target = core.svn_uri_canonicalize(sys.argv[1])

else:

target = core.svn_dirent_canonicalize(sys.argv[1])

client.cat(sys.stdout, # output file handle

target,

rev, # revision

ctx) #client context

python example cat4
Python Example - Cat

Automating Subversion with Bindings

import sys

from svn import core, client

ctx = client.create_context()

cfg = core.svn_config_get_config(None)

cfg_config = cfg[core.SVN_CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = core.svn_cmdline_create_auth_baton(False, #non_interactive

None, #username

None, #password

None, #config_dir

False, #no_auth_cache

False, #trust_server_cert

cfg_config, #config category

None, #cancel_func

None) #cancel_baton

rev = core.svn_opt_revision_t()

rev.kind = core.svn_opt_revision_head

if core.svn_path_is_url(sys.argv[1]):

target = core.svn_uri_canonicalize(sys.argv[1])

else:

target = core.svn_dirent_canonicalize(sys.argv[1])

client.cat(sys.stdout, # output file handle

target,

rev, # revision

ctx) #client context

python example cat5
Python Example - Cat

Automating Subversion with Bindings

import sys

from svn import core, client

ctx = client.create_context()

cfg = core.svn_config_get_config(None)

cfg_config = cfg[core.SVN_CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = core.svn_cmdline_create_auth_baton(False, #non_interactive

None, #username

None, #password

None, #config_dir

False, #no_auth_cache

False, #trust_server_cert

cfg_config, #config category

None, #cancel_func

None) #cancel_baton

rev = core.svn_opt_revision_t()

rev.kind = core.svn_opt_revision_head

if core.svn_path_is_url(sys.argv[1]):

target = core.svn_uri_canonicalize(sys.argv[1])

else:

target = core.svn_dirent_canonicalize(sys.argv[1])

client.cat(sys.stdout, # output file handle

target,

rev, # revision

ctx) #client context

perl example cat
Perl Example - Cat

Automating Subversion with Bindings

use SVN::Client;

my $ctx = new SVN::Client();

my $cfg = SVN::Core::config_get_config(undef);

my $cfg_config = $cfg->{SVN::Core::CONFIG_CATEGORY_CONFIG};

$ctx->auth(

SVN::Core::cmdline_create_auth_baton(0, #non_interactive

undef, #username

undef, #password

undef, #config_dir

0, #no_auth_cache

0, #trust_server_cert,

$cfg_config, #config category

undef, #cancel_func

undef) #cancel_baton

);

my $target;

if (SVN::Core::path_is_url($ARGV[0])) {

$target = SVN::Core::uri_canonicalize($ARGV[0]);

} else {

$target = SVN::Core::dirent_canonicalize($ARGV[0]);

}

$ctx->cat(\*STDOUT, #output filehandle

$target,

'HEAD'); #rev

perl example cat1
Perl Example - Cat

Automating Subversion with Bindings

use SVN::Client;

my $ctx = new SVN::Client();

my $cfg = SVN::Core::config_get_config(undef);

my $cfg_config = $cfg->{SVN::Core::CONFIG_CATEGORY_CONFIG};

$ctx->auth(

SVN::Core::cmdline_create_auth_baton(0, #non_interactive

undef, #username

undef, #password

undef, #config_dir

0, #no_auth_cache

0, #trust_server_cert,

$cfg_config, #config category

undef, #cancel_func

undef) #cancel_baton

);

my $target;

if (SVN::Core::path_is_url($ARGV[0])) {

$target = SVN::Core::uri_canonicalize($ARGV[0]);

} else {

$target = SVN::Core::dirent_canonicalize($ARGV[0]);

}

$ctx->cat(\*STDOUT, #output filehandle

$target,

'HEAD'); #rev

perl example cat2
Perl Example - Cat

Automating Subversion with Bindings

use SVN::Client;

my $ctx = new SVN::Client();

my $cfg = SVN::Core::config_get_config(undef);

my $cfg_config = $cfg->{SVN::Core::CONFIG_CATEGORY_CONFIG};

$ctx->auth(

SVN::Core::cmdline_create_auth_baton(0, #non_interactive

undef, #username

undef, #password

undef, #config_dir

0, #no_auth_cache

0, #trust_server_cert,

$cfg_config, #config category

undef, #cancel_func

undef) #cancel_baton

);

my $target;

if (SVN::Core::path_is_url($ARGV[0])) {

$target = SVN::Core::uri_canonicalize($ARGV[0]);

} else {

$target = SVN::Core::dirent_canonicalize($ARGV[0]);

}

$ctx->cat(\*STDOUT, #output filehandle

$target,

'HEAD'); #rev

perl example cat3
Perl Example - Cat

Automating Subversion with Bindings

use SVN::Client;

my $ctx = new SVN::Client();

my $cfg = SVN::Core::config_get_config(undef);

my $cfg_config = $cfg->{SVN::Core::CONFIG_CATEGORY_CONFIG};

$ctx->auth(

SVN::Core::cmdline_create_auth_baton(0, #non_interactive

undef, #username

undef, #password

undef, #config_dir

0, #no_auth_cache

0, #trust_server_cert,

$cfg_config, #config category

undef, #cancel_func

undef) #cancel_baton

);

my $target;

if (SVN::Core::path_is_url($ARGV[0])) {

$target = SVN::Core::uri_canonicalize($ARGV[0]);

} else {

$target = SVN::Core::dirent_canonicalize($ARGV[0]);

}

$ctx->cat(\*STDOUT, #output filehandle

$target,

'HEAD'); #rev

perl example cat4
Perl Example - Cat

Automating Subversion with Bindings

use SVN::Client;

my $ctx = new SVN::Client();

my $cfg = SVN::Core::config_get_config(undef);

my $cfg_config = $cfg->{SVN::Core::CONFIG_CATEGORY_CONFIG};

$ctx->auth(

SVN::Core::cmdline_create_auth_baton(0, #non_interactive

undef, #username

undef, #password

undef, #config_dir

0, #no_auth_cache

0, #trust_server_cert,

$cfg_config, #config category

undef, #cancel_func

undef) #cancel_baton

);

my $target;

if (SVN::Core::path_is_url($ARGV[0])) {

$target = SVN::Core::uri_canonicalize($ARGV[0]);

} else {

$target = SVN::Core::dirent_canonicalize($ARGV[0]);

}

$ctx->cat(\*STDOUT, #output filehandle

$target,

'HEAD'); #rev

ruby example cat
Ruby Example - Cat

Automating Subversion with Bindings

require "svn/client"

Svn::Client::Context.new do |ctx|

cfg = Svn::Core::Config.get()

cfg_config = cfg[Svn::Core::CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = Svn::Core.cmdline_create_auth_baton(

false, #non_interactive

nil, #username

nil, #password

nil, #config_dir

false, #no_auth_cache

false, #trust_server_cert

cfg_config, #config category

nil, #cancel_func

nil) #cancel_baton

if Svn::Core.path_is_url(ARGV[0])

target = Svn::Core::uri_canonicalize(ARGV[0])

else

target = Svn::Core::dirent_canonicalize(ARGV[0])

end

ctx.cat(target,

"HEAD", #rev

nil, #pegrev

STDOUT) #output filehandle

end

ruby example cat1
Ruby Example - Cat

Automating Subversion with Bindings

require "svn/client"

Svn::Client::Context.new do |ctx|

cfg = Svn::Core::Config.get()

cfg_config = cfg[Svn::Core::CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = Svn::Core.cmdline_create_auth_baton(

false, #non_interactive

nil, #username

nil, #password

nil, #config_dir

false, #no_auth_cache

false, #trust_server_cert

cfg_config, #config category

nil, #cancel_func

nil) #cancel_baton

if Svn::Core.path_is_url(ARGV[0])

target = Svn::Core::uri_canonicalize(ARGV[0])

else

target = Svn::Core::dirent_canonicalize(ARGV[0])

end

ctx.cat(target,

"HEAD", #rev

nil, #pegrev

STDOUT) #output filehandle

end

ruby example cat2
Ruby Example - Cat

Automating Subversion with Bindings

require "svn/client"

Svn::Client::Context.new do |ctx|

cfg = Svn::Core::Config.get()

cfg_config = cfg[Svn::Core::CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = Svn::Core.cmdline_create_auth_baton(

false, #non_interactive

nil, #username

nil, #password

nil, #config_dir

false, #no_auth_cache

false, #trust_server_cert

cfg_config, #config category

nil, #cancel_func

nil) #cancel_baton

if Svn::Core.path_is_url(ARGV[0])

target = Svn::Core::uri_canonicalize(ARGV[0])

else

target = Svn::Core::dirent_canonicalize(ARGV[0])

end

ctx.cat(target,

"HEAD", #rev

nil, #pegrev

STDOUT) #output filehandle

end

ruby example cat3
Ruby Example - Cat

Automating Subversion with Bindings

require "svn/client"

Svn::Client::Context.new do |ctx|

cfg = Svn::Core::Config.get()

cfg_config = cfg[Svn::Core::CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = Svn::Core.cmdline_create_auth_baton(

false, #non_interactive

nil, #username

nil, #password

nil, #config_dir

false, #no_auth_cache

false, #trust_server_cert

cfg_config, #config category

nil, #cancel_func

nil) #cancel_baton

if Svn::Core.path_is_url(ARGV[0])

target = Svn::Core::uri_canonicalize(ARGV[0])

else

target = Svn::Core::dirent_canonicalize(ARGV[0])

end

ctx.cat(target,

"HEAD", #rev

nil, #pegrev

STDOUT) #output filehandle

end

ruby example cat4
Ruby Example - Cat

Automating Subversion with Bindings

require "svn/client"

Svn::Client::Context.new do |ctx|

cfg = Svn::Core::Config.get()

cfg_config = cfg[Svn::Core::CONFIG_CATEGORY_CONFIG]

ctx.auth_baton = Svn::Core.cmdline_create_auth_baton(

false, #non_interactive

nil, #username

nil, #password

nil, #config_dir

false, #no_auth_cache

false, #trust_server_cert

cfg_config, #config category

nil, #cancel_func

nil) #cancel_baton

if Svn::Core.path_is_url(ARGV[0])

target = Svn::Core::uri_canonicalize(ARGV[0])

else

target = Svn::Core::dirent_canonicalize(ARGV[0])

end

ctx.cat(target,

"HEAD", #rev

nil, #pegrev

STDOUT) #output filehandle

end

python example log
Python Example - Log

Automating Subversion with Bindings

deflog_entry_receiver(log_entry, pool):

print("r"+str(log_entry.revision))

revprops = log_entry.revprops

print(revprops['svn:log']+"\n")

end = core.svn_opt_revision_t()

end.kind = core.svn_opt_revision_number

end.value.number = 0

rev_range = core.svn_opt_revision_range_t()

rev_range.start = rev

rev_range.end = end

client.log5((target,), #target

rev, #pegrev

(rev_range,), #rev range

0, #limit (0=unlimited)

True, #discover changed paths

True, #strict_node_history

False, #include_merged_revisions

None, #array of revprops to retrieve

# (None for all)

log_entry_receiver, #callback

ctx)

python example log1
Python Example - Log

Automating Subversion with Bindings

deflog_entry_receiver(log_entry, pool):

print("r"+str(log_entry.revision))

revprops = log_entry.revprops

print(revprops['svn:log']+"\n")

end = core.svn_opt_revision_t()

end.kind = core.svn_opt_revision_number

end.value.number = 0

rev_range = core.svn_opt_revision_range_t()

rev_range.start = rev

rev_range.end = end

client.log5((target,), #target

rev, #pegrev

(rev_range,), #rev range

0, #limit (0=unlimited)

True, #discover changed paths

True, #strict_node_history

False, #include_merged_revisions

None, #array of revprops to retrieve

# (None for all)

log_entry_receiver, #callback

ctx)

python example log2
Python Example - Log

Automating Subversion with Bindings

deflog_entry_receiver(log_entry, pool):

print("r"+str(log_entry.revision))

revprops = log_entry.revprops

print(revprops['svn:log']+"\n")

end = core.svn_opt_revision_t()

end.kind = core.svn_opt_revision_number

end.value.number = 0

rev_range = core.svn_opt_revision_range_t()

rev_range.start = rev

rev_range.end = end

client.log5((target,), #target

rev, #pegrev

(rev_range,), #rev range

0, #limit (0=unlimited)

True, #discover changed paths

True, #strict_node_history

False, #include_merged_revisions

None, #array of revprops to retrieve

# (None for all)

log_entry_receiver, #callback

ctx)

python example log3
Python Example - Log

Automating Subversion with Bindings

deflog_entry_receiver(log_entry, pool):

print("r"+str(log_entry.revision))

revprops = log_entry.revprops

print(revprops['svn:log']+"\n")

end = core.svn_opt_revision_t()

end.kind = core.svn_opt_revision_number

end.value.number = 0

rev_range = core.svn_opt_revision_range_t()

rev_range.start = rev

rev_range.end = end

client.log5((target,), #target

rev, #pegrev

(rev_range,), #rev range

0, #limit (0=unlimited)

True, #discover changed paths

True, #strict_node_history

False, #include_merged_revisions

None, #array of revprops to retrieve

# (None for all)

log_entry_receiver, #callback

ctx)

perl example log
Perl Example - Log

Automating Subversion with Bindings

sub log_entry_receiver {

my ($log_entry,$pool) = @_;

my $revprops = $log_entry->revprops;

print "r",$log_entry->revision;

print "\n$revprops->{'svn:log'}\n\n"

}

$ctx->log5($target,

'HEAD', #pegrev

['HEAD',0], #rev range

0, #limit (0=unlimited)

1, #discover_changed_paths

1, #strict_node_history

0, #include_merged_revisions

undef, #array of revprops to retrive

# (undef for all)

\&log_entry_receiver); #callback

perl example log1
Perl Example - Log

Automating Subversion with Bindings

sub log_entry_receiver {

my ($log_entry,$pool) = @_;

my $revprops = $log_entry->revprops;

print "r",$log_entry->revision;

print "\n$revprops->{'svn:log'}\n\n"

}

$ctx->log5($target,

'HEAD', #pegrev

['HEAD',0], #rev range

0, #limit (0=unlimited)

1, #discover_changed_paths

1, #strict_node_history

0, #include_merged_revisions

undef, #array of revprops to retrive

# (undef for all)

\&log_entry_receiver); #callback

perl example log2
Perl Example - Log

Automating Subversion with Bindings

sub log_entry_receiver {

my ($log_entry,$pool) = @_;

my $revprops = $log_entry->revprops;

print "r",$log_entry->revision;

print "\n$revprops->{'svn:log'}\n\n"

}

$ctx->log5($target,

'HEAD', #pegrev

['HEAD',0], #rev range

0, #limit (0=unlimited)

1, #discover_changed_paths

1, #strict_node_history

0, #include_merged_revisions

undef, #array of revprops to retrive

# (undef for all)

\&log_entry_receiver); #callback

ruby example log
Ruby Example - Log

Automating Subversion with Bindings

args = [target,

"HEAD", #start rev

0, #end rev

0, #limit

true, #discover_changed_paths

true] #strict node history

ctx.log(*args) do |changed_paths, rev, author, date, message|

print("r",rev,"\n")

print(message,"\n\n")

end

ruby example log1
Ruby Example - Log

Automating Subversion with Bindings

args = [target,

"HEAD", #start rev

0, #end rev

0, #limit

true, #discover_changed_paths

true] #strict node history

ctx.log(*args) do |changed_paths, rev, author, date, message|

print("r",rev,"\n")

print(message,"\n\n")

end

ruby example log2
Ruby Example - Log

Automating Subversion with Bindings

args = [target,

"HEAD", #start rev

0, #end rev

0, #limit

true, #discover_changed_paths

true] #strict node history

ctx.log(*args) do |changed_paths, rev, author, date, message|

print("r",rev,"\n")

print(message,"\n\n")

end

ruby example log3
Ruby Example - Log

Automating Subversion with Bindings

args = [target,

"HEAD", #start rev

0, #end rev

0, #limit

true, #discover_changed_paths

true] #strict node history

ctx.log(*args)do |changed_paths, rev, author, date, message|

print("r",rev,"\n")

print(message,"\n\n")

end

swig advice
SWIG Advice

Automating Subversion with Bindings

  • Use the latest version
swig advice1
SWIG Advice

Automating Subversion with Bindings

  • Use the latest version
  • Refer to C API documentation to determine arguments
swig advice2
SWIG Advice

Automating Subversion with Bindings

  • Use the latest version
  • Refer to C API documentation to determine arguments
  • Use the force
swig advice3
SWIG Advice

Automating Subversion with Bindings

  • Use the latest version
  • Refer to C API documentation to determine arguments
  • Use the force source
swig advice4
SWIG Advice

Automating Subversion with Bindings

  • Use the latest version
  • Refer to C API documentation to determine arguments
  • Use the source and examples under tools/examples, {tools,contrib}/{client-side,hook-scripts,server-side}, and the test suites for the bindings.
swig advice5
SWIG Advice

Automating Subversion with Bindings

  • Use the latest version
  • Refer to C API documentation to determine arguments
  • Use the source and examples under tools/examples, {tools,contrib}/{client-side,hook-scripts,server-side}, and the test suites for the bindings.
  • Errors about missing functions are often a sign of mismatched libraries. Check that the language path is correct and that the Subversion libraries being loaded match. Adding a sleep to your code and then using lsof against that process can be helpful here.
swig advice6
SWIG Advice

Automating Subversion with Bindings

  • If you can, build your own with debug symbols by passing this to configure:

--enable-maintainer-mode

swig advice7
SWIG Advice

Automating Subversion with Bindings

  • If you can, build your own with debug symbols by passing this to configure:

--enable-maintainer-mode

  • Use the start.sh script included with my examples to use uninstalled bindings from a Subversion build to ease debugging/testing:

SVN_BUILDDIR=$HOME/subversion-1.8.3 \

start.shgdb –argsperlcat.pl

swig advice8
SWIG Advice

Automating Subversion with Bindings

  • If you can, build your own with debug symbols by passing this to configure:

--enable-maintainer-mode

  • Use the start.sh script included with my examples to use uninstalled bindings from a Subversion build to ease debugging/testing:

SVN_BUILDDIR=$HOME/subversion-1.8.3 \

start.shgdb-argsperlcat.pl

  • The start.sh script can be helpful in understanding what parameters are needed to point your language at the right libraries.
javahl
JavaHL

Automating Subversion with Bindings

  • HL stands for High Level
javahl1
JavaHL

Automating Subversion with Bindings

  • HL stands for High Level
  • Uses the C API behind the scenes via JNI
javahl2
JavaHL

Automating Subversion with Bindings

  • HL stands for High Level
  • Uses the C API behind the scenes via JNI
  • Interface is not based on C API
javahl3
JavaHL

Automating Subversion with Bindings

  • HL stands for High Level
  • Uses the C API behind the scenes via JNI
  • Interface is not based on C API
  • Hides details like APR Pools
javahl4
JavaHL

Automating Subversion with Bindings

HL stands for High Level

Uses the C API behind the scenes via JNI

Interface is not based on C API

Hides details like APR Pools

Interface is more Java like than SWIG bindings are to their languages

javahl5
JavaHL

Automating Subversion with Bindings

  • HL stands for High Level
  • Uses the C API behind the scenes via JNI
  • Interface is not based on C API
  • Hides details like APR Pools
  • Interface is more Java like than SWIG bindings are to their languages
  • Don’t need to canonicalize
javahl6
JavaHL

Automating Subversion with Bindings

  • HL stands for High Level
  • Uses the C API behind the scenes via JNI
  • Interface is not based on C API
  • Hides details like APR Pools
  • Interface is more Java like than SWIG bindings are to their languages
  • Don’t need to canonicalize
  • Throws SubversionException and ClientException
javahl example cat
JavaHL Example - Cat

Automating Subversion with Bindings

import org.apache.subversion.javahl.SVNClient;

import org.apache.subversion.javahl.types.*;

import org.apache.subversion.javahl.ClientException;

public class cat {

public static void main(String[] args)

throws ClientException

{

SVNClient client = new SVNClient();

client.streamFileContent(args[0], // target

Revision.HEAD, // rev

Revision.HEAD, // peg rev

System.out); //output

}

}

javahl example cat1
JavaHL Example - Cat

Automating Subversion with Bindings

import org.apache.subversion.javahl.SVNClient;

import org.apache.subversion.javahl.types.*;

import org.apache.subversion.javahl.ClientException;

public class cat {

public static void main(String[] args)

throws ClientException

{

SVNClient client = new SVNClient();

client.streamFileContent(args[0], // target

Revision.HEAD, // rev

Revision.HEAD, // peg rev

System.out); //output

}

}

javahl example cat2
JavaHL Example - Cat

Automating Subversion with Bindings

import org.apache.subversion.javahl.SVNClient;

import org.apache.subversion.javahl.types.*;

import org.apache.subversion.javahl.ClientException;

public class cat {

public static void main(String[] args)

throws ClientException

{

SVNClient client = new SVNClient();

client.streamFileContent(args[0], // target

Revision.HEAD, // rev

Revision.HEAD, // peg rev

System.out); //output

}

}

javahl example cat3
JavaHL Example - Cat

Automating Subversion with Bindings

import org.apache.subversion.javahl.SVNClient;

import org.apache.subversion.javahl.types.*;

import org.apache.subversion.javahl.ClientException;

public class cat {

public static void main(String[] args)

throws ClientException

{

SVNClient client = new SVNClient();

client.streamFileContent(args[0], // target

Revision.HEAD, // rev

Revision.HEAD, // peg rev

System.out); //output

}

}

javahl example log 1 2
JavaHL Example – Log (1/2)

Automating Subversion with Bindings

import org.apache.subversion.javahl.SVNClient;

import org.apache.subversion.javahl.types.*;

import org.apache.subversion.javahl.callback.*;

import org.apache.subversion.javahl.ClientException;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

import java.util.Map;

import java.io.UnsupportedEncodingException;

public class log {

public static void main(String[] args)

throws ClientException

{

SVNClient client = new SVNClient();

List<RevisionRange> revRanges = new ArrayList<RevisionRange>(1);

revRanges.add(new RevisionRange(Revision.HEAD,

Revision.getInstance(0)));

Set<String> revProps = new HashSet<String>(1);

revProps.add("svn:log");

javahl example log 1 21
JavaHL Example – Log (1/2)

Automating Subversion with Bindings

import org.apache.subversion.javahl.SVNClient;

import org.apache.subversion.javahl.types.*;

import org.apache.subversion.javahl.callback.*;

import org.apache.subversion.javahl.ClientException;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

import java.util.Map;

import java.io.UnsupportedEncodingException;

public class log {

public static void main(String[] args)

throws ClientException

{

SVNClient client = new SVNClient();

List<RevisionRange> revRanges = new ArrayList<RevisionRange>(1);

revRanges.add(new RevisionRange(Revision.HEAD,

Revision.getInstance(0)));

Set<String> revProps = new HashSet<String>(1);

revProps.add("svn:log");

javahl example log 1 22
JavaHL Example – Log (1/2)

Automating Subversion with Bindings

import org.apache.subversion.javahl.SVNClient;

import org.apache.subversion.javahl.types.*;

import org.apache.subversion.javahl.callback.*;

import org.apache.subversion.javahl.ClientException;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

import java.util.Map;

import java.io.UnsupportedEncodingException;

public class log {

public static void main(String[] args)

throws ClientException

{

SVNClient client = new SVNClient();

List<RevisionRange> revRanges = new ArrayList<RevisionRange>(1);

revRanges.add(new RevisionRange(Revision.HEAD,

Revision.getInstance(0)));

Set<String> revProps = new HashSet<String>(1);

revProps.add("svn:log");

javahl example log 2 2
JavaHL Example – Log (2/2)

Automating Subversion with Bindings

client.logMessages(args[0], // target

Revision.HEAD, //peg rev

revRanges, // rev ranges

true, // stop on copy

true, // discover path

false, // include merged revisions

revProps, // revprops to get

0, // limit (0 = unlimited)

new LogMessageCallback () {

public void singleMessage(Set<ChangePath> changedPaths,

long revision,

Map<String,byte[]> revprops,

booleanhasChildren)

{

byte[] message = revprops.get("svn:log");

System.out.println("r" + revision);

if (message != null) {

try {

System.out.println(new String(message, "UTF-8"));

} catch (UnsupportedEncodingException e) { /* ignore */ }

}

System.out.println("\n");

}

});

}

}

javahl example log 2 21
JavaHL Example – Log (2/2)

Automating Subversion with Bindings

client.logMessages(args[0], // target

Revision.HEAD, //peg rev

revRanges, // rev ranges

true, // stop on copy

true, // discover path

false, // include merged revisions

revProps, // revprops to get

0, // limit (0 = unlimited)

new LogMessageCallback () {

public void singleMessage(Set<ChangePath> changedPaths,

long revision,

Map<String,byte[]> revprops,

booleanhasChildren)

{

byte[] message = revprops.get("svn:log");

System.out.println("r" + revision);

if (message != null) {

try {

System.out.println(new String(message, "UTF-8"));

} catch (UnsupportedEncodingException e) { /* ignore */ }

}

System.out.println("\n");

}

});

}

}

javahl example log 2 22
JavaHL Example – Log (2/2)

Automating Subversion with Bindings

client.logMessages(args[0], // target

Revision.HEAD, //peg rev

revRanges, // rev ranges

true, // stop on copy

true, // discover path

false, // include merged revisions

revProps, // revprops to get

0, // limit (0 = unlimited)

new LogMessageCallback () {

public void singleMessage(Set<ChangePath> changedPaths,

long revision,

Map<String,byte[]> revprops,

booleanhasChildren)

{

byte[] message = revprops.get("svn:log");

System.out.println("r" + revision);

if (message != null) {

try {

System.out.println(new String(message, "UTF-8"));

} catch (UnsupportedEncodingException e) { /* ignore */ }

}

System.out.println("\n");

}

});

}

}

getting help resources
Getting Help/Resources

Automating Subversion with Bindings

  • http://svn.ms/autosvnexamples
  • http://subversion.apache.org/mailing-lists.html (particularly users@subversion.apache.org)
  • http://subversion.apache.org/docs/ (C API and JavaHL documentation)
  • http://svnbook.red-bean.com/ (Chapter 8)
  • perldoc SVN::Client (et al)
  • http://svn.apache.org/repos/asf/subversion/trunk/
  • http://www.wandisco.com/subversion/download
  • http://alagazam.net/
  • http://pysvn.tigris.org/
  • http://svnkit.com/
contributing
Contributing

Automating Subversion with Bindings

Found a Bug? Have a fix for a bug? Want to write documentation?

Participate at dev@subversion.apache.org mailing list.