Open main menu

CDOT Wiki β

Svn.pl

Revision as of 13:36, 14 December 2006 by Elichak (talk | contribs)
#!/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