dochanges #8

  • //
  • guest/
  • richard_geiger/
  • utils/
  • cvs2p4_meta/
  • bin/
  • dochanges
  • View
  • Commits
  • Open Download .zip Download (17 KB)
eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
  & eval 'exec perl -S $0 $argv:q'
  if 0;
#  THE PRECEEDING STUFF EXECS perl via $PATH
# -*-Fundamental-*-

require 5.000;

my $s = "\001";

# Schema stuff
#
$Act_add	= 0;
$Act_edit	= 1;
$Act_delete	= 2;
$Act_branch	= 3;
$Act_integ	= 4;
$Act_import	= 5;

#  $Id: //guest/richard_geiger/utils/cvs2p4_meta/bin/dochanges#8 $
#
#  Richard Geiger
#

sub dirname
{
  local($dir) = @_;
  $dir =~ s%^$%.%; $dir = "$dir/";
  if ($dir =~ m%^/[^/]*//*$%) { return "/"; }
  if ($dir =~ m%^.*[^/]//*[^/][^/]*//*$%)
  { $dir =~ s%^(.*[^/])//*[^/][^/]*//*$%$1%; { return $dir; } }
  return ".";
}

use Carp; # ...or flounder. (This will fail unless 'perl' is a perl5!)
$| = 1;

($Myname = $0) =~ s%^.*/%%;
$Mydir = &dirname($0);
$Here = `/bin/pwd`; chop $Here;
if ($Mydir ne ".") { chdir "$Mydir" || die "$Myname: can't chdir \"$Mydir\": $!"; }
chdir ".." || die "$Myname: can't chdir \"..\": $!";
$Mydir = `/bin/pwd`; chop $Mydir;
chdir $Here || die "$Myname: can't chdir \"$Here\": $!";

#obs#use IPC::Open2;
require "$Mydir/lib/util.pl";

$Usage = <<LIT;
$Myname: usage: $Myname [-v <n>] [-s <change>] [-c] <conversiondir>
LIT


sub usage
{
  print STDERR $Usage;
  exit 1;
}


sub help
{
  print STDERR <<LIT;
$Usage

  -v <n>       set verbosity level [0]
  -s <change>  start numbering generated changes at <change>
  -c           copy (rather than link) the file archive

$Myname uses the outputs of the genmetadata and genchanges stages of
cvs2p4 and creates a Perforce metadatabase describing the converted
changes. It also links (or, optionally, copies) the RCS archives being
converted into the file archive tree under $P4ROOT.

LIT
  exit 1;
}


sub path
{
  my($prefix, $file_dir, $file_name) = @_;
  my($path);
  $path = "$prefix";
  if ($file_dir) { $path .= "$file_dir/"; }
  $path .= "$file_name";
  return $path;
}


sub is_binary_ext
{
  my ($path) = @_;
  my ($filename) = $path;
  $filename =~ s/^.*\///;
  my $fileext;
  $filename =~ m/\.([^\.]+)$/;
  $fileext = $1;
  $fileext =~ tr/A-Z/a-z/;
  if (defined($EXT{$fileext})) { return 1; }
  return 0;
}

#if (&is_binary_ext($ARGV[0]))
#  { print "BINARY\n"; } else { print "TEXT\n"; }
#exit 1;


#  Determine whether the depot already has this file on this code line.
#  (Used to determine when we need to branch).
#

sub depot_has
{
  my($file) = @_;
  if (defined($DEPOTMAP{$file})) { return ${$DEPOTMAP{$file}}[0]; }
  return 0;
}


sub depot_newrev
{
  my($file, $action) = @_;
  my ($have, $rev);

  if ($action =~ /^(add|branch)$/)
    {
      if (defined($DEPOTMAP{$file}))
        {
          ($have, $rev) = @{$DEPOTMAP{$file}};
	  if ($have)
	    { die "already have $file on add"; }
          $have = 1;
          $rev++;
        }
      else
        {
          $have = 1;
          $rev = 1;
          $DEPOTMAP{$file} = [ ];
        }
    }
  else
    {
      if (! defined($DEPOTMAP{$file}))
        {
          print "$Myname: unmapped \"$file\" on edit/delete.\n";
          exit 1;
        }
      ($have, $rev) = @{$DEPOTMAP{$file}};

      if (! $have)
        {
          print "$Myname: don't already have \"$file\" on edit/delete.\n";
          exit 1;
        }
      if ($action eq "delete")
        { $have = 0; }
      $rev++;
    }
    
  @{$DEPOTMAP{$file}} = ( $have, $rev );

  return $rev;
}


sub genrev
{
  my ($depotfile, $p4rev, $type, $action, $modtime, $lbrfile, $lbrrev, $lbrtype) = @_;
  return "$depotfile$s$p4rev$s$type$s$action$s$modtime$s//$lbrfile$s$lbrrev$s$lbrtype";
}


sub genchange
{
  my ($revs, $ch_time, $msg, $who, $integs) = @_;

  if ($LOGNOTE)
    {
      my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
      my($ts) = sprintf("%04d/%02d/%02d %02d:%02d:%02d",
                         $year+1900, $mon+1, $mday, $hour, $min, $sec);
      $msg .= "\n[imported from CVS by cvs2p4 at $ts]\n";
    }

  my $smsg = $msg;
  $smsg = substr($smsg, 0, 31);
  $smsg = &atq($smsg);

  print DBMETA "\@pv\@ 0 \@db.change\@ $Change $Change cvs2p4 $who $ch_time 1 $smsg\n";
  
  $msg = &atq($msg);
  print DBMETA "\@pv\@ 0 \@db.desc\@ $Change $msg\n";

  foreach my $rev (@{$revs})
    {
      my ($depotfile, $p4rev, $type, $action, $modtime, $lbrfile, $lbrrev, $lbrtype) = split(/$s/, $rev);

      $depotfile = &atq($depotfile);
      $lbrfile   = &atq($lbrfile);
      $lbrrev    = &atq($lbrrev);
      $zdig      = "00000000000000000000000000000000";

      $depotfile =~ s/\/Attic(\/[^\/]+)$/$1/;

      print DBMETA "\@pv\@ 3 \@db.rev\@ $depotfile $p4rev $type $action ".
                      "$Change $ch_time $time $zdig $lbrfile $lbrrev $lbrtype\n";
      print DBMETA "\@pv\@ 0 \@db.revcx\@ $Change $depotfile $p4rev $action\n";
    }

  foreach my $integ (@{$integs})
    {
      my($tofile, $fromfile, $fromrev) = split(/$s/, $integ);

      $tofile = &atq($tofile);
      $fromfile = &atq($fromfile);

      $tofile =~ s/\/Attic(\/[^\/]+)$/$1/;
      $fromfile =~ s/\/Attic(\/[^\/]+)$/$1/;

      print DBMETA "\@pv\@ 0 \@db.integed\@ $tofile $fromfile 0 $fromrev 0 1 2 $Change\n";
      print DBMETA "\@pv\@ 0 \@db.integed\@ $fromfile $tofile 0 1 0 $fromrev 3 $Change\n";
    }

  $Change++;

}

  
sub type_of
{
   my ($rcsfile, $rev, $options) = @_;

   my $binary = 0;

   if ($options =~ /[ob]/ || &is_binary_ext($rcsfile))
     { $binary = 1; }
   elsif ($CHECKBIN)
     {
       if (&s("$CO -q -p$rev '$file' >'$Convdir/rev.tmp'"))
         {
           print "$Myname: \"$CO -p$rev '$file' >'$Convdir/rev.tmp'\" failed.\n";
           exit 1;
         }
       if (-B "$Convdir/rev.tmp") { $binary = 1; }
       unlink "$Convdir/rev.tmp";
     }
       
   my $type = 0;
   if ($binary)         { $type |= 0x0100; } else { $type |= 0x0020; }
   if ($options =~ /x/) { $type |= 0x0200; }
   return $type;
}


sub rmap
{
  my ($depotrev, $cvsrev, $revinfo) = @_;

  $depotrev =~ s/\/Attic(\/[^\/]+)$/$1/;

  $REVMAP{$depotrev} = $revinfo;
  if ($RREVMAP{$cvsrev}) { $RREVMAP{$cvsrev} .= "\001"; }
  $RREVMAP{$cvsrev} .= "$depotrev";
}

#  Process one "change" from CVS.
#  Called with the set of CVS files/revs to process in @change
#
sub dochange
{
  my %map;   # will remember the p4 rev for files in this change group, for integ records

  print "========== change group $do_change_num\n";

  if ($V > 0)
    {
      foreach $c (@change)
        {
          ($filerev, $time, $who, $state, $line, $branches, $prevrev, $options) = split(/$S/, $c);
          @filerev = split(/\//, $filerev);
          $rev = pop(@filerev);
          $file = join("/", @filerev);
         print "$who $time $filerev $state $line $branches\n";
       }
    }

  # Do the revisions...
  #
#  print "=== deletes\n";

  undef @revs;

  my $ch_time = 0;
  foreach $c (@change)
    {
      chomp $c;
      ($filerev, $time, $who, $state, $line, $branches, $prevrev, $options) = split(/$S/, $c);
      if ($line eq "$TRUNKLINE") { $line = "main"; }
      @filerev = split(/\//, $filerev);
      $rev = pop(@filerev);
      $file = join("/", @filerev);

      ($file_dir = &dirname($file)) =~ s/^$CVS_MODULE//;
      $file_dir =~ s/^\///;
      ($file_name = $file) =~ s%^.*/%%;

      $Depotfile  = &path("$P4_DEPOT/$line/", $file_dir, $file_name);
      $Importfile = &path("$IMPORT/", $file_dir, $file_name);

      if ($state eq "dead")
        {
          $Exists_in_depot = &depot_has($Depotfile);
          if ($Exists_in_depot)
            {
	      $type = &type_of($file, $rev, $options);
	      if ($time > $ch_time) { $ch_time = $time; }
	      my $grev = &depot_newrev($Depotfile, "delete");
	      &rmap("$Depotfile#$grev", $filerev, $c);
              push(@revs, (&genrev($Depotfile,
                                   $grev,
                                   $type,
                                   $Act_delete,
                                   $time, 
                                   $Importfile,
                                   $rev,
                                   $type)));
            }
        }
    }

  if ($#revs >=  0) { &genchange(\@revs, $ch_time, $MSGS{$filerev}, $who); }

#  print "===adds/edits===\n";
  undef @revs;
  $ch_time = 0;
  foreach $c (@change)
    {
      chomp $c;
      ($filerev, $time, $who, $state, $line, $branches, $prevrev, $options) = split(/$S/, $c);
      if ($line eq "$TRUNKLINE") { $line = "main"; }
      @filerev = split(/\//, $filerev);
      $rev = pop(@filerev);
      $file = join("/", @filerev);

      ($file_dir = &dirname($file)) =~ s/^$CVS_MODULE//;
      $file_dir =~ s/^\///;
      ($file_name = $file) =~ s%^.*/%%;

      $Depotfile  = &path("$P4_DEPOT/$line/", $file_dir, $file_name);
      $Importfile = &path("$IMPORT/", $file_dir, $file_name);

      # Note: we assume binary files never become text files or vice versa
      #

      if ($state ne "dead")
        {
          $Exists_in_depot = &depot_has($Depotfile);

          if ($Exists_in_depot)
            {
	      $type = &type_of($file, $rev, $options);
	      if ($time > $ch_time) { $ch_time = $time; }
	      my $grev = &depot_newrev($Depotfile, "edit");
	      &rmap("$Depotfile#$grev", $filerev, $c);
 	      push(@revs, (&genrev($Depotfile,
                                   $grev,
                                   $type,
                                   $Act_edit,
                                   $time,
                                   $Importfile,
                                   $rev,
                                   $type)));
	      $map{"$Depotfile$s$rev"} = $grev;
            }
          else
            {

	      $type = &type_of($file, $rev, $options);
	      if ($time > $ch_time) { $ch_time = $time; }
	      my $grev = &depot_newrev($Depotfile, "add");
	      &rmap("$Depotfile#$grev", $filerev, $c);
 	      push(@revs, (&genrev($Depotfile,
                                   $grev,
                                   $type,
                                   $Act_add,
                                   $time,
                                   $Importfile,
                                   $rev,
                                   $type)));
	      $map{"$Depotfile$s$rev"} = $grev;
            }
        }
    }

  if ($#revs >= 0) { &genchange(\@revs, $ch_time, $MSGS{$filerev}, $who); }

#  print "===branches===\n";
  undef @revs; undef @integs;
  $ch_time = 0;
  foreach $c (@change)
    {
      chomp $c;
      ($filerev, $time, $who, $state, $line, $branches, $prevrev, $options) = split(/$S/, $c);
      if ($line eq "$TRUNKLINE") { $line = "main"; }
      if ($state ne "dead" && $branches ne "-")
        {
          @filerev = split(/\//, $filerev);
          $rev = pop(@filerev);
          $file = join("/", @filerev);

          ($file_dir = &dirname($file)) =~ s/^$CVS_MODULE//;
          $file_dir =~ s/^\///;
          ($file_name = $file) =~ s%^.*/%%;

          $Depotfile  = &path("$P4_DEPOT/$line/", $file_dir, $file_name);
          $Importfile = &path("$IMPORT/", $file_dir, $file_name);

          foreach $branch (split(/:/, $branches))
            {
	      $type = &type_of($file, $rev, $options);

              $Depot_branchfile = &path("$P4_DEPOT/$branch/", $file_dir, $file_name);

	      if ($time > $ch_time) { $ch_time = $time; }
              my $grev = &depot_newrev($Depot_branchfile, "add");

	      &rmap("$Depot_branchfile#$grev", $filerev, $c);

 	      push(@revs, (&genrev($Depot_branchfile,
                                   $grev,
                                   $type,
                                   $Act_branch,
                                   $time,
                                   $Importfile,
                                   $rev,
                                   $type)));

	      my $bprev;
              if (! ($bprev = $map{"$Depotfile$s$rev"})) { die "unmapped rev"; }

	      push(@integs, "$Depot_branchfile$s$Depotfile$s$bprev");
            }
        } 
    }

  if ($#revs >= 0) { &genchange(\@revs, $ch_time, "Branching\n", $who, \@integs); }

}


###### main starts here
#  

# option switch variables get defaults here...

$Metadata = "metadata";

# option switch variables get defaults here...

$V = 0;
$Change = 1;
$Copy = 0;

while ($#ARGV >= 0)
  {
    if ($ARGV[0] eq "-c")    { $Copy = 1; shift; next; }
    elsif ($ARGV[0] eq "-v")
      {
        shift; if ($ARGV[0] < 0) { &usage; }
        $V = $ARGV[0]; shift; next;
      }
    elsif ($ARGV[0] eq "-s")
      {
        shift; if ($ARGV[0] < 0) { &usage; }
        $Change = $ARGV[0]; shift; next;
      }
    elsif ($ARGV[0] eq "-help")
      { &help; }
    elsif ($ARGV[0] =~ /^-/) { &usage; }
    push(@Args, $ARGV[0]);
    shift;
  }

if ($#Args ne 0) { &usage; }

$Convdir = $Args[0];
#chdir $Convdir || die "$Myname: can't chdir \"$Convdir\": $!";
#$Convdir = `/bin/pwd`; chop $Convdir;
#chdir $Here || die "$Myname: can't chdir \"$Here\": $!";

require "$Convdir/config";

my ($p4d_y, $p4d_r) = &p4d_vers($P4D);

if ($p4d_y < 2002)
  { print "$Myname: this version requires p4d 2002.1 or later <$p4d>.\n"; exit 1; }

if ($CHECKBIN)
  {
    #  Path the the RCS co command
    #
    if (! defined($CO)) { $CO = "/usr/local/bin/co"; }
    if (! -x ($CO))
      { print "$Myname: No executable \"co\" command at \"$CO\".\n"; exit 1; }
  }

$Metadata = "$Convdir/metadata";
$Logmsgs  = "$Convdir/logmsgs";
$Changes  = "$Convdir/changes";
$Revmap   = "$Convdir/revmap";
$Rrevmap  = "$Convdir/rrevmap";
$Depotmap = "$Convdir/depotmap";
$Client   = "$Convdir/p4";
$DBmeta   = "$P4ROOT/dbmeta";
$Checkpoint = "checkpoint";

$LOGNOTE = 1;

if (! defined($P4PORT))
  { print "$Myname: no P4PORT in \"$Convdir/config\".\n"; exit 1; }

($P4HOST = $P4PORT) =~ s/:.*//;
($P4PORTNUM = $P4PORT) =~ s/^.*://;

$P4ADMINUSER = "p4";

# These defaults can be overriden in the config file
#

if ($Change == 1)
  {
    # Remove any revmap, rrevmap files...
    #  
    if (&s("/bin/rm -f $Revmap.db $Revmap.dir $Revmap.pag $Rrevmap.db $Rrevmap.dir $Rrevmap.pag"))
      { die "/bin/rm -f $Revmap.db ..."; }
    if (&s("/bin/rm -f $Depotmap.db $Depotmap.dir $Depotmap.pag"))
      { die "/bin/rm -f $Depotmap.db ..."; }
    if (&s("/bin/rm -rf $P4ROOT && mkdir -p $P4ROOT"))
      { die "/bin/rm /bin/rm -rf $P4ROOT && mkdir -p $P4ROOT"; }
  }

$CVS_MODPATH = $CVS_MODULE;

chdir $CVS_MODPATH || die "$Myname: can't chdir \"$CVS_MODPATH\": $!";
$CVS_MODPATH = `/bin/pwd`; chop $CVS_MODPATH;
chdir $Here || die "$Myname: can't chdir \"$Here\": $!";

chdir $P4ROOT || die "$Myname: can't chdir \"$P4ROOT\": $!";
$P4ROOT = `/bin/pwd`; chop $P4ROOT;
if (&s("/bin/mkdir -p $P4ROOT/depot"))
  { die "/bin/mkdir -p $P4ROOT/depot"; }

if (($Copy || $COPYIMPORT) && &s("/bin/cp -rp $CVS_MODPATH $P4ROOT/depot/IMPORT"))
  {
    print "$Myname \"/bin/cp -rp $CVS_MODPATH $P4ROOT/depot/IMPORT\" failed.\n";
    exit 1;
  }
elsif (&s("/bin/ln -s $CVS_MODPATH $P4ROOT/depot/IMPORT"))
  {
    print "$Myname \"/bin/ln -s $CVS_MODPATH $P4ROOT/depot/IMPORT\" failed.\n";
    exit 1;
  }

$IMPORT = "depot/IMPORT";
chdir $Here || die "$Myname: can't chdir \"$Here\": $!";

#  Open the changes file (this is the genchanges output file)
#
if (! open(CHGS, "<$Changes"))
  { print "$Myname: can't open \"$Changes\": $!\n"; exit 1; }

#  Open the db metadata (journal format) file we will write
#
if (! open(DBMETA, ">$DBmeta"))
  { print "$Myname: can't open \"$DBmeta\": $!\n"; exit 1; }

#  Open the REVMAP database...
#
if (! dbmopen(REVMAP, $Revmap, 0666))
  { print "$Myname: can't dbmopen \"$Revmap\": $!\n"; exit 1; }

#  Open the RREVMAP database...
#
if (! dbmopen(RREVMAP, $Rrevmap, 0666))
  { print "$Myname: can't dbmopen \"$Rrevmap\": $!\n"; exit 1; }

#  Open the DEPOTMAP database...
#
if (! dbmopen(DEPOTMAP, $Depotmap, 0666))
  { print "$Myname: can't dbmopen \"$Depotmap\": $!\n"; exit 1; }

#  Open the log messages database
#
if (! dbmopen(MSGS, $Logmsgs, 0444))
  { print "$Myname: can't dbmopen \"$Logmsgs\": $!\n"; exit 1; }

$gather_change_num = $do_change_num = 0;
while (<CHGS>)
  {
    if (/^# ([0-9]+)$/)
      {
        $gather_change_num = $1;
        if ($do_change_num)
          {
            &dochange(@change);
            $do_change_num = 0;
          }

        #  Clear the change
        #
        undef @change;
      }
    elsif ($gather_change_num)
      { push(@change, $_); $do_change_num = $gather_change_num; }
  }
if ($do_change_num) { &dochange(@change); }

$Change--;
print DBMETA "\@pv\@ 0 \@db.counters\@ \@change\@ $Change\n";

#  We've written an upgrade-level 3 compliant database.
#
print DBMETA "\@pv\@ 0 \@db.counters\@ \@upgrade\@ 3\n";

close DBMETA;
dbmclose MSGS;
close CHGS;
dbmclose REVMAP;
dbmclose RREVMAP;
dbmclose DEPOTMAP;

$DBmeta =~ s%^.*/%%;

if (&s("cd $P4ROOT && $P4D -jr $DBmeta"))
  { print "$Myname: \"$P4D -jr $DBmeta\" failed.\n"; exit 1; }

if ($p4d_y > 2002 || $p4d_r > 1)
  {
    # Then we could need a database upgrade. Let's go for it...
    #
    if (&s("cd $P4ROOT && $P4D -xu"))
      { print "$Myname: \"$P4D -xu\" failed.\n"; exit 1; }
  }

if (&s("cd $P4ROOT && rm -f $Checkpoint && $P4D -jd $Checkpoint"))
  { print "$Myname: \"$P4D -jd $Checkpoint\" failed.\n"; exit 1; }

exit 0;

# Change User Description Committed
#8 1744 Richard Geiger Changes for 2.0b6:

- handle Attic files correctly - this required a change from the old
  version (and required touching genmetadata), since we now use the
  old RCS archive tree in place (or a copy thereof).

- dolabels now closes the labels journal file explicitly. Previously,
  the subsequent "p4d -jr" could see premature eof to due buffered
  data, and the last bunch of labels in the dblbls file would not
  be converted.

- fix a bug that broke conversion of files that had been deleted and
  then re-added in CVS; upon re-adding the file, it would be given
  revision #1 agian, instead of the next unused revision number.

- added a couple of test cases for these.

Many thanks to Fan Zhang of Numeritech for helping to wring out
these problems!
#7 1732 Richard Geiger cruft removed only; no functinoal change.
#6 1729 Richard Geiger Changes for 2.0b5.
#5 1726 Richard Geiger Write upgrade counter; also, insure we have 2002.1 or better,
and run p4d -xu to upgrade if later than 2002.1.
#4 1660 Richard Geiger dochanges now sets the change counter properly.
#3 1655 Richard Geiger Changes for 2.0b2
#2 1650 Richard Geiger 2.0b1 changes.
#1 1636 Richard Geiger Branch for working on a direct-metadata generation verison of cvs2p4
//guest/richard_geiger/utils/cvs2p4/bin/dochanges
#13 1407 Richard Geiger === Release 1.3.2

- Reduce the memory footprint of bin/genmetadata. Previously, it was
  holding and sorting a complete copy of the metadata file "in-core"
  (as well as a copy of all of the RCS revision tags data!). This adds
  up quick, and some users saw genmetadata gobbling memory voraciously
  (and in some cases being running out, causing thrashing and/or process
  termination by the OS).

  genmetadata now keeps the metadata in a temp file, (sorting it in
  primary-key-sized chunks), and the revision tag information in a
  db-backed hash.

- Fix the label handling so that _all_ perforce revisions based on the
  labeled cvs revision are included in the generated
  labels. Previously, one of the N "correct" Perforce revisions were
  being tagged (effectively, at random). This stems from the fact that
  lazy copying and branching are explicit in Perforce, but implicit in
  CVS. I.e., the "#1" revision in a new Perforce branch _appears_ to
  be a separate entity (identical to the revision from which it was
  branched. This means that to use the converted labels, it will be up
  to _you_ to remember what labels go with what branches: but that's
  the way it is in CVS, too.

- A minor change in revmap to have a meaningful usage message, and
  properly handle the new rrevmap format.

- dochanges correctly deletes revmap database files for either
  *.db or *.pag/*.dat style databases.
#12 1185 Richard Geiger Changes for 1.3
(Labels!)
#11 1172 Richard Geiger Complete the toleracne of change renumbering.
#10 1150 Richard Geiger Allow messages about change renumbering, so cvs2p4 can be used
to import to an existing (nonvirginal!) server. Note that I
*don't* claim this works completely now, but from my
experience at Orca a year ago, this was the only bugaboo that
bit. Note also that it's still the user's obligation to insure
that there are no pathname overlaps with files that already
exist. *That* is guarenteed
       not to work!
#9 791 Richard Geiger Update for a new release; my change-of-venue noted;
desensitized to conflicting P4CONFIG.
#8 421 Richard Geiger Fix to the fix by Thomas Quinot.
#7 416 Richard Geiger Pull in Thomas Quinot <[email protected]>'s UTC bugfix, for 1.2.12.
#6 250 Richard Geiger Changes to allow coping with shell metacharacters (' ' & '$', at least)
in file names.
#5 249 Richard Geiger Changes in preparation for supporting spaces in filenames.
(In fact, this may work as of this change, but is not yet tested.)
Also, add "runtest -gengood" to allow easier generatino of new *.good
files. (It just doesn't quick on a miscompare!).
#4 240 Richard Geiger Version 1.2.5, to account for post-1999 RCS behavior.
(Courtesy of David Simon, Goldman Sachs)
#3 228 Richard Geiger Changes for 1.2.4 - recognize alternative "p4 files" message
for files not present in the depot.
#2 179 Richard Geiger CHanges for 1.2.3
#1 130 Richard Geiger CVS-to-Perforce converter.
This is release 1.2.2
(first submit to the Perforce Public Depot)