Emerciv Logo

Subversion, Subversion, Wherefore Art Thou Subversion

March 15, 2009
by Daniel W. Strimpel
When looking for software to help manage our projects, I came across Subversion (also known as SVN). The software helps to keep all of your files under version control, helping to eliminate most of the problems that occur in a multi-developer work environment. In this article, I am going to discuss the software and the benefits that we found as we began to institute it into our business processes. I will conclude with the class that I wrote in PHP to issue the commandline commands.

Subversion Description

Subversion is version control software to help manage changes in the software that you write. It is meant to be a replacement of the Concurrent Versions System (CVS) that was the defacto standard for many years. Both solutions are open-source tools that can be used in place of each other, however it should be noted that there are some fundamental differences between the two.

When I first started working for the company, back in 2004, I helped to implement CVS twice. While it did its job at helping another developer and me work on a large project, it was very difficult to set up. I can understand the pain that it is to try to understand the software and how to configure it as I had to learn the software because no one had worked with it before. Once it was set up though, it was very helpful in allowing the two of us to work on the project with minimal problems.

The best way to describe the software is to discuss the problems that were occurring in our development process, which using Subversion helped to fix. Most of our projects are large enough to require multiple developers/designers working together to get it done. This may be because it requires individuals with different competencies or that is is too large for one designer to do. If one person was working on a file, the other individuals could not, because the files would be overwritten by the last individual. This caused tension, as the developer with the overwritten code would be upset that he/she had to redo work (it also upset the rest of the staff that rework had to be done, thus hurting profit margins greatly). The main problem was that neither of the developers would know who was working on what, besides using the yelling method (you know, yell across the room and make sure that no one else was using the file that you wanted to modify lol).

Another problem that was common was that someone had changed code at some previous point, with no way to go back to the old code. This could have been because of overwriting or because someone was trying to fix a bug/implement a new feature. This might require rework, as the newer solution actually caused more problems than it fixed.

Subversion Benefits

The Code

The following class was used to issue the Subversion commands to manage the different projects. While this was not the only code we used, this was the foundation for the software we wrote. We wrote our own SVN management software to manage all of our clients and their projects through a web-based solution. The following class was used to issue the commandline statements that needed to be ran in order to use Subversion.

class SVNRepository {
  public static function add($path,$non_recursive=false,$quiet=false){
    $cmd = 'svn add '.($non_recursive ? '-N ' : '').($quiet ? '-q ' : '').'"'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function cat($target,$is_binary=false,$revision=0){
    $cmd = 'svn cat '.($revision > 0 ? '-R '.$revision.' ' : '').'"'.$target.'"';
    if (!$is_binary) {
      exec($cmd, $output, $return);
      return array($return, $output);
    }
    else {
      $file = '/usr/local/apache2/htdocs/'.rand().'_'.time();
      exec($cmd.' > "'.$file.'"',$output,$return);
      $file_contents = @file_get_contents($file);
      exec('rm "'.$file.'"');
      return array($return,$file_contents);
    }
  }

  public static function checkout($url,$path,$non_recursive=false,$quiet=false){
    $cmd = 'svn checkout '.($non_recursive ? '-N ' : '').($quiet ? '-q ' : '').
           '"'.$url.'" "'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function commit($path,$message,$non_recursive=false,$quiet=false){
    $cmd = 'svn commit '.($non_recursive ? '-N ' : '').($quiet ? '-q ' : '').
           '"'.$path.'" -m "'.$message.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }
  
  public static function create($path) {
    $cmd = 'svnadmin create "'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function delete($path,$quiet=false){
    $cmd = 'svn delete '.($quiet ? '-q ' : '').'"'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }
  
  public static function diff($path,$version1,$version2){
    $cmd = 'svn diff "'.$path.'@'.$version1.'" "'.$url.$path.'@'.$version2.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function export($url,$path,$non_recursive=false,$quiet=false){
    $cmd = 'svn export '.($non_recursive ? '-N ' : '').($quiet ? '-q ' : '').
           '"'.$url.'" "'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }
  
  public static function ignore($pattern, $path,$recursive=false,$quiet=false) {
    $cmd = 'svn propset svn:ignore '.($recursive ? '-R ' : '').($quiet ? '-q ' : '').
           '"'.$pattern.'" "'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }
  
  public static function import($url,$path,$message,$non_recursive=false,$quiet=false) {
    $cmd = 'svn import '.($non_recursive ? '-N ' : '').($quiet ? '-q ' : '').
           '"'.$path.'" "'.$url.'" -m "'.$message.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function info($path,$recursive=false){
    $cmd = 'svn info '.($recursive ? '-R ' : '').'"'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function listFiles($target,$recursive=false,$verbose=false,$revision=0){
    $cmd = 'svn list '.($recursive ? '-R ' : '').($revision > 0 ? '-R '.$revision.' ' : '').
           ($verbose ? '-v ' : '').'"'.$target.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function log($path,$verbose=false,$quiet=false,$start=false,$end=false){
    $cmd = 'svn log '.($verbose ? '-v ' : '').($quiet ? '-q ' : '').
           ($start && $end ? '-R '.$end.':'.$start.' ' : '').'"'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }
  
  public static function mimeGet($path,$recursive=false) {
    $cmd = 'svn propget svn:mime-type '.($recursive ? '-R ' : '').'"'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function status($path,$show_updates=false,$verbose=false,$non_recursive=false,
                                $quiet=false){
    $cmd = 'svn status '.($show_updates ? '-u ' : '').($verbose ? '-v ' : '').
           ($non_recursive ? '-N ' : '').($quiet ? '-q ' : '').'"'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }

  public static function update($path,$non_recursive=false,$quiet=false){
    $cmd = 'svn update '.($non_recursive ? '-N ' : '').($quiet ? '-q ' : '').'"'.$path.'"';
    exec($cmd, $output, $return);
    return array($return, $output);
  }
}

The class was set up as a list of static functions so that they could be issued using this syntax:

  ...
  list($return, $output) = SVNRepository::update('path/to/repository/');
  ...

Doing this enabled us to keep the SVN code in one class, helping to manage the code dealing with the SVN statements.

While the code should be pretty straight forward, I would highly recommend an individual to read the Subversion documentation before trying to use this class to implement a solution. The only function that I believe needs to be talked about is the cat function. This function will retrieve the contents of a file that is in the repository. The problem that I found was that the commandline would alter some of the contents if the file was in a binary format. To fix this, we stored the output from the commandline in a random file and opened the file using the PHP file_get_contents function. You will need to alter the random file location to a location on your server.

We most likely will alter the class as our needs change, but we have found no problems so far with what is currently there. I did not feel that it was necessary to allow all flags to be specified, however you may need this for your needs. If you simply follow the way that I added each of the flags, you should have your own solution in no time.

Conclusion

Comments
No Comments for this Article
Rate This Article

Average Article Rating
Brian's Recent Articles

Average Article Rating
Daniel's Recent Articles

Average Article Rating
Jason's Recent Articles
No Articles Found

Average Article Rating
Rob's Recent Articles

Average Article Rating
Ryan's Recent Articles
No Articles Found