#!/usr/bin/perl -w # # Visual SourceSafe to Perforce converter, top level wrapper (calls all other scripts) # # Copyright 1998 Perforce Software. All rights reserved. # Written by James Strickland, April 1998 # Maintained by Robert Cowham, since 2000 # # $Id: //guest/perforce_software/utils/vsstop4/main/convert.pl#12 $ # require 5.0; use strict; use lib '.'; $| = 1; # don't buffer output use convert; convert::log("START=======================================\n"); convert::log("Starting run. " . scalar(localtime()) . "\n"); # Check that P4 Module is installed eval{require P4; import P4;}; if ($@) { print "\nP4Perl module (P4) is required for the converter to run. Install P4Perl from http://public.perforce.com//guest/tony_smith/perforce/API/Perl/index.html. Use the Current version (for Perl 5.6 or 5.8 as appropriate), and just double-click on Windows installer and run it (no real need to download and save). E.g.: http://public.perforce.com/guest/tony_smith/perforce/API/Perl/current/p4perl56-setup.exe or http://public.perforce.com/guest/tony_smith/perforce/API/Perl/current/p4perl58-setup.exe \n"; exit(1); } # Check for parameter to avoid asking questions my $confirm = shift(@ARGV); $confirm = "" if (!defined($confirm)); if (!defined($ENV{'SSDIR'})) { print "The environment variable SSDIR must be defined!\n"; exit(1); } my $p4 = new P4; $p4->SetPort($convert::p4port); $p4->SetClient($convert::p4client); $p4->SetUser($convert::p4user); $p4->Connect() or die( "Failed to connect to Perforce Server: $convert::p4port $!\n" ); my $p4form = new P4; $p4form->SetPort($convert::p4port); $p4form->SetClient($convert::p4client); $p4form->SetUser($convert::p4user); $p4form->ParseForms(); $p4form->Connect() or die( "Failed to connect to Perforce Server: $convert::p4port $!\n" ); # check that p4 is operational, warn if version does not support -f print "Running p4 info.\n"; my $p4info = p4run($p4, "info"); # note: p4 info prints errors to stderr, so we deduce an error from the lack # of output saying anything about the server if( $p4info !~ m@server@si) { print "\np4 info returned an error which must be fixed before proceeding. Check the installation section of the Perforce manual. Most likely you haven't started a Perforce server or you haven't set P4PORT to point to the server. You can obtain Perforce documentation from http://www.perforce.com\n\n"; print "Here's what p4 info returned:\n$p4info" if($p4info); exit(1); } if( $p4info =~ m@\nServer version:\s+[^\s]+/([0-9]+) @s) { my $change_number = $1; my $magic_number = 4761; # first release of 97.3 if( $change_number < $magic_number ) { print "Detected Perforce server version with change number $change_number. The VSS converter requires a 97.3 or later server. You can download Perforce from http://www.perforce.com/\n"; exit(2); } } else { # Server version line not recognized print "The Perforce server version was not detected - either you have a really old version (you can get the latest version from http://www.perforce.com) or the format of the output of p4 info has changed and no one updated this script to match (in which case, we'd appreciate it if you let us know - send email to support\@perforce.com). The VSS converter requires a 97.3 or later server. You can download Perforce from http://www.perforce.com/ "; if ($confirm !~ /\-[yY]/) { print "Do you wish to proceed with your existing server? (y/n) "; exit(3) if( !~ /y/); } } # check that the depot is empty print "Checking that the depot is empty.\n"; if(p4run($p4, "changes -m 1", 1) || p4run($p4, "labels", 1)) { my $port = $p4info; $port =~ s@.*\nServer address:\s*(\S+).*@$1@s; print "The Perforce depot stored by the server at '$port' is not empty! Running this import process will import changes with earlier timestamps than existing changes in the depot. Be careful!! "; if ($confirm !~ /-[yY]/) { print "Are you sure you want to proceed? "; exit(4) if( !~ /y/); } } # Check if we are being asked to ignore changes - dangerous!! if($convert::start_time != 0) { print "************* WARNING You have specified a start_time before which to ignore changelists. This is potentially dangerous because if you have not correctly specified the time stamp, you will get duplicate changelists! "; print "Are you sure you want to proceed? "; exit(4) if( !~ /y/); } # Check that the user has superuser or admin protections if(!p4run($p4, "protect -o", 0)) { print "You do not have superuser permissions for this Perforce repository. The converter updates the date and time on imported changelists which requires superuser or administrator permissions. "; print "Are you sure you want to proceed? "; exit(4) if( !~ /y/); } # Timestamp print_status("Conversion started " . scalar(localtime()) . "\n"); # set up user name and client $ENV{P4PORT} = $convert::p4port; $ENV{P4USER} = $convert::p4user; $ENV{P4CLIENT} = $convert::p4client; print_status("\nUsing port/client/user '$ENV{P4PORT}/$ENV{P4CLIENT}/$ENV{P4USER}'.\n\n"); my $client_view = "//$convert::depot/$convert::depot_root... //$ENV{P4CLIENT}/$convert::depot_root...\n"; print_status("...creating/updating client $ENV{P4CLIENT} with:\n"); print_status(" root $convert::client_root.\n"); print_status(" view $client_view\n"); # Update the root and view my $form = $p4form->FetchClient($ENV{P4CLIENT}); my @view; push @view, $client_view; $form->{"Root"} = $convert::client_root; $form->{'View'} = \@view; my @result = $p4form->SaveClient($form); convert::log("Client update:\n".join("\n", @result)); print_p4errors($p4form, "Updating client ".$ENV{P4CLIENT}, 1); # check no opened files... print_status("Checking for no opened files.\n"); if(p4run($p4, "opened", 1)) { print "************************** ERROR You have a variety of opened files in the client workspace - conversion cannot proceed. Please revert them (in workspace $convert::p4client) and try again: "; print p4run($p4, "opened"); exit(4); } if ($convert::bypass_metadata) { # If a bypass is requested, verify that the files are there. $convert::bypass_metadata = -f "$convert::metadata_dir/files" && -f "$convert::metadata_dir/labels_summary" && -f "$convert::metadata_dir/changes"; } if ($convert::bypass_metadata) { print "BYPASSING the re-creation of the metadata/ files.\n"; } else { print_status("Extracting metadata... " . scalar(localtime()) . "\n"); print_status("...from all VSS projects at and below $convert::root\n"); print_status("...in VSS Repository $ENV{'SSDIR'}\n\n"); runcmd("perl readhist.pl"); # Sort the metadata print_status("Sorting the metadata. " . scalar(localtime()) . "\n"); runcmd("perl sortmeta.pl"); # Improve the metadata - group changes, etc. print_status("Improving the metadata. " . scalar(localtime()) . "\n"); runcmd("perl improve.pl"); } # And now, what you've all been waiting for.. print_status("Creating the Perforce depot. " . scalar(localtime()) . "\n"); runcmd("perl mkdepot.pl"); # Some post-processing print_status("Sorting the mapping file. " . scalar(localtime()) . "\n"); runcmd("perl sortmap.pl"); # Verification step if ($convert::perform_verify) { print_status("\nVerifying the result. " . scalar(localtime()) . "\n"); runcmd("perl verify.pl"); } # Timestamp print_status("Conversion finished " . scalar(localtime()) . "\n"); sub runcmd { my $cmd = shift; my $result = system($cmd); if ($result) { die "***** Failed to run command: $cmd\n"; } } sub p4run { my ($p4, $cmd, $errorexit) = @_; $errorexit = 0 if (!defined($errorexit)); my @result = $p4->Run(split(' ', $cmd)); my $result = join("\n", @result); print_p4errors($p4, $cmd, $errorexit); return $result; } sub print_p4errors { my ($p4, $msg, $errorexit) = @_; $errorexit = 0 if (!defined($errorexit)); if ($p4->ErrorCount()) { print "**p4errors - $msg:\n"; convert::log("**p4errors - $msg:\n"); foreach my $e ($p4->Errors()){ if (scalar(@$e)) { convert::log("@$e\n"); print "@$e\n" if $errorexit; } else { convert::log("$e\n"); print "$e\n" if $errorexit; } } exit(4) if $errorexit; } } sub get_p4errors { my @result; if ($p4->ErrorCount()) { foreach my $e ($p4->Errors()){ if (scalar(@$e)) { push @result, "@$e\n"; } else { push @result, "$e\n"; } } } return join("\n", @result); } sub print_status { my $msg = shift; print $msg; convert::log($msg); } #eof