Subversion Repositories DevTools

Rev

Rev 1295 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#!c:/perl/bin/perl.exe -w

###############################################################################
# Codestriker: Copyright (c) 2001 - 2004 David Sitsky.  All rights reserved.
# sits@users.sourceforge.net
#
# This program is free software; you can redistribute it and modify it under
# the terms of the GPL.

# Perl script for creating a single diff file over a Visual SourceSafe
# project, in a suitable form that can be input as a Codestiker
# (http://codestriker.sourceforge.net) topic.

###############################################################################
# Script configuration.

# If no argument is passed to the script, this is the SourceSafe
# project which will be used.  Modify this to reflect your own usage.
my $ss_project = '$/Project';

# Set this to the path of your ss.exe executable.
my $ss = 'C:/Program Files/Microsoft Visual Studio/VSS/win32/ss.exe';

# Specify the SS username and password to use when running ss.exe
# commands.
my $ss_username = 'admin';
my $ss_password = 'password';

# Specify the location of the SS repository.  If this is left empty
# then the SSDIR environment variable will not be set, and ss.exe will
# use the default repository.
my $ssdir = '';
#my $ssdir = '\\\\VisualSourceSafeMachineName\\SharedRepositoryPath';
#my $ssdir = 'c:\\Program Files\\Microsoft Visual Studio\\VSS';

# Set this to 1 to see all the SS commands being executed.
my $verbose = 0;

# End script configuration.
###############################################################################

use strict;
use File::Temp qw/ tmpnam tempdir /;

# First, check if an argument has been passed, which overrides
# $ss_project.
if ($#ARGV == 0) {
    $ss_project = $ARGV[0];
} elsif ($#ARGV > 0) {
    print STDERR "usage: ssdiff.pl [SourceSafe Project] > file.txt\n";
    print STDERR "       SourceSafe Project defaulted to $ss_project\n";
    exit 1;
}

# Create a temporary directory where all of the temporary files
# will be written to.  This iwll be automatically removed when the
# script exits.
my $tempdir;
if (defined $Codestriker::tmpdir && $Codestriker::tmpdir ne "") {
    $tempdir = tempdir(DIR => $Codestriker::tmpdir, CLEANUP => 1);
}
else {
    $tempdir = tempdir(CLEANUP => 1);
}

# Set the SSDIR environment variable if necessary.
if (defined $ssdir && $ssdir ne '')
{
    $ENV{SSDIR} = $ssdir;
}

# Now execute an 'ss dir' command to determine what files are a part
# of this project.
if ($verbose) {
    print STDERR "\"$ss\" dir -y${ss_username},${ss_password}" .
        " -R -I-Y \"$ss_project\"\n";
}
open(VSS, "\"$ss\" dir -y${ss_username},${ss_password}" .
     " -R -I-Y \"$ss_project\" |") || die "Unable to run ss diff command: $!";

# Collect the list of filename and revision numbers into a list.
my @files = ();
my $current_dir = '';
my $top_dir;
while (<VSS>) {
    if (/^(\$\/.*):$/o) {
        # Entering a new top-level directory.
        $current_dir = $1;
        $top_dir = $1 unless defined $top_dir;
    } elsif (/^\$[^\/]/o) {
        # Sub-directory entry which can be skipped.
    } elsif (/^\d+ item/o) {
        # Item count line which can be skipped.
    } elsif (/^\s*$/o) {
        # Skip blank lines.
    } elsif (/^(.*)$/o) {
        # Actual file entry.
        push @files, "$current_dir/$1";
    }
}
close VSS;

my $top_dir_length = length($top_dir);

# Now for each text file, we need to run an 'ss diff' command to see
# what contents have changed.
for (my $i = 0; $i <= $#files; $i++) {
    # Determine if the file is a text file, and if not, skip it.
    # Also determine its version number.
    if ($verbose) {
        print STDERR "\"$ss\" properties \"$files[$i]\"" .
            " -y${ss_username},${ss_password} -I-Y\n";
    }
    open(VSS, "\"$ss\" properties \"$files[$i]\"" .
         " -y${ss_username},${ss_password} -I-Y |")
            || die "Unable to run ss properties on $files[$i]\n";
    my $text_type = 0;
    my $version;
    while (<VSS>) {
        if (/Type:\s*Text/o) {
            $text_type = 1;
        } elsif (/^  Version:\s+(\d+)\s/o) {
            $version = $1;
        }
    }
    close(VSS);
    next if $text_type == 0;
    die "Couldn't get version for $files[$i]\n" unless defined $version;

    # Now need to construct the path to the real file from the SS path.
    # First we need to remove the project part from the full "path".
    my $real_file = substr($files[$i], $top_dir_length+1);
    if (! defined $real_file) {
        die "Can't extract filename from $files[$i] top_dir $top_dir\n";
    }

    # Translate the forward slashes to back slashes.
    $real_file =~ s/\//\\/g;

    # If there are no slashes in the filename, we need to add .\ in the
    # front.  Don't ask!
    if ($real_file !~ /\\/o) {
        $real_file = ".\\" . $real_file;
    }

    print STDERR "Diffing $real_file against $files[$i]\n";

    # Note the command has to be redirected to a file, otherwise the ss
    # command will wrap the lines.
    my $command_output = "$tempdir\\___output.txt";
    if ($verbose) {
        print STDERR "\"$ss\" diff -y${ss_username},${ss_password} -I-Y" .
            " -DU3000X5 -O\"$command_output\" \"$files[$i]\" \"$real_file\"\n";
    }
    system("\"$ss\" diff -y${ss_username},${ss_password} -I-Y" .
           " -DU3000X5 -O\"$command_output\" \"$files[$i]\" \"$real_file\"");
    if (open(VSS, $command_output)) {
        # Because ss doesn't include the version number of the file we are
        # diffing against, we have to do so here.
        my $first_line = <VSS>;
        chop $first_line;
        print STDOUT "$first_line;$version\n";
        while (<VSS>) {
            print STDOUT $_;
        }
        close VSS;
    }
    unlink $command_output;
}