# ============================= # pvcs2svn Tool # ============================= # Author: Thomas Wolkenstein (thomas@wolkenstein.com) # Company: AMS Engineering STICHT GesmbH, A-4232 Hagenberg i. M. # Version: 1.0 # Date: 24.09.2004 # ============================= # Description: # -) This script copies a PVCS repository into an Subversion repository while keeping all pvcs revisions # including the correct check in date, author and comment. For every pvcs Versionlabel the script # creates a Subversin tag. # -) directory tree: # - # - branches # - tags # - trunk # - # - # # Notes: # -) Use at your own risk. # -) This script was designed for use with PVCS Version Manager, Version 6.8.10 # -) The script is dependant on following binaries: pcli, svn # -) The Workpath setting for the files in PVCS is ignored, the workpath in the command line is used instead # -) The Subversion Repository must be enabled to accept revision property changes. # Create an executable file named "pre-revprop-change" in the "hooks" directory # -) Befor running the script you have tor create the target svn repository with "svnadmin create" # No further changes should be made. The script will create the /trunk /tags /brunches directories # -) It doesn't matter where you run the script, but absolut pathes are recommended use strict; if($#ARGV != 6) { print "usage: perl pvcs2svn.pl \n\n"; print " The User of the PVCS Repository. SuperUser rights are needed.\n"; print " Use syntax : to specify a password.\n"; print " The absolut path to the pvcs repository. (like in the GUI)\n"; print " No backslash at the end.\n"; print " The PVCS Subproject. Use \"/\" to convert everything.\n"; print " otherwise specify a subproject. Only leading slash.\n"; print " The Subversion user. Write access is mandatory.\n"; print " The Password of the Subversion User.\n"; print " The Url to the Suversion repository.\n"; print " A lokal directory where a working copy is created.\n"; print " The scipt will use this directory to perform all operations.\n"; exit; } my $PVCSUser = $ARGV[0]; my $PVCSProjectPath = $ARGV[1]; my $PVCSProject = $ARGV[2]; my $SVNUser = $ARGV[3]; my $SVNPwd = $ARGV[4]; my $SVNURL = $ARGV[5]; my $SVNWorkPath = $ARGV[6]; my $PVCSvlog = "pvcs2svnvlog.txt"; # Clear File. open(DATEI, ">$PVCSvlog"); close(DATEI); # Generate the pvcs log file, which contains every revision print "\n PVCS VersionLog wird generiert.\n"; system("pcli vlog -z -id$PVCSUser -f$PVCSvlog -pr\"$PVCSProjectPath\" \"$PVCSProject\""); # Read the pvcs log open(DATEI, "<$PVCSvlog") || die "Die Datei $PVCSvlog wurde nicht gefunden oder konnte nicht zum Lesen geöffnet werden."; my @PVCSvlogZeilen = ; close(DATEI); print "\n$#PVCSvlogZeilen Lines read \n\n"; # Parsing PVCS Log my @PVCSCheckIns; my @Verzeichnisse; my @VersionLabels; my $Zustand = 0; my @Erwartet; push (@Erwartet,"^Archive:.+"); push (@Erwartet,"^Workfile:"); push (@Erwartet,"^Version labels:"); push (@Erwartet,"^\\s\\s\\s\""); push (@Erwartet,"Description:"); push (@Erwartet,""); push (@Erwartet,"^-----------------------------------"); push (@Erwartet,"^Rev"); push (@Erwartet,"^Checked in:"); push (@Erwartet,"^Author id:"); push (@Erwartet,""); push (@Erwartet,"^==================================="); my $AktuellesVerzeichnis; my $AktuelleDatei; my @AktuelleVersionLabels; my $AktVerLabIndex=0; my $AktuelleDescription; my @AktuelleRevisions; my $AktRevIndex=0; my $AktuelleRevisionNummer; my $AktuelleRevisionDatum; my $AktuelleRevisionAuthor; my $AktuelleRevisionKommentar = " "; my $Monat; foreach(@PVCSvlogZeilen) { #print "\n$_"; if($Zustand == 0) { #print "Erwartet: $Erwartet[0]\n"; if( $_ =~ /$Erwartet[0]/) { $_ =~ /\\archives\\(.*)\\([\w-\.]+)/; $AktuellesVerzeichnis = $1; # Verzeichnis bestimmen #print "Verzeichnis: $1\n"; my $i; my $VIndex = -1; for($i = 0; $i <= $#Verzeichnisse; $i++) { if($1 eq $Verzeichnisse[$i]) { $VIndex = $i; } } if($VIndex == -1) { push(@Verzeichnisse,$1); $VIndex = $#Verzeichnisse; } $Zustand = 1; #print "Zustand: 1\n"; } } elsif($Zustand == 1) { if($_ =~ /$Erwartet[1]/) { $_ =~ /$Erwartet[1]\s*(\w*\.\w*)/; # Dateiname bestimmen $AktuelleDatei = $1; #print "Datei: $1\n"; $Zustand = 2; #print "Zustand: 2\n"; } } elsif($Zustand == 2) { if($_ =~ /$Erwartet[2]/) { $Zustand = 3; #print "Zustand: 3\n"; } } elsif($Zustand == 3) { if($_ =~ /$Erwartet[3]/) { # Version labels sammeln $_ =~ /"(.*)" = (.*)/; #print "Version Labels: $1 = $2\n"; $AktuelleVersionLabels[$AktVerLabIndex][0] = $1; #Label $AktuelleVersionLabels[$AktVerLabIndex][1] = $2; #Revision $AktVerLabIndex += 1; #print "Zustand: 3\n"; } if($_ =~ /$Erwartet[4]/) { $Zustand = 5; #print "Zustand: 5\n"; } } elsif($Zustand == 5) { if($_ =~ /$Erwartet[6]/) { $Zustand = 7; #print "Zustand: 7\n"; } elsif ($_ =~ /$Erwartet[5]/) { $AktuelleDescription .= $_; # Description bestimmen #print "Zustand: 5\n"; } } elsif($Zustand == 7) { if($_ =~ /$Erwartet[7]/) { $_ =~ /^Rev\s(.*)/; $AktuelleRevisionNummer = $1; # Revisionnummer $Zustand = 8; #print "Zustand: 8\n"; } } elsif($Zustand == 8) { if($_ =~ /$Erwartet[8]/) { $_ =~ /^Checked in:\s\s\s\s\s(\w\w\w)\s(\d\d)\s(\d\d\d\d)\s(\d\d):(\d\d):(\d\d)/; if($1 eq "Jan") { $Monat = "01"; } if($1 eq "Feb") { $Monat = "02"; } if($1 eq "Mar") { $Monat = "03"; } if($1 eq "Apr") { $Monat = "04"; } if($1 eq "May") { $Monat = "05"; } if($1 eq "Jun") { $Monat = "06"; } if($1 eq "Jul") { $Monat = "07"; } if($1 eq "Aug") { $Monat = "08"; } if($1 eq "Sep") { $Monat = "09"; } if($1 eq "Oct") { $Monat = "10"; } if($1 eq "Nov") { $Monat = "11"; } if($1 eq "Dec") { $Monat = "12"; } $AktuelleRevisionDatum = "$3-$Monat-$2T$4:$5:$6.0Z"; # RevisionsDatum $Zustand = 9; #print "Zustand: 9\n"; } } elsif($Zustand == 9) { if($_ =~ /$Erwartet[9]/) { $_ =~ /^Author id: (\w*)/; $AktuelleRevisionAuthor = $1; $Zustand = 10; #print "Zustand: 10\n"; } } elsif($Zustand == 10) { if($_ =~ /$Erwartet[6]/) { $AktuelleRevisions[$AktRevIndex][0] = $AktuelleRevisionNummer; $AktuelleRevisions[$AktRevIndex][1] = $AktuelleRevisionDatum; $AktuelleRevisions[$AktRevIndex][2] = $AktuelleRevisionAuthor; $AktuelleRevisions[$AktRevIndex][3] = $AktuelleRevisionKommentar; $AktRevIndex += 1; $AktuelleRevisionNummer = ""; $AktuelleRevisionDatum = ""; $AktuelleRevisionAuthor= ""; $AktuelleRevisionKommentar= ""; $Zustand = 7; #print "Zustand: 7\n"; } elsif($_ =~ /$Erwartet[11]/) { $AktuelleRevisions[$AktRevIndex][0] = $AktuelleRevisionNummer; $AktuelleRevisions[$AktRevIndex][1] = $AktuelleRevisionDatum; $AktuelleRevisions[$AktRevIndex][2] = $AktuelleRevisionAuthor; $AktuelleRevisions[$AktRevIndex][3] = $AktuelleRevisionKommentar; $AktuelleRevisionNummer = ""; $AktuelleRevisionDatum = ""; $AktuelleRevisionAuthor= ""; $AktuelleRevisionKommentar= ""; for(my $i = 0; $i <= $#AktuelleVersionLabels; $i++) { #print "Im VersionLabel die Revision durch das Datum ersetzen\n"; #print "Revisionen: $#AktuelleRevisions\n"; for(my $j = 0; $j <= $#AktuelleRevisions; $j++) { #print "$AktuelleVersionLabels[$i][0] = $AktuelleVersionLabels[$i][1]\n"; if($AktuelleRevisions[$j][0] eq $AktuelleVersionLabels[$i][1]) { $AktuelleVersionLabels[$i][1] = $AktuelleRevisions[$j][1]; } } my $LIndex = -1; #print "Ueberpruefen, ob das Versionlabel schon existiert.\n"; for(my $j = 0; $j <= $#VersionLabels; $j++) { if($AktuelleVersionLabels[$i][0] eq $VersionLabels[$j][0]) { $LIndex = $j; } } #print "Neues VersionLabel wird hinzugefügt.\n"; if($LIndex == -1) { $LIndex = $#VersionLabels + 1; $VersionLabels[$LIndex][0] = $AktuelleVersionLabels[$i][0]; $VersionLabels[$LIndex][1] = $AktuelleVersionLabels[$i][1]; } #print "Datum des VersionLabels aktualisieren.\n"; if($VersionLabels[$LIndex][1] lt $AktuelleVersionLabels[$i][1]) { $VersionLabels[$LIndex][1] = $AktuelleVersionLabels[$i][1]; } } for(my $i = 0; $i <= $#AktuelleRevisions; $i++) { my $j = $#PVCSCheckIns + 1; $PVCSCheckIns[$j][0] = $AktuelleRevisions[$i][0]; $PVCSCheckIns[$j][1] = $AktuelleRevisions[$i][1]; $PVCSCheckIns[$j][2] = $AktuelleRevisions[$i][2]; $PVCSCheckIns[$j][3] = $AktuelleRevisions[$i][3]; if(!($PVCSCheckIns[$j][3] =~ /\w/)) { $PVCSCheckIns[$j][3] = "Kein Kommentar"; } $PVCSCheckIns[$j][4] = $AktuelleDatei; $PVCSCheckIns[$j][5] = $AktuellesVerzeichnis; $PVCSCheckIns[$j][6] = $AktuelleDescription; #print "$PVCSCheckIns[$j][0],$PVCSCheckIns[$j][1],$PVCSCheckIns[$j][2],$PVCSCheckIns[$j][3],$PVCSCheckIns[$j][4],$PVCSCheckIns[$j][5],$PVCSCheckIns[$j][6]\n"; } $AktuelleDatei = ""; $AktuellesVerzeichnis = ""; $AktuelleDescription = ""; @AktuelleVersionLabels = (); @AktuelleRevisions = (); $AktVerLabIndex = 0; $AktRevIndex = 0; $Zustand = 0; #print "Zustand: 0\n"; } elsif($_ =~ /$Erwartet[10]/) { $AktuelleRevisionKommentar .= $_; $Zustand = 10; #print "Zustand: 10\n"; } } } print "PVCS Repository\n"; print "Total Revisions: $#PVCSCheckIns\n"; print "VersionLabels : $#VersionLabels\n\n"; my @SortierteVersionLabels = sort(VersionLabelSort @VersionLabels); my @SortiertePVCSCheckIns = sort (PVCSCheckInSort @PVCSCheckIns); my @SortierteVerzeichnisse= sort(@Verzeichnisse); sub VersionLabelSort { if(@{$a}[1] lt @{$b}[1]) { return -1; } elsif (@{$a}[1] eq @{$b}[1]) { return 0; } else { return 1; } } sub PVCSCheckInSort { if(@{$a}[1] lt @{$b}[1]) { return -1; } elsif (@{$a}[1] eq @{$b}[1]) { return 0; } else { return 1; } } for(my $i = 0; $i <= $#SortierteVersionLabels ; $i++) { print "VersionLabel: $SortierteVersionLabels[$i][0] am $SortierteVersionLabels[$i][1]\n"; } #for(my $i = 0; $i <= $#SortiertePVCSCheckIns ; $i++) { # print "Datei: $SortiertePVCSCheckIns[$i][4]\n"; # print "Revision: $SortiertePVCSCheckIns[$i][0]\n"; # print "Datum: $SortiertePVCSCheckIns[$i][1]\n"; # print "Author: $SortiertePVCSCheckIns[$i][2]\n"; # print "Kommentar: $SortiertePVCSCheckIns[$i][3]\n"; # print "Verzeichnis: $SortiertePVCSCheckIns[$i][5]\n"; # print "Description: $SortiertePVCSCheckIns[$i][6]\n"; #} #for(my $i = 0; $i <= $#SortierteVerzeichnisse ; $i++) { # print "Verzeichnisse: $SortierteVerzeichnisse[$i]\n"; #} my $LabelIndex = 0; my $SVNprop = "pvcs2svnprop.txt"; my $SVNm = "pvcs2svnm.txt"; my $SVNDiffLog = "pvcs2svndifflog.txt"; my $SVNCommitLog = "pvcs2svncommitlog.txt"; my $PVCSGetLog = "pvcs2svngetlog.txt"; open(DATEI, ">$SVNCommitLog"); close(DATEI); open(DATEI, ">$PVCSGetLog"); close(DATEI); # Subversion Verzeichnisstruktur aufbauen: system("mkdir $SVNWorkPath\\branches"); system("mkdir $SVNWorkPath\\tags"); system("mkdir $SVNWorkPath\\trunk"); for(my $i=0; $i <= $#SortierteVerzeichnisse ; $i++) { system("mkdir $SVNWorkPath\\trunk\\$SortierteVerzeichnisse[$i]"); } # In Repository importieren #print("svn import -m\"Verzeichnisstruktur\" $SVNWorkPath $SVNURL"); system("svn import --username $SVNUser --password $SVNPwd -m\"Verzeichnisstruktur\" $SVNWorkPath $SVNURL"); system("svn propset svn:date --username $SVNUser --password $SVNPwd --revprop -r HEAD $SortiertePVCSCheckIns[0][1] $SVNURL/trunk"); # Lokale Verzeichnisstruktur löschen system("rmdir /s /q $SVNWorkPath\\branches"); system("rmdir /s /q $SVNWorkPath\\tags"); #print("rmdir /s /q $SVNWorkPath\\trunk"); system("rmdir /s /q $SVNWorkPath\\trunk"); # Subversion Working Copy mit svn checkout initialisieren #print("svn checkout $SVNURL/trunk $SVNWorkPath"); system("svn checkout $SVNURL/trunk $SVNWorkPath"); # Dateien aus PVCS holen und in SVN hinzufügen my $SortiertePVCSCheckInsCount = $#SortiertePVCSCheckIns; for(my $i=0; $i <= $SortiertePVCSCheckInsCount ; $i++) { my $Datei = $SortiertePVCSCheckIns[$i][4]; my $Revision = $SortiertePVCSCheckIns[$i][0]; my $Datum = $SortiertePVCSCheckIns[$i][1]; my $Author = $SortiertePVCSCheckIns[$i][2]; my $Kommentar = $SortiertePVCSCheckIns[$i][3]; $Kommentar =~ s/å/ao/cgim; $Kommentar =~ s/ä/ae/cgim; $Kommentar =~ s/ö/oe/cgim; $Kommentar =~ s/ü/ue/cgim; $Kommentar =~ s/Å/Ao/cgim; $Kommentar =~ s/Ä/Ae/cgim; $Kommentar =~ s/Ö/Oe/cgim; $Kommentar =~ s/Ü/Ue/cgim; $Kommentar =~ s/ß/ss/cgim; my $Verzeichnis = $SortiertePVCSCheckIns[$i][5]; my $Description = $SortiertePVCSCheckIns[$i][6]; $Description =~ s/å/ao/cgim; $Description =~ s/ä/ae/cgim; $Description =~ s/ö/oe/cgim; $Description =~ s/ü/ue/cgim; $Description =~ s/Å/Ao/cgim; $Description =~ s/Ä/Ae/cgim; $Description =~ s/Ö/Oe/cgim; $Description =~ s/Ü/Ue/cgim; $Description =~ s/ß/ss/cgim; my $VerzeichnisSlashes = $Verzeichnis; $VerzeichnisSlashes =~ s/\\/\//cgim; print("pcli get -w$Revision -pr\"$PVCSProjectPath\" /$VerzeichnisSlashes/$Datei\n"); system("pcli run -y -ns get -id$PVCSUser -o -a\"$SVNWorkPath\\$Verzeichnis\\$Datei\" -w$Revision -pr\"$PVCSProjectPath\" /$VerzeichnisSlashes/$Datei"); if($Revision eq "1.0") { #Falls die Datei zum ersten mal aus PVCS geholt wird, dann muss sie als Subversion Working File zur Working Copy hinzugefügt werden. #print("svn add \"$SVNWorkPath\\$Verzeichnis\\$Datei\"\n"); system("svn add \"$SVNWorkPath\\$Verzeichnis\\$Datei\""); open(DATEI, ">$SVNprop") || die "Die Datei $SVNprop wurde nicht gefunden oder konnte nicht zum Schreiben geöffnet werden."; print DATEI $Description; close(DATEI); #print("svn propset description -F $SVNprop \"$SVNWorkPath\\$Verzeichnis\\$Datei\"\n"); system("svn propset description -F $SVNprop \"$SVNWorkPath\\$Verzeichnis\\$Datei\""); } # Wenn die nächste PVCS Revision den gleichn Benutzer und das gleiche Kommentar trägt, dann wird nicht sofot in Subversion eingecheckt. if(($SortiertePVCSCheckIns[$i][2] ne $SortiertePVCSCheckIns[($i+1)][2]) || ($SortiertePVCSCheckIns[$i][3] ne $SortiertePVCSCheckIns[($i+1)][3])) { #system("svn diff --old $SVNURL/trunk --new $SVNWorkPath > $SVNDiffLog"); #open(DATEI, "<$SVNDiffLog") || die "Die Datei $SVNDiffLog wurde nicht gefunden oder konnte nicht zum Lesen geöffnet werden."; #my @DiffLogZeilen = ; #close(DATEI); #if($#DiffLogZeilen >= 4) { #print("svn add \"$SVNWorkPath\\$Verzeichnis\"\n"); #system("svn add \"$SVNWorkPath\\$Verzeichnis\""); open(DATEI, ">$SVNm") || die "Die Datei $SVNm wurde nicht gefunden oder konnte nicht zum Schreiben geöffnet werden."; print DATEI $Kommentar; close(DATEI); #print("svn commit --username $SVNUser --password *** -F $SVNm \"$SVNWorkPath\" > $SVNCommitLog\n"); # Commit durchführen system("svn commit --username $SVNUser --password $SVNPwd -F $SVNm \"$SVNWorkPath\" > $SVNCommitLog"); # Den Author und das Datum der letzten Suversion Revision auf die Werte in PVCS ändern. open(DATEI, "<$SVNCommitLog") || die "Die Datei $SVNCommitLog wurde nicht gefunden oder konnte nicht zum Lesen geöffnet werden."; my @SVNCommitLogZeilen = ; close(DATEI); print @SVNCommitLogZeilen; if($#SVNCommitLogZeilen > 1) { print("svn propset svn:author $Author\n"); system("svn propset svn:author --username $SVNUser --password $SVNPwd --revprop -r HEAD $Author $SVNURL/trunk"); print("svn propset svn:date $Datum\n"); system("svn propset svn:date --username $SVNUser --password $SVNPwd --revprop -r HEAD $Datum $SVNURL/trunk"); } if($SortierteVersionLabels[$LabelIndex][1] eq $Datum || $SortierteVersionLabels[$LabelIndex][1] lt $Datum) { print("svn copy --username $SVNUser --password *** $SVNURL/trunk $SVNURL/tags/$SortierteVersionLabels[$LabelIndex][0] -m \"Tagging $SortierteVersionLabels[$LabelIndex][0]\"\n"); system("svn copy --username $SVNUser --password $SVNPwd $SVNURL/trunk $SVNURL/tags/$SortierteVersionLabels[$LabelIndex][0] -m \"Tagging $SortierteVersionLabels[$LabelIndex][0]\""); $LabelIndex += 1; print("svn propset svn:author $Author\n"); system("svn propset svn:author --username $SVNUser --password $SVNPwd --revprop -r HEAD $Author $SVNURL/trunk"); print("svn propset svn:date $Datum\n"); system("svn propset svn:date --username $SVNUser --password $SVNPwd --revprop -r HEAD $Datum $SVNURL/trunk"); } my $Fortschritt = ($i / $#SortiertePVCSCheckIns) * 100; print("-->Progress: $Fortschritt \%\n"); #} } } print "\n\nDone.\n";