oreilly.comSafari Books Online.Conferences.


Using the Subversion Client API, Part 2

by Garrett Rooney

In the first article of this series, we learned how to make basic use of the Subversion client libraries. We covered why one would want to use the Subversion client libraries directly instead of simply calling the svn binary directly, the basic use of the Apache Portable Runtime, which Subversion uses as its portability library, and a few low-level Subversion constructs, including svn_error_t and svn_client_ctx_t. Finally, we went over the first few functions necessary for making a minimal Subversion client.

Let's continue with the example begun in the first article, expanding our basic client. The examples in this article will be written for version 0.20.0 of the Subversion API. If you are using an earlier version, you should upgrade. If you are using a later version, you should be aware that there may be some differences in the API, but the concepts should still apply.

Now that you've provided your company's web developers with a minimalistic Subversion client application, which allows them to deploy sites directly from your repository onto the web server, they've become a bit more used to the idea of version control. Some of them are even using the regular svn command line client. The rest, though, are a bit stuck. They still need a way to interact with the repository to make changes to the sites that are stored there, but they uncertain about using command line tools. Fortunately, your newfound knowledge of the Subversion client APIs will save the day. All you have to do is extend your client to support a few more features. You've already got checkout, status, and update. There are just a few more you'll need to provide to give them enough functionality to make changes to the sites they're working on and commit them back into the repository.

First, a note about function targets. Many subversion commands (and the underlying libsvn_client functions which implement them) can target either a working copy or a repository. For example, you can use svn copy to copy a file in your local working copy and then commit that change back to the repository later, or you can use it to copy a file or directory in the repository directly. You would do this if you were tagging a particular release of your software, for example. Generally, the effect you get from a command that targets the repository directly can be achieved within the working copy, as long as you follow it up with a commit.

The reason the functions can work on both the repository and the working copy is efficiency. If you tag a new release of your software by performing the copy in your checked out working copy, you have to check out the directory that holds your tags as well as the one that holds the version you are tagging, which could take up a lot of disk space. Then when you do the actual copy, the client will need to write many files out to disk as part of maintaining the working copy (the contents of all the .svn directories in the new directory, as well as the actual files you copy). When you finally commit, all the changes need to be communicated to the server. Doing the copy directly in the server saves all this trouble, so it's the usual way of working with large copies like tags and branches.

For the examples in this article, we use the libsvn_client functions on the working copy, but using them on the repository is essentially the same. It only requires the addition of a new parameter which Subversion uses to hold the results of the commit and a callback function inside the client context that Subversion uses to get the log message for the commit. We'll cover both when we talk about svn_client_commit.

So What Did I Change Anyway?

To get your web developers started, all you need to do is give them the ability to edit a file, verify that the change is what they want, and commit it back to the repository. The editing part is easy. Subversion doesn't actually require you to do anything before making a change, so users can make changes in their favorite editor. Once they've made a change, use svn_client_diff to show them exactly what they are going to be committing to the repository.

svn_client_diff takes a number of arguments, but it's really not that complicated. Here's the function prototype.

svn_error_t *svn_client_diff (
                              const apr_array_header_t *diff_options,
                              const char *path1,
                              const svn_opt_revision_t *revision1,
                              const char *path2,
                              const svn_opt_revision_t *revision2,
                              svn_boolean_t recurse,
                              svn_boolean_t no_diff_deleted,
                              apr_file_t *outfile,
                              apr_file_t *errfile,
                              svn_client_ctx_t *ctx,
                              apr_pool_t *pool);

The diff_options argument is an apr_array_header_t * of const char * command line arguments to be passed to an external diff command such as GNU diff. We can just pass an empty array, since we'll be using Subversion's internal diff library to produce our diffs. It doesn't understand any options yet. path1 is the path (or URL in the repository) for the source file and revision1 determines which revision of that file to read. path2 and revision2 determine the destination file. recurse determines if the diff should recurse into the target (if the target is a directory) and no_diff_deleted indicates that there should not be any diff for deleted files. outfile and errfile are apr_file_t *s that will hold the output of the diff and any errors that occur. The client context is used for authentication when diffing against a repository.

Here's an example of how to use svn_client_diff to find the difference between the version you have in your working copy and the version you started with:

diff_wc_to_working(const char *filename,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
  apr_array_header_t *diff_opts = apr_array_make(pool, 0, sizeof (char *));
  svn_opt_revision_t rev1 = { 0 }, rev2 = { 0 };
  apr_file_t *outfile, *errfile;
  svn_error_t *err;

  /* the revision we started with. */
  rev1.kind = svn_opt_revision_head;

  /* to the revision we've got here. */
  rev2.kind = svn_opt_revision_working;

  /* for your client, you'd probably want to open temp files for this, but for 
   * our purposes we'll just use stdout and stderr. */
  apr_file_open_stdout (&outfile, pool);
  apr_file_open_stderr (&errfile, pool);

  err = svn_client_diff (diff_opts,
                         filename, &rev1,
                         filename, &rev2,
  if (err)
    handle_error (err);

Oops, I Didn't Mean To Do That

Once the developer can see what changes have been made to the working copy, a reversion back to unmodified files may be required. Subversion provides svn_client_revert to do just that. svn_client_revert is pretty simple: you give it the path to the file or directory in your working copy that you want to revert and a flag to determine if the revert should recurse into subdirectories. Then it will revert the current changes. As with svn_client_status, you can include a notification callback in the client context structure to be called for each file that is reverted. Here's an example:

revert_notification_callback (void *baton,
                              const char *path,
                              svn_wc_notify_action_t action,
                              svn_node_kind_t kind,
                              const char *mime_type,
                              svn_wc_notify_state_t content_state,
                              svn_wc_notify_state_t prop_state,
                              svn_revnum_t revision)
  printf ("reverting %s\n", path);

revert_wc_file (const char *path,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
  ctx->notify_func = revert_notification_callback;

  svn_error_t *err = svn_client_revert (path, FALSE, ctx, pool);
  if (err)
    handle_error (err);

Pages: 1, 2

Next Pagearrow

Linux Online Certification

Linux/Unix System Administration Certificate Series
Linux/Unix System Administration Certificate Series — This course series targets both beginning and intermediate Linux/Unix users who want to acquire advanced system administration skills, and to back those skills up with a Certificate from the University of Illinois Office of Continuing Education.

Enroll today!

Linux Resources
  • Linux Online
  • The Linux FAQ
  • Linux Kernel Archives
  • Kernel Traffic

  • Sponsored by: