Automating Subversion with Bindings Ben Reser http svn
Automating Subversion with Bindings @Ben. Reser http: //svn. ms/autosvnslides
About Ben 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. Automating Subversion with Bindings Slide 2
What are Bindings?
What is Subversion… An implementation of a Version Control System? Automating Subversion with Bindings Slide 4
What is Subversion… An implementation of a Version Control System? Libraries that implement a Version Control System. Automating Subversion with Bindings Slide 5
What is Subversion… An implementation of a Version Control System? Libraries that implement a Version Control System. – Written in C Automating Subversion with Bindings Slide 6
Layered Library Design Automating Subversion with Bindings Slide 7
Layered Library Design - Client – Implements the basic functions of a client. Knows about working copies and uses the… Automating Subversion with Bindings Slide 8
Layered Library Design - Client – Implements the basic functions of a client. Knows about working copies and uses the… WC (Working Copy) – Implements the working copy Automating Subversion with Bindings Slide 9
Layered Library Design - 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: //) Automating Subversion with Bindings Slide 10
Layered Library Design - Server Repos – Repository interface which implements high level repository functionality and uses… Automating Subversion with Bindings Slide 11
Layered Library Design - Server 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) Automating Subversion with Bindings Slide 12
Layered Library Design – Misc. Subr – Miscellaneous subroutines Automating Subversion with Bindings Slide 13
Layered Library Design – Misc. Subr – Miscellaneous subroutines Delta – Tree and byte-stream differencing routines Automating Subversion with Bindings Slide 14
Layered Library Design – Misc. Subr – Miscellaneous subroutines Delta – Tree and byte-stream differencing routines Diff – Contextual differencing and merge routines Automating Subversion with Bindings Slide 15
What are Bindings? Access Subversion C APIs from other Higher Level Programming Languages Automating Subversion with Bindings Slide 16
What are Bindings? Access Subversion C APIs from other Higher Level Programming Languages Somewhat easier to use than C Automating Subversion with Bindings Slide 17
What are 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 Automating Subversion with Bindings Slide 18
What are 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 Automating Subversion with Bindings Slide 19
Why use Bindings?
Can’t I Just Script The Client? The client tries to have machine readable formats Automating Subversion with Bindings Slide 21
Can’t I Just Script The Client? 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 Automating Subversion with Bindings Slide 22
Can’t I Just Script The Client? It worked great until it ran into this output: svn log –c 933481 https: //svn. apache. org/repos/asf/subversion/trunk ------------------------------------r 933481 | 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: ---r 2 | 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 ---- Automating Subversion with Bindings Slide 23
What about XML? The client supports XML output with --xml on most commands. Automating Subversion with Bindings Slide 24
What about XML? 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 Automating Subversion with Bindings Slide 25
Command behavior changes We try to avoid changing the output and behavior of commands. Automating Subversion with Bindings Slide 26
Command behavior changes We try to avoid changing the output and behavior of commands. Automating Subversion with Bindings Slide 27
Command behavior changes We try to avoid changing the output and behavior of commands. svn mergeinfo 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. Automating Subversion with Bindings Slide 28
Greater capabilities We can implement functionality that the command line client doesn’t have. Examples: – View. VC – Subclipse – control-chars. py hook-script Automating Subversion with Bindings Slide 29
Why not use Bindings? Poor documentation Automating Subversion with Bindings Slide 30
Why not use Bindings? Poor documentation Need to install them Automating Subversion with Bindings Slide 31
Why not use Bindings? Poor documentation Need to install them Expose internal details that may be hard to understand Automating Subversion with Bindings Slide 32
Why not use Bindings? Poor documentation Need to install them Expose internal details that may be hard to understand Not always updated for the latest features Automating Subversion with Bindings Slide 33
Getting Started
What Bindings Are Available SWIG – Python – Perl – Ruby Java. HL ctypes-python SVNKit py. SVN Automating Subversion with Bindings Slide 35
What is SWIG? Simplified Wrapper and Interface Generator Automating Subversion with Bindings Slide 36
What is SWIG? Simplified Wrapper and Interface Generator – Partly automated generator Automating Subversion with Bindings Slide 37
What is SWIG? Simplified Wrapper and Interface Generator – Partly automated generator – Acts like a specialized C compiler Automating Subversion with Bindings Slide 38
What is SWIG? Simplified Wrapper and Interface Generator – Partly automated generator – Acts like a specialized C compiler Only needed at interface generation time Automating Subversion with Bindings Slide 39
How To Install Bindings Windows Mac Red. Hat based Linux Debian based Linux Other Automating Subversion with Bindings Slide 40
Windows WANdisco installer – Provides swig-python (for Python 2. 7. 2) and Java. HL Alagazam. net – Provides swig-python, swig-perl, swig-ruby, and Java. HL Automating Subversion with Bindings Slide 41
Red. Hat based Linux 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. Automating Subversion with Bindings Slide 42
Debian based Linux WANdisco packages – – python-subversion (SWIG) libsvn-ruby (and libsvn-ruby 1. 8 for Ruby 1. 8) libsvn-perl libsvn-java (Java. HL) OS Packages – Older but usually available and named same as above. Automating Subversion with Bindings Slide 43
Mac WANdisco installer – Provides swig-python, swig-perl, swig-ruby and Java. HL Mac. Ports – – subversion-javahlbindings subversion-perlbindings-5. 16 (number is perl version) subversion-python 27 bindings (number is python version) subversion-rubybindings Homebrew – can provide Java. HL, swig-perl, swig-python, and swig-ruby Xcode – Command line tools – old but includes swig-python, swig-perl and swig-ruby Automating Subversion with Bindings Slide 44
Other 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-py swig-rb Don’t use do parallel builds of bindings (-j option to make) Automating Subversion with Bindings Slide 45
Build It Yourself - SWIG 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 Automating Subversion with Bindings Slide 46
Build It Yourself - SWIG 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 Automating Subversion with Bindings Slide 47
Build It Yourself - SWIG 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 Automating Subversion with Bindings Slide 48
Build It Yourself - SWIG 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 Automating Subversion with Bindings Slide 49
Build It Yourself - Java. HL Need --enable-javahl passed to configure Automating Subversion with Bindings Slide 50
Build It Yourself - Java. HL 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 Automating Subversion with Bindings Slide 51
Build It Yourself - Java. HL 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-amd 64 Automating Subversion with Bindings Slide 52
Using the Bindings
SWIG Bindings Thin layer over C API Automating Subversion with Bindings Slide 54
SWIG 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 Automating Subversion with Bindings Slide 55
SWIG 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 Automating Subversion with Bindings Slide 56
SWIG 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. Automating Subversion with Bindings Slide 57
SWIG Modules 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 Automating Subversion with Bindings Slide 58
APR Pools APR is Apache Portable Runtime Automating Subversion with Bindings Slide 59
APR Pools APR is Apache Portable Runtime Pools are used for memory management. Automating Subversion with Bindings Slide 60
APR Pools APR is Apache Portable Runtime Pools are used for memory management. Pools have a lifetime. Lifetime ends when pool or its parent is destroyed. Automating Subversion with Bindings Slide 61
APR Pools 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) Automating Subversion with Bindings Slide 62
APR Pools 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 Automating Subversion with Bindings Slide 63
APR Pools 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) Automating Subversion with Bindings Slide 64
Callbacks and Batons C API uses a lot of callbacks, so SWIG does as well Automating Subversion with Bindings Slide 65
Callbacks and Batons C API uses a lot of callbacks, so SWIG does as well Callback args are func, baton. Automating Subversion with Bindings Slide 66
Callbacks and Batons 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. Automating Subversion with Bindings Slide 67
Callbacks and Batons 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. Automating Subversion with Bindings Slide 68
Callbacks and Batons 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. Automating Subversion with Bindings Slide 69
SWIG Types SWIG wraps the C types for you Automating Subversion with Bindings Slide 70
SWIG Types 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 Automating Subversion with Bindings Slide 71
SWIG Types 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() Automating Subversion with Bindings Slide 72
SWIG Types 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 Automating Subversion with Bindings Slide 73
SWIG Types 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 Automating Subversion with Bindings Slide 74
Canonicalization C API requires that paths be UTF-8 and canonical Automating Subversion with Bindings Slide 75
Canonicalization 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) Automating Subversion with Bindings Slide 76
Canonicalization 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 Automating Subversion with Bindings Slide 77
Canonicalization 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. Automating Subversion with Bindings Slide 78
Canonicalization 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. Automating Subversion with Bindings Slide 79
Error Handling Python and Ruby have exceptions so errors are handled via that mechanism Automating Subversion with Bindings Slide 80
Error Handling 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 Automating Subversion with Bindings Slide 81
Error Handling 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 struct svn_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 Automating Subversion with Bindings Slide 82
Python Example - Cat 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 Automating Subversion with Bindings Slide 83
Python Example - Cat 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 Automating Subversion with Bindings Slide 84
Python Example - Cat 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 Automating Subversion with Bindings Slide 85
Python Example - Cat 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 Automating Subversion with Bindings Slide 86
Python Example - Cat 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 Automating Subversion with Bindings Slide 87
Python Example - Cat 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 Automating Subversion with Bindings Slide 88
Perl Example - Cat 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 Automating Subversion with Bindings Slide 89
Perl Example - Cat 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 Automating Subversion with Bindings Slide 90
Perl Example - Cat 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 Automating Subversion with Bindings Slide 91
Perl Example - Cat 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 Automating Subversion with Bindings Slide 92
Perl Example - Cat 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 Automating Subversion with Bindings Slide 93
Ruby Example - Cat 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 Automating Subversion with Bindings Slide 94
Ruby Example - Cat 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 Automating Subversion with Bindings Slide 95
Ruby Example - Cat 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 Automating Subversion with Bindings Slide 96
Ruby Example - Cat 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 Automating Subversion with Bindings Slide 97
Ruby Example - Cat 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 Automating Subversion with Bindings Slide 98
Python Example - Log def log_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_range. end = end client. log 5((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) Automating Subversion with Bindings Slide 99
Python Example - Log def log_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_range. end = end client. log 5((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) Automating Subversion with Bindings Slide 100
Python Example - Log def log_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_range. end = end client. log 5((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) Automating Subversion with Bindings Slide 101
Python Example - Log def log_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_range. end = end client. log 5((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) Automating Subversion with Bindings Slide 102
Perl Example - Log sub log_entry_receiver { my ($log_entry, $pool) = @_; my $revprops = $log_entry->revprops; print "r", $log_entry->revision; print "n$revprops->{'svn: log'}nn" } $ctx->log 5($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 Automating Subversion with Bindings Slide 103
Perl Example - Log sub log_entry_receiver { my ($log_entry, $pool) = @_; my $revprops = $log_entry->revprops; print "r", $log_entry->revision; print "n$revprops->{'svn: log'}nn" } $ctx->log 5($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 Automating Subversion with Bindings Slide 104
Perl Example - Log sub log_entry_receiver { my ($log_entry, $pool) = @_; my $revprops = $log_entry->revprops; print "r", $log_entry->revision; print "n$revprops->{'svn: log'}nn" } $ctx->log 5($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 Automating Subversion with Bindings Slide 105
Ruby Example - Log 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, "nn") end Automating Subversion with Bindings Slide 106
Ruby Example - Log 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, "nn") end Automating Subversion with Bindings Slide 107
Ruby Example - Log 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, "nn") end Automating Subversion with Bindings Slide 108
Ruby Example - Log 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, "nn") end Automating Subversion with Bindings Slide 109
SWIG Advice Use the latest version Automating Subversion with Bindings Slide 110
SWIG Advice Use the latest version Refer to C API documentation to determine arguments Automating Subversion with Bindings Slide 111
SWIG Advice Use the latest version Refer to C API documentation to determine arguments Use the force Automating Subversion with Bindings Slide 112
SWIG Advice Use the latest version Refer to C API documentation to determine arguments Use the force source Automating Subversion with Bindings Slide 113
SWIG Advice 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. Automating Subversion with Bindings Slide 114
SWIG Advice 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. Automating Subversion with Bindings Slide 115
SWIG Advice If you can, build your own with debug symbols by passing this to configure: --enable-maintainer-mode Automating Subversion with Bindings Slide 116
SWIG Advice 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. sh gdb –args perl cat. pl Automating Subversion with Bindings Slide 117
SWIG Advice 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. sh gdb -args perl cat. pl The start. sh script can be helpful in understanding what parameters are needed to point your language at the right libraries. Automating Subversion with Bindings Slide 118
Java. HL HL stands for High Level Automating Subversion with Bindings Slide 119
Java. HL HL stands for High Level Uses the C API behind the scenes via JNI Automating Subversion with Bindings Slide 120
Java. HL HL stands for High Level Uses the C API behind the scenes via JNI Interface is not based on C API Automating Subversion with Bindings Slide 121
Java. HL 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 Automating Subversion with Bindings Slide 122
Java. HL 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 Automating Subversion with Bindings Slide 123
Java. HL 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 Automating Subversion with Bindings Slide 124
Java. HL 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 Subversion. Exception and Client. Exception Automating Subversion with Bindings Slide 125
Java. HL Example - Cat import org. apache. subversion. javahl. SVNClient; import org. apache. subversion. javahl. types. *; import org. apache. subversion. javahl. Client. Exception; public class cat { public static void main(String[] args) throws Client. Exception { SVNClient client = new SVNClient(); client. stream. File. Content(args[0], // target Revision. HEAD, // rev Revision. HEAD, // peg rev System. out); //output } } Automating Subversion with Bindings Slide 126
Java. HL Example - Cat import org. apache. subversion. javahl. SVNClient; import org. apache. subversion. javahl. types. *; import org. apache. subversion. javahl. Client. Exception; public class cat { public static void main(String[] args) throws Client. Exception { SVNClient client = new SVNClient(); client. stream. File. Content(args[0], // target Revision. HEAD, // rev Revision. HEAD, // peg rev System. out); //output } } Automating Subversion with Bindings Slide 127
Java. HL Example - Cat import org. apache. subversion. javahl. SVNClient; import org. apache. subversion. javahl. types. *; import org. apache. subversion. javahl. Client. Exception; public class cat { public static void main(String[] args) throws Client. Exception { SVNClient client = new SVNClient(); client. stream. File. Content(args[0], // target Revision. HEAD, // rev Revision. HEAD, // peg rev System. out); //output } } Automating Subversion with Bindings Slide 128
Java. HL Example - Cat import org. apache. subversion. javahl. SVNClient; import org. apache. subversion. javahl. types. *; import org. apache. subversion. javahl. Client. Exception; public class cat { public static void main(String[] args) throws Client. Exception { SVNClient client = new SVNClient(); client. stream. File. Content(args[0], // target Revision. HEAD, // rev Revision. HEAD, // peg rev System. out); //output } } Automating Subversion with Bindings Slide 129
Java. HL Example – Log (1/2) import org. apache. subversion. javahl. SVNClient; org. apache. subversion. javahl. types. *; org. apache. subversion. javahl. callback. *; org. apache. subversion. javahl. Client. Exception; import import java. util. Array. List; java. util. Hash. Set; java. util. List; java. util. Set; java. util. Map; java. io. Unsupported. Encoding. Exception; public class log { public static void main(String[] args) throws Client. Exception { SVNClient client = new SVNClient(); List<Revision. Range> rev. Ranges = new Array. List<Revision. Range>(1); rev. Ranges. add(new Revision. Range(Revision. HEAD, Revision. get. Instance(0))); Set<String> rev. Props = new Hash. Set<String>(1); rev. Props. add("svn: log"); Automating Subversion with Bindings Slide 130
Java. HL Example – Log (1/2) import org. apache. subversion. javahl. SVNClient; org. apache. subversion. javahl. types. *; org. apache. subversion. javahl. callback. *; org. apache. subversion. javahl. Client. Exception; import import java. util. Array. List; java. util. Hash. Set; java. util. List; java. util. Set; java. util. Map; java. io. Unsupported. Encoding. Exception; public class log { public static void main(String[] args) throws Client. Exception { SVNClient client = new SVNClient(); List<Revision. Range> rev. Ranges = new Array. List<Revision. Range>(1); rev. Ranges. add(new Revision. Range(Revision. HEAD, Revision. get. Instance(0))); Set<String> rev. Props = new Hash. Set<String>(1); rev. Props. add("svn: log"); Automating Subversion with Bindings Slide 131
Java. HL Example – Log (1/2) import org. apache. subversion. javahl. SVNClient; org. apache. subversion. javahl. types. *; org. apache. subversion. javahl. callback. *; org. apache. subversion. javahl. Client. Exception; import import java. util. Array. List; java. util. Hash. Set; java. util. List; java. util. Set; java. util. Map; java. io. Unsupported. Encoding. Exception; public class log { public static void main(String[] args) throws Client. Exception { SVNClient client = new SVNClient(); List<Revision. Range> rev. Ranges = new Array. List<Revision. Range>(1); rev. Ranges. add(new Revision. Range(Revision. HEAD, Revision. get. Instance(0))); Set<String> rev. Props = new Hash. Set<String>(1); rev. Props. add("svn: log"); Automating Subversion with Bindings Slide 132
Java. HL Example – Log (2/2) client. log. Messages(args[0], // target Revision. HEAD, //peg rev. Ranges, // rev ranges true, // stop on copy true, // discover path false, // include merged revisions rev. Props, // revprops to get 0, // limit (0 = unlimited) new Log. Message. Callback () { public void single. Message(Set<Change. Path> changed. Paths, long revision, Map<String, byte[]> revprops, boolean has. Children) { byte[] message = revprops. get("svn: log"); System. out. println("r" + revision); if (message != null) { try { System. out. println(new String(message, "UTF-8")); } catch (Unsupported. Encoding. Exception e) { /* ignore */ } } System. out. println("n"); } } Automating Subversion with Bindings Slide 133
Java. HL Example – Log (2/2) client. log. Messages(args[0], // target Revision. HEAD, //peg rev. Ranges, // rev ranges true, // stop on copy true, // discover path false, // include merged revisions rev. Props, // revprops to get 0, // limit (0 = unlimited) new Log. Message. Callback () { public void single. Message(Set<Change. Path> changed. Paths, long revision, Map<String, byte[]> revprops, boolean has. Children) { byte[] message = revprops. get("svn: log"); System. out. println("r" + revision); if (message != null) { try { System. out. println(new String(message, "UTF-8")); } catch (Unsupported. Encoding. Exception e) { /* ignore */ } } System. out. println("n"); } } Automating Subversion with Bindings Slide 134
Java. HL Example – Log (2/2) client. log. Messages(args[0], // target Revision. HEAD, //peg rev. Ranges, // rev ranges true, // stop on copy true, // discover path false, // include merged revisions rev. Props, // revprops to get 0, // limit (0 = unlimited) new Log. Message. Callback () { public void single. Message(Set<Change. Path> changed. Paths, long revision, Map<String, byte[]> revprops, boolean has. Children) { byte[] message = revprops. get("svn: log"); System. out. println("r" + revision); if (message != null) { try { System. out. println(new String(message, "UTF-8")); } catch (Unsupported. Encoding. Exception e) { /* ignore */ } } System. out. println("n"); } } Automating Subversion with Bindings Slide 135
Resources
Getting Help/Resources http: //svn. ms/autosvnexamples http: //subversion. apache. org/mailing-lists. html (particularly users@subversion. apache. org) http: //subversion. apache. org/docs/ (C API and Java. HL 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/ Automating Subversion with Bindings Slide 137
Contributing Found a Bug? Have a fix for a bug? Want to write documentation? Participate at dev@subversion. apache. org mailing list. Automating Subversion with Bindings Slide 138
Questions?
- Slides: 139