#!/usr/bin/perl -w # # VSS to Perforce converter, phase III: construct Perforce depot # # Copyright 1998 Perforce Software. All rights reserved. # Written by James Strickland, April 1998 # # This script uses the metadata produced by earlier phases to direct a loop # which extracts VSS revisions and performs the required Perforce commands # to construct a Perforce depot corresponding to the (improved) VSS data. # # RHGC - Modifed to use new depot and depot_root as specified in config. require 5.0; use strict; use integer; use lib '.'; use convert; use Change; # open all our input files my $msg="can't open for read"; open(FILES, "<$convert::metadata_dir/files") or die $msg; open(LABELS, "<$convert::metadata_dir/labels") or die $msg; open(CHANGES, "<$convert::metadata_dir/changes") or die $msg; open(MAPPING, ">$convert::metadata_dir/mapping.ns") or die "can't open for write: $!"; # variables to be initialized with metadata read from files my (%file_type, # maps archive -> file type # e.g. "$/foo" -> "text" %labels, # maps "revision archive" -> list of labels # e.g. "1 $/foo" -> "itworks","bobsyouruncle" %filesinlabel, # maps label name -> list of "file#rev" %added, # maps depot file -> true/false # e.g. "//depot/foo" -> 1 ); # initialize %file_type while() { chomp; my ($file_type,$file) = split(/ /,$_,2); $file_type{$file} = $file_type; } close(FILES); # initialize %label and run p4 label once for each label which is not a # "delete" label my %created; while() { chomp; my ($revision,$label,$timestamp,$file) = split(/ /,$_,4); my $index = "$revision $file"; $labels{$index} = defined($labels{$index}) ? [ @{$labels{$index}} , $label ] : [ $label ]; my $comment = ''; $comment .= while ($comment !~ /\*{10}\n/); $comment =~ s/\*{10}\n$//; $comment = "vsstop4 label" if ($comment =~ /^\s*$/); # Set default comment. next if($created{$label}); my $form=convert::p4run(" label -o $label"); # label names cannot contain spaces $comment =~ s@\n@\n\t@gs; my $label_view = "//$convert::depot/$convert::depot_root/..."; # Update the Description field in the label. $form =~ s@(\nDescription:\s*)\n\s+\S[^\n]*\n@$1\n\t$comment@s; # RHGC - Create a more specific view for the label - not just all depots which is the default. $form =~ s@(\nView:\s*)\n\s+.*\n$@$1\n\t$label_view@s; # adjust the update time of the label my (@tm,$date); @tm=localtime($timestamp); $date=sprintf("%4d/%02d/%02d %02d:%02d:%02d",(($tm[5]>=70) ? $tm[5]+1900 : $tm[5]+2000), $tm[4]+1,$tm[3],$tm[2],$tm[1],$tm[0]); if ($form =~ /(\nUpdate:\s*)\d.*$/) { $form =~ s@(\nUpdate:\s*)\d.*$@$1$date@s; } else { $form =~ s@(\nLabel:.*?\n)@$1\nUpdate: $date\n@s; } convert::p4run(" label -i",$form); $created{$label}=1; } close(LABELS); undef %created; # we're finished with this hash, so free up the space # print timestamp print "Depot creation started " . scalar(localtime()) . "\n"; # For each change, # - retrieve revisions from VSS using 'get' # - mark files as added or edited with 'p4 add' or 'p4 edit', # followed by 'p4 submit' # - update list of file#rev associated with any pertinent labels my $start_time = $convert::start_time; my ($c,$op); CHG: while( $c = get Change(\*CHANGES) ) { my ($change_number,@checkins); # Ignore change if a start_time is specified if ($start_time > $c->timestamp) { print "Ignoring changelist with timestamp: ". $c->datetime ."\n"; next CHG; } my $index; foreach $index (@{$c->changelist}) { my $p4rev; my ($revision,$vss_file) = split(/ /,$index,2); my ($client_rel_dir,$client_file) = convert::p4dir_and_file( $vss_file); my $client_dir = convert::join_paths( $convert::client_root, $client_rel_dir ); # create all needed directories on the path convert::emkdir($client_dir); # for p4 - could use $client_file, but I'd rather make sure we use # the same string that's written out to the mapping file my $depot_file = convert::join_paths("//$convert::depot", $client_rel_dir, $client_file ); # get the file from VSS convert::get_vss_file($vss_file,($file_type{$vss_file} eq "tempobj") ? "" : $revision,$client_dir,$client_file); # see if the file is indeed there now if (-f "${client_dir}/${client_file}") { # schedule p4 add or edit operation # depending on whether file has already been added push(@checkins, [ $vss_file,$revision,$depot_file ] ); my $operation; if($added{$depot_file}) { convert::p4run(" edit \"$depot_file\"") =~ /#(\d+) - opened for edit/ or die "p4 edit $depot_file failed"; $p4rev=$1 +1; } else { # RHGC - because of restartability, add extra check if (convert::p4run(" -s fstat \"$depot_file\"") !~ /- no such file\(s\)/) { convert::p4run(" edit \"$depot_file\"") =~ /#(\d+) - opened for edit/ or die "p4 edit $depot_file failed"; $added{$depot_file}=1; $p4rev=$1 +1; } else { my $addcmd = " add -t $file_type{$vss_file} \"$depot_file\""; if ($convert::typemap_regexp) { # don't specify type when file is handled with p4 typemap if ($depot_file =~ /$convert::typemap_regexp/) { $addcmd = " add \"$depot_file\""; } else { print "file $depot_file not matched by typemap.\n"; } } convert::p4run($addcmd) =~ /opened for add/ or die "p4 add $depot_file failed"; $added{$depot_file}=1; $p4rev=1; } } # check if this revision is labelled if(exists($labels{$index})) { for (@{$labels{$index}}) { $filesinlabel{$_} = defined($filesinlabel{$_}) ? [ @{$filesinlabel{$_}} , "$depot_file#$p4rev" ] : [ "$depot_file#$p4rev" ]; } } } else { # the file isn't there - the ss get failed if ($convert::skip_ss_get_errors) { print STDERR "ERROR: VSS file not found: ${vss_file}#${revision}\n"; } else { die "get_vss_file() revision $revision to $client_dir/$client_file failed"; } } } # submit the change, and write out the association between VSS # archive and revision number and Perforce file and change number $change_number = $c->submit; # submit the change my $checkin; foreach $checkin (@checkins) { my ($vss_file,$r,$depot_filename) = @$checkin; # write change number#filename to avoid confusion with filename#revision print MAPPING "$r#$change_number#$depot_filename#$vss_file\n"; # NOTE: $vss_file has to go last since it can contain # characters } } # now do the labelling print "\nLabelling started " . scalar(localtime()) . "\n"; for (keys(%filesinlabel)) { convert::p4run(" -x - labelsync -l $_",join("\n",@{$filesinlabel{$_}})."\n"); }