#!/usr/bin/perl # # blah blah... license info blah blah seems most other source files have this header comment format # # The Original Code was written for: # Delta Debugging Framework. # # The Initial Developer of the Original Code: # Richard Chu # # Contributor(s): # Elizabeth Chak - Documentation # # Date Created: October 09, 2006 # Date Last Modified: October 24, 2006 # # Version: 0.03 # # Description: # Light Wrapper around SVN commands used to manage, update, manipulate the SVN source repository. # The wrapper assumes the most common usage of each command. It can perform the following commands: # svn checkout # svn update # svn commit # svn diff # # One thing I haven't figured out yet is if the svn commands return a return code to indicate # whether or not the command executed successfully or not. If the svn commands do, then I # would probably perform a check on whether or not the commands executed successfully or not. # # NOTE/FIXME: Currently (Oct. 24, 2006 version), the subroutines that take in revision numbers # (update, diff) require that the argument be numerical. There is no support for # revision keywords (HEAD, BASE, COMMITED, PREV), or revision dates as described # here: http://svnbook.red-bean.com/nightly/en/svn.tour.revs.html # # Change History: # October 09, 2006: # - svn class created. Initial support for most common usage of checkout, update, and commit commands # # October 15, 2006: # - added support for most common usage of diff command. # - updated the update subroutine to receive another parameter for file/directory path. # arguments in update subroutine are all optional now. 1st argument default is "HEAD". # # October 24, 2006: # - fixed conditional statement in diff subroutine from < $nRevisions to <= $nRevisions # ############################################################################### use warnings; use strict; package RCS::SVN; #### # Create an generic RCS element. The hash ($self) holds the values for svn # url, username and password passed into the subroutine. Data type of # hash is then changed to $class. # @param url svn url # @param username svn username # @param password svn password # # Developer's comments: # I think this class should ideally be designed as a singleton but I haven't figured # out how to do that in Perl. Yet. #### sub new ($$$) { my $class = shift; # first element in @_ is class name my ($url, $username, $password) = @_; # the rest are arguments passed in to subroutine my $self = { _url => $url, _username => $username, _password => $password }; bless ($self, $class); return $self; }; #### # This is the destructor. It deletes the class variables that # consist of svn url, svn username and svn password #### sub destroy () { my $self = shift; delete $self->{_url}; delete $self->{_username}; delete $self->{_password}; } #### # Checkout subroutine checks out the source tree from the svn source repository. # # # @param directory Optional; Allows you to change the top-level directory of your # working copy to be different than that in the SVN repository. # The value must be relative position from your present working directory # If it is undefined, it will default to empty string (top-level directory # of working copy same as repository) # # Some interesting values: # "." will make the top-level directory your present working directory # "../" will make the top-level directory the parent directory of your present working directory. # "C:\<directory>" will not work as expected as the value must be relative to present working directory. #### sub checkout (;$) { my $self = shift; my $directory = pop(@_); if (defined($self->{_url})) { if (!defined($directory)) { $directory = ""; } my $rc = `svn checkout $self->{_url} $directory`; } } #### # Commit subroutine that commits changes to the source repository if the # class variables for the svn username and svn password are defined. # Argument passed in is the svn log message; can be an empty string but it's # not recommended for logging purposes. # # @param message svn log message, describing the change #### sub commit ($) { my $message = pop(@_); my $self = shift; if (defined($self->{_username}) && defined($self->{_password})) { my $rc = `svn commit -m \"$message\" --username $self->{_username} --password $self->{_password}`; } else { print "No username or password defined."; } } #### # Update subroutine that updates your working copy to the source repository to receive changes # made by other developers since your last update. An update will take files/ directories etc. # on the server and copy it to your local copy. Update is only done if the username and password # are defined and if revision numbers are not out of range. Otherwise, the user will be alerted about # the error. # # @param revision Specified by argument passed in as long as it's valid (default is HEAD revision) # Possible revision keywords: HEAD, (BASE?, COMMITTED?, PREV?) and numbers # The number has to be less or equal to the number of revisions in the SVN source repository # and can be acquired through getNumberOfRevisions() subroutine # # Revision keywords and definitions: # # HEAD # # The latest (or "youngest") revision in the repository. # # BASE # # The revision number of an item in a working copy. If the item has been locally modified, the # "BASE version" refers to the way the item appears without those local modifications. # # COMMITTED # # The most recent revision prior to, or equal to, BASE, in which an item changed. # # PREV # # The revision immediately before the last revision in which an item changed. # (Technically, COMMITTED - 1.) # # NOTE: PREV, BASE, and COMMITTED can be used to refer to local paths, but not to URLs. # # @param file Specified by second argument; file or directory is only updated if defined. # @return rc svn update command #### sub update (;$$) { my $self = shift; my ($revision, $file) = @_; if (!defined($revision)) { $revision = "HEAD"; } if (!defined($file)) { $file = ""; } my $nRevisions = $self->getNumberOfRevisions(); if (defined($self->{_username}) && defined($self->{_password}) && ($revision eq "HEAD" || $revision eq "BASE" || $revision eq "COMMITTED" || $revision eq "PREV" || ($revision > 0 && $revision <= $nRevisions))) { my $rc = `svn update -r $revision --username $self->{"_username"} --password $self->{"_password"} $file`; } else { print "username or password undefined or revision number out of range. Must be between 1 and $nRevisions"; } } #### # Diff subroutine gets the differences between two paths ; optionally takes 3 parameters. # If no arguments are given, then the user's working copy will be compared with the latest revision. # If one argument is given (a revision number), then the working copy is compared with the passed in revision. # If two arguments are given (2 revision numbers), then the first and second revision numbers passed in are compared. # If a third option is given, then the differences between the file given is returned. # The svn diff command will only perform if the username and password are defined. # # @param rev1 Revision number, working copy is compared with the passed in revision, has to be more than 0 and # less or equal to the revision number retrieved from the number of revisions in the SVN source # repository retrieved from getNumberOfRevisions subroutine # @param rev2 Second revision number, first and second revision numbers passed in are compared, has to be more # than 0 and less or equal to the revision number retrieved from the number of revisions in the SVN # source repository retrieved from getNumberOfRevisions subroutine # @param file Filename, differences between the file given is returned if this is defined # @return rc svn diff command #### sub diff (;$$$) { my $self = shift; my ($rev1, $rev2, $file) = @_; my $rc; my $nRevisions = $self->getNumberOfRevisions(); if (!defined($rev1)) { $rev1 = ""; } if (!defined($rev2)) { $rev2 = ""; } if (!defined($file)) { $file = ""; } if (defined($self->{_username}) && defined($self->{_password}) && ($rev1 eq "" || ($rev1 > 0 && $rev1 <= $nRevisions)) && ($rev2 eq "" || ($rev2 > 0 && $rev2 <= $nRevisions))) { if ($rev2 ne "") { $rev2 = ":" . $rev2; } $rc = `svn diff -r $rev1$rev2 --username $self->{_username} --password $self->{_password} $file`; } else { print "No username or password defined. Or revision number out of range."; } return $rc; } #### # getNumberOfRevisions subroutine returns the number of revisions in the SVN source repository # if the class variables username and password are defined # # @return rc number of revisions in the SVN source repository # # Comments from developer: # Did not find an svn command that returns the number of revisions so this is # like a work around. May not be the best way but it is one way. # This is supposed to be a private method. However, I have not figured out how to # properly create private methods in perl (if it's even possible). Yet. #### sub getNumberOfRevisions () { my $self = shift; my $rc = -1; if (defined($self->{_username}) && defined($self->{_password})) { my $log = `svn log -r HEAD --username $self->{"_username"} --password $self->{"_password"}`; $log =~ m/r[0-9]+/; my $r = $&; $r =~ m/[0-9]+/; $rc = $&; } return $rc; } 1; # last expression of file must return true