Subversion API usage

Source: Internet
Author: User
Tags hacking guide subversion client

Use API

Using the Subversion library API to develop applications looks quite straightforward. All public header files are placed in the source filesubversion/includeDirectory, from the source code to compile and install the Subversion itself, you need to copy these header files to the system location. These header files include the functions and types that can be accessed by all users and Subversion libraries. The Subversion developer community carefully ensures that all public APIs have good documentation-directly reference the documentation of header files.

First, you should note that the data types and methods of the Subversion are protected by namespaces.svn_Followed by a definition of this object (suchwc,clientAndfsThe short encoding of the library, followed by an underscore (_) And the Object Name. The semi-public method (used by the library, but the code outside the library cannot be used and can only be seen in the Library's own directory) is different from the naming mode, not followed by an underscore after the library code, they use two underscores (__). The private method of the given source file does not have a special prefix.staticStatement. Of course, a compiler does not care about naming conventions, but is used to differentiate the application scope of a given method or data type.

Another good resource for Subversion API programming is the hacking guide.http://subversion.tigris.org/hacking.htmlFound. This document contains useful information, satisfying the requirements of Subversion developers and developers who use Subversion as a third-party library. [50]

Apache Portable Runtime Library

With Subversion's own data type, you will see a lotaprData Type reference at the beginning-an object from the Apache Portable Runtime Library (APR. APR is an Apache Portable Runtime Library. It is derived from the multi-platform nature of server code and attempts to isolate specific bytes of different operating systems from unrelated operating system code. As a result, a base API library is provided, with only some moderate differences-or a wide range-from various operating systems. The Apache HTTP server is obviously the first user of the APR database. The Subversion developer immediately finds the value of using the APR database. This means that the Subversion has no specific operating system code, and that the Subversion client can be compiled and run on the platform where the Server exists. The current list includes various types of Unix, Win32, OS/2, and Mac OS X.

In addition to cross-platform consistent system calls, [51] APR provides Subversion with fast access to multiple data types, such as dynamic arrays and hash tables. Subversion is widely used in code, but the most common APR type in the Subversion API prototype is the apr_pool_t-APR memory pool, subversion uses the internal buffer pool for memory allocation (unless the external library requires a different memory management mode when passing parameters through the API ), [52] if a person does not need to do the same thing for the Subversion API encoding, they can provide a buffer pool for the API as needed. This means that the Subversion API user must also link to APR and must callapr_initialize()To initialize the APR subsystem. When using the Subversion API, you must create and manage the pool.svn_pool_create(),svn_pool_clear()Andsvn_pool_destroy().

Use memory pool Programming

Almost every developer who has used the C language once lamented the daunting memory management, allocated enough memory, and tracked the memory allocation, releasing the memory when there is no need-this task will be very complicated. Of course, if you do not do this correctly, the program will destroy yourself, or even worse, paralyze your computer.

On the other hand, the advanced language completely frees developers from memory management. [53] using languages such as Java and PythonGarbage CollectionPrinciple: allocate the object memory as needed and clean up when not in use.

APR provides a medium memory management method called pool-based, allowing developers to control memory in a low-resolution manner-memory of each block (or pool, instead of every object. Not usedmalloc()And other ways to allocate memory based on objects, you require APR to create a memory pool from the memory. When you stop using the objects created in the pool, you destroy the pool, it can effectively cancel the memory consumed by the objects. Through the pool, you do not need to track the memory release of each object. Your program only needs to track these objects and allocate them to the pool, the lifecycle of the Pool (the time between the creation and deletion of the pool) meets the needs of all objects.

URL and path requirements

Because the distributed version control operation is the focus of Subversion, it makes sense to pay attention to the International (i18n) support. After all, "distributed" may mean "cross-office" and "Cross-world ". To make it easier, all public interfaces of Subversion only accept path parameters that are traditionally encoded using UTF-8. This means that, for example, any new client library using the libsvn_client interface, before passing these parameters to the Subversion library, you need to first convert the path from the local code to the UTF-8 code, the path passed back from the Subversion is converted to the local code. Fortunately, the Subversion provides a conversion method that can be used by any program (seesubversion/include/svn_utf.h).

Similarly, the Subversion API requires all URL parameters to be correctly encoded in the URI, so we will not passfile:///home/username/My File.txtAsMy File.txtTo passfile:///home/username/My%20File.txt. Again, Subversion provides some helper methods you can use-svn_path_uri_encode()Andsvn_path_uri_decode()URI encoding and decoding.

Use languages other than C and C ++

In addition to the C language, if you are interested in using other languages combined with the Subversion library-such as Python scripts or Java applications-Subversion provides initial support through the simple package generator (SWIG. The SWIG binding of Subversion is locatedsubversion/bindings/swigAnd gradually enters the available status. This binding allows you to directly call the Subversion API method. Using the package will convert the script data type to the C language library type required by Subversion.

Unfortunately, the Subversion language binding lacks attention to the core Subversion module. However, it takes a lot of effort to create function binding for Python, Perl, and Ruby. To a certain extent, the workload on these interfaces can be reused on SWIG (including C #, Guile, Java, MzScheme, OCaml, PHP, and Tcl) interfaces in other languages. However, in order to complete complex APIs, some SWIG interfaces still require additional programming work. For more information about SWIG itself, see the project's website.http://www.swig.org/.

Subversion also has Java language binding, and JavaJL binding (located in the Subversion source directory treesubversion/bindings/java) It is not based on SWIG, but a mix of javah and handwritten JNI. JavaHL covers almost the API of the Subversion client, with the goal of implementing the Subversion client and integrated IDE as the basis of Java.

The Subversion language binding lacks the attention of the Subversion core module, but it can usually be trusted as a product. A large number of scripts, applications, Subversion GUI clients, and other third-party tools have now successfully used the Subversion language binding to complete Subversion integration.

Using methods in other languages to interact with Subversion does not make any sense: the Subversion development community does not provide other bindings. You can go to the Subversion Project Link Page (http://subversion.tigris.org/links.html) Find other binding links, but some popular bindings I think should pay special attention. First, popular Python bindings, Barry Scott's PySVN (http://pysvn.tigris.org/). PySVN advocates that they provide more Python-style interfaces, unlike the C-style interfaces bound to Subversion Python. For those who want to seek Subversion pure Java implementation, you can look at SVNKit (http://svnkit.com/), That is, the Subversion written from the ground up using Java. You must be careful that SVNKit does not use the Subversion core library and its behavior method does not ensure that it matches the Subversion.

Sample Code

Example 8.1 "using the version library layer" contains a section of C code (written in C) that describes the concept we are discussing. It uses the version library and file system interface (you can use the method namesvn_repos_Andsvn_fs_(Resolution) creates a version for adding a directory. You can see that APR library usage is passed for memory allocation, the Code also reveals some obscure facts about Subversion error handling-All Subversion errors must be explicitly handled to prevent memory leakage (in some cases, application failure ).

Example 8.1: Use the version library Layer

/* Convert a Subversion error into a simple boolean error code. * * NOTE:  Subversion errors must be cleared (using svn_error_clear()) *        because they are allocated from the global pool, else memory *        leaking occurs. */#define INT_ERR(expr)                           \  do {                                          \    svn_error_t *__temperr = (expr);            \    if (__temperr)                              \      {                                         \        svn_error_clear(__temperr);             \        return 1;                               \      }                                         \    return 0;                                   \  } while (0)/* Create a new directory at the path NEW_DIRECTORY in the Subversion * repository located at REPOS_PATH.  Perform all memory allocation in * POOL.  This function will create a new revision for the addition of * NEW_DIRECTORY.  Return zero if the operation completes * successfully, non-zero otherwise. */static intmake_new_directory(const char *repos_path,                   const char *new_directory,                   apr_pool_t *pool){  svn_error_t *err;  svn_repos_t *repos;  svn_fs_t *fs;  svn_revnum_t youngest_rev;  svn_fs_txn_t *txn;  svn_fs_root_t *txn_root;  const char *conflict_str;  /* Open the repository located at REPOS_PATH.    */  INT_ERR(svn_repos_open(&repos, repos_path, pool));  /* Get a pointer to the filesystem object that is stored in REPOS.    */  fs = svn_repos_fs(repos);  /* Ask the filesystem to tell us the youngest revision that   * currently exists.    */  INT_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));  /* Begin a new transaction that is based on YOUNGEST_REV.  We are   * less likely to have our later commit rejected as conflicting if we   * always try to make our changes against a copy of the latest snapshot   * of the filesystem tree.    */  INT_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, pool));  /* Now that we have started a new Subversion transaction, get a root   * object that represents that transaction.    */  INT_ERR(svn_fs_txn_root(&txn_root, txn, pool));    /* Create our new directory under the transaction root, at the path   * NEW_DIRECTORY.    */  INT_ERR(svn_fs_make_dir(txn_root, new_directory, pool));  /* Commit the transaction, creating a new revision of the filesystem   * which includes our added directory path.   */  err = svn_repos_fs_commit_txn(&conflict_str, repos,                                 &youngest_rev, txn, pool);  if (! err)    {      /* No error?  Excellent!  Print a brief report of our success.       */      printf("Directory '%s' was successfully added as new revision "             "'%ld'.\n", new_directory, youngest_rev);    }  else if (err->apr_err == SVN_ERR_FS_CONFLICT)    {      /* Uh-oh.  Our commit failed as the result of a conflict       * (someone else seems to have made changes to the same area        * of the filesystem that we tried to modify).  Print an error       * message.       */      printf("A conflict occurred at path '%s' while attempting "             "to add directory '%s' to the repository at '%s'.\n",              conflict_str, new_directory, repos_path);    }  else    {      /* Some other error has occurred.  Print an error message.       */      printf("An error occurred while attempting to add directory '%s' "             "to the repository at '%s'.\n",              new_directory, repos_path);    }  INT_ERR(err);} 

Note that in example 8.1 "using the version library layer", the code can be very easy to use.svn_fs_commit_txn()Commit a transaction. But the file system API does not know anything about the version library hook. If you want your Subversion library to automatically execute some non-Subversion tasks each time a transaction is committed (for example, send an email describing transaction modification to the developer contact list.) You need to use the libsvn_repos package feature version. This feature will first run an existingpre-commitHook the script, commit the transaction, and finally runpost-commitHook script. Hooks provide a special reporting mechanism, which does not really belong to the Core File System Library itself. (For more information about the Subversion library hook, see the "Implementation version library hook" section .)

Now let's change the language. In example 8.2, "Use Python to process version library layer", the Python binding of Subversion SWIG is used to obtain the latest version from the version library, and printed the directory accessed during the extraction.

Example 8.2. Use Python to process the version library Layer

#!/usr/bin/python"""Crawl a repository, printing versioned object path names."""import sysimport os.pathimport svn.fs, svn.core, svn.reposdef crawl_filesystem_dir(root, directory):    """Recursively crawl DIRECTORY under ROOT in the filesystem, and return    a list of all the paths at or below DIRECTORY."""    # Print the name of this path.    print directory + "/"        # Get the directory entries for DIRECTORY.    entries = svn.fs.svn_fs_dir_entries(root, directory)    # Loop over the entries.    names = entries.keys()    for name in names:        # Calculate the entry's full path.        full_path = directory + '/' + name        # If the entry is a directory, recurse.  The recursion will return        # a list with the entry and all its children, which we will add to        # our running list of paths.        if svn.fs.svn_fs_is_dir(root, full_path):            crawl_filesystem_dir(root, full_path)        else:            # Else it's a file, so print its path here.            print full_pathdef crawl_youngest(repos_path):    """Open the repository at REPOS_PATH, and recursively crawl its    youngest revision."""        # Open the repository at REPOS_PATH, and get a reference to its    # versioning filesystem.    repos_obj = svn.repos.svn_repos_open(repos_path)    fs_obj = svn.repos.svn_repos_fs(repos_obj)    # Query the current youngest revision.    youngest_rev = svn.fs.svn_fs_youngest_rev(fs_obj)        # Open a root object representing the youngest (HEAD) revision.    root_obj = svn.fs.svn_fs_revision_root(fs_obj, youngest_rev)    # Do the recursive crawl.    crawl_filesystem_dir(root_obj, "")    if __name__ == "__main__":    # Check for sane usage.    if len(sys.argv) != 2:        sys.stderr.write("Usage: %s REPOS_PATH\n"                         % (os.path.basename(sys.argv[0])))        sys.exit(1)    # Canonicalize the repository path.    repos_path = svn.core.svn_path_canonicalize(sys.argv[1])    # Do the real work.    crawl_youngest(repos_path)

The same C program needs to process the APR memory pool system, but Python handles the memory itself, and the Python binding of Subversion follows this habit. In the C language, custom data types (such as the database provided by APR) need to be processed to represent the hash of paths and entries, but Python has a hash (called "dictionaries "), it is also a built-in data type, and also provides a series of functions to operate these types, so SWIG (through the custom help of the Subversion language binding layer) be careful to map these custom data types to the Data Types of the target language, which provides a more intuitive interface for users of the target language.

The Python binding of Subversion can also be used for copy operations. In the previous sections of this chapter, we mentionedlibsvn_clientInterface. The purpose of this interface is to simplify the difficulty of writing Subversion clients. For example, 8.3 "a Python state crawler" is an example, this article describes how to use SWIG to bind an extended version of the svn status Command.

Example 8.3. A Python status Crawler

#!/usr/bin/env python"""Crawl a working copy directory, printing status information."""import sysimport os.pathimport getoptimport svn.core, svn.client, svn.wcdef generate_status_code(status):    """Translate a status value into a single-character status code,    using the same logic as the Subversion command-line client."""    code_map = { svn.wc.svn_wc_status_none        : ' ',                 svn.wc.svn_wc_status_normal      : ' ',                 svn.wc.svn_wc_status_added       : 'A',                 svn.wc.svn_wc_status_missing     : '!',                 svn.wc.svn_wc_status_incomplete  : '!',                 svn.wc.svn_wc_status_deleted     : 'D',                 svn.wc.svn_wc_status_replaced    : 'R',                 svn.wc.svn_wc_status_modified    : 'M',                 svn.wc.svn_wc_status_merged      : 'G',                 svn.wc.svn_wc_status_conflicted  : 'C',                 svn.wc.svn_wc_status_obstructed  : '~',                 svn.wc.svn_wc_status_ignored     : 'I',                 svn.wc.svn_wc_status_external    : 'X',                 svn.wc.svn_wc_status_unversioned : '?',               }    return code_map.get(status, '?')def do_status(wc_path, verbose):    # Calculate the length of the input working copy path.    wc_path_len = len(wc_path)    # Build a client context baton.    ctx = svn.client.svn_client_ctx_t()    def _status_callback(path, status, root_path_len=wc_path_len):        """A callback function for svn_client_status."""        # Print the path, minus the bit that overlaps with the root of        # the status crawl        text_status = generate_status_code(status.text_status)        prop_status = generate_status_code(status.prop_status)        print '%s%s  %s' % (text_status, prop_status, path[wc_path_len + 1:])            # Do the status crawl, using _status_callback() as our callback function.    svn.client.svn_client_status(wc_path, None, _status_callback,                                 1, verbose, 0, 0, ctx)def usage_and_exit(errorcode):    """Print usage message, and exit with ERRORCODE."""    stream = errorcode and sys.stderr or sys.stdout    stream.write("""Usage: %s OPTIONS WC-PATHOptions:  --help, -h    : Show this usage message  --verbose, -v : Show all statuses, even uninteresting ones""" % (os.path.basename(sys.argv[0])))    sys.exit(errorcode)    if __name__ == '__main__':    # Parse command-line options.    try:        opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose"])    except getopt.GetoptError:        usage_and_exit(1)    verbose = 0    for opt, arg in opts:        if opt in ("-h", "--help"):            usage_and_exit(0)        if opt in ("-v", "--verbose"):            verbose = 1    if len(args) != 1:        usage_and_exit(2)                # Canonicalize the repository path.    wc_path = svn.core.svn_path_canonicalize(args[0])    # Do the real work.    try:        do_status(wc_path, verbose)    except svn.core.SubversionException, e:        sys.stderr.write("Error (%d): %s\n" % (e[1], e[0]))        sys.exit(1)

Just like the example in "using Python to process version library layer" in example 8.2, this program is a free pool and the most important thing is to use Python data types.svn_client_ctx_t()It is spoofing, because the Subversion API does not have this method-this is only a problem in SWIG automatic language generation (this is a factory method that corresponds to a complex C structure ). You also need to note that the path passed to the Program (like the last one) is throughsvn_path_canonicalize()To prevent the assertion of the underlying C library of the Subversion, that is, to prevent the program from exiting at will immediately.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.