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/jay_han/perforce/utils/cvs2p4/bin/dochanges#1 $
#
# 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;
# NOTE: CVS/RCS just doesn't have the notion of Perforce's "text"
# vs "ktext" types; in RCS, a file is either "text" (in which
# keywords get expanded in one way or another), or "binary", in
# which they are left untouched (RCS's concept of "binary". How's a
# poor conversion program to cope?! For now, we just treat ALL RCS
# "text" files as either "ktext", or ALL as "text". That's controlled
# by the $TEXTTYPE configuration setting
#
# else { $type |= $TEXTTYPE; }
#
# line, below. If you need your conversion to treat _some_ one
# way, and _others_ another way, you'll need to add a mechanism
# for determining which to use, hereabouts. - rmg
#
if ($binary) { $type |= 0x0100; } else { $type |= $TEXTTYPE; }
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 $DEADSTATE)
{
$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 $DEADSTATE)
{
$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 $DEADSTATE && $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 $Revmap.db $Revmap.dir $Revmap.pag"))
{ die "/bin/rm -f $Revmap.db ..."; }
if (&s("/bin/rm -f $Rrevmap $Rrevmap.db $Rrevmap.dir $Rrevmap.pag"))
{ die "/bin/rm -f $Rrevmap.db ..."; }
if (&s("/bin/rm -f $Depotmap $Depotmap.db $Depotmap.dir $Depotmap.pag"))
{ die "/bin/rm -f $Depotmap.db ..."; }
if (&s("/bin/rm -rf $P4ROOT && mkdir -p $P4ROOT"))
{ die "/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\": $!";
$CVS_MODULE_NAME = $CVS_MODULE;
$CVS_MODULE_NAME =~ s@/.*/@@g;
$IMPORT = "$DEPOT/$CVS_MODULE_NAME";
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"; }
#print "IMPORT $IMPORT\n"; die;
if ($Copy || $COPYIMPORT)
{
if (&s("/bin/cp -rp $CVS_MODPATH $P4ROOT/$IMPORT"))
{
print "$Myname \"/bin/cp -rp $CVS_MODPATH $P4ROOT/$IMPORT\" failed.\n";
exit 1;
}
}
elsif (&s("/bin/ln -s $CVS_MODPATH $P4ROOT/$IMPORT"))
{
print "$Myname \"/bin/ln -s $CVS_MODPATH $P4ROOT/$IMPORT\" failed.\n";
exit 1;
}
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; }
use DB_File;
$DBMCLASS="DB_File";
$myhashinfo = new DB_File::HASHINFO;
$myhashinfo->{bsize}=4096;
# Open the REVMAP database...
#
if (! tie(%REVMAP, $DBMCLASS, $Revmap, O_CREAT|O_RDWR, 0666, $myhashinfo))
{ print "$Myname: can't tie \"$Revmap\": $!\n"; exit 1; }
# Open the RREVMAP database...
#
if (! tie(%RREVMAP, $DBMCLASS, $Rrevmap, O_CREAT|O_RDWR, 0666, $myhashinfo))
{ print "$Myname: can't tie \"$Rrevmap\": $!\n"; exit 1; }
# Open the DEPOTMAP database...
#
if (! tie(%REVMAP, $DBMCLASS, $Depotmap, O_CREAT|O_RDWR, 0666, $myhashinfo))
{ print "$Myname: can't tie \"$Depotmap\": $!\n"; exit 1; }
# Open the log messages database
#
if (! tie(%MSGS, $DBMCLASS, $Logmsgs, O_RDONLY, 0444, $myhashinfo))
{ print "$Myname: can't tie \"$Logmsgs\": $!\n"; exit 1; }
#
#
($depotname) = ($P4_DEPOT =~ m/\/\/([^\/]+)\/?/);
if ($depotname ne "depot")
{
print DBMETA "\@pv\@ 0 \@db.depot\@ \@$depotname\@ 0 \@subdir\@ \@$depotname/...\@\n";
$now = time;
print DBMETA "\@pv\@ 2 \@db.domain\@ \@$depotname\@ 100 \@\@ \@\@ \@cvs2p4\@ $now $now".
" 0 0 \@Created by cvs2p4\n@\n";
}
$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;
untie %MSGS;
close CHGS;
untie %REVMAP;
untie %RREVMAP;
untie %DEPOTMAP;
$DBmeta =~ s%^.*/%%;
$P4D = "$P4D -r .";
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 | |
|---|---|---|---|---|---|
| #1 | 2778 | Jay Han | creating guest branch per tutorial http://public.perforce.com/public/tutorial.html | ||
| //guest/perforce_software/utils/cvs2p4/bin/dochanges | |||||
| #13 | 2063 | rmg | Publish 2.3.2 | ||
| #12 | 1989 | Richard Geiger | Public 2.3.1 | ||
| #11 | 1971 | rmg | Publish 2.2 | ||
| #10 | 1786 | rmg | Publish 2.0 | ||
| #9 | 1410 | rmg | Publish 1.3.2 | ||
| #8 | 1187 | Richard Geiger |
1.3. Mainly, support for labels! |
||
| #7 | 796 | Richard Geiger | Release 1.2.16 update | ||
| #6 | 436 | Richard Geiger | Publish 1.2.13 | ||
| #5 | 418 | Richard Geiger | Publish 1.2.12 | ||
| #4 | 256 | james | push cvs2p4 1.2.6 to public area | ||
| #3 | 242 | james |
Pull cvs2p4 into //public so latest version (1.2.5) gets synced onto the Perforce FTP area. Note the cvs2p4-latest.tar symlink - I'll update loadsupp to point to that. |
||
| #2 | 230 | Laura Wingerd |
Pull cvs2p4 into //public so latest version (1.2.4) gets synced onto the Perforce FTP area. |
||
| #1 | 152 | Laura Wingerd | cvs2p4 goes public. | ||
| //guest/richard_geiger/utils/cvs2p4/bin/dochanges | |||||
| #1 | 130 | Richard Geiger |
CVS-to-Perforce converter. This is release 1.2.2 (first submit to the Perforce Public Depot) |
||