|
|
@echo off for %%i in (%0.cmd) do perl -w -x %%~dp$PATH:i%0.cmd %* goto :eof #!perl # line 6 # # FileName: sdbackup.cmd # # Usage = sdbackup [-v] [-d altdir] <backupdir> # # Enumerates all the SD opened files in all depots and copies the # changes out to the specified path. This can be useful simply as # a regular backup of local changes, or as a mechanism for sharing # private changes with another person. # # Example: # sdbackup \\scratch\scratch\jvert\sdbackup # copies all opened files to \\scratch\scratch\jvert\sdbackup\<currentdate> # sdbackup -d newchange \\scratch\scratch\jvert # copies all opened files to \\scratch\scratch\jvert\newchange # # use Getopt::Std; use File::Path; use File::Spec; use File::Copy;
# # initialize globals # $opt_v = 0; $opt_d = 0; %revisionlist = (); %changelist = (); %clientfilelist = ();
$Usage = " USAGE: $0 [-v] [-d altdir] [backupdir] -v Verbose output -d altdir use <altdir> instead of <currentdate> as the root directory backupdir Supplies directory where files will be backed up to. The directory structure created will look like this: <backupdir>\<currentdate> backup.log - list of files and their versions \\nt\.. - directories and files If -n is specified, the directory structure will look like this: <backupdir>\\nt.. - directories and files If not specified, the filenames will just be printed to stdout.\n";
# # Finds the full filenames of all checked out files #
getopts('vd:') or die $Usage; $backupdir = $ARGV[0];
$opt_v and print("backupdir is $backupdir\n");
foreach $line (`sdx opened`) { chomp $line; # # throw away blank lines, depot specifiers, and empty lists # $line =~ /^[\t\s]*$|^------|^File\(s\) not opened/ and next;
# # throw away files that aren't in the default change list. Kind of sleazy, # but it prevents the public libraries from getting in the list # $line =~ /edit change \d/ and next;
# # throw away deleted files # $line =~ /delete default change/ and next;
# # If we hit the summary, we're done # $line =~ /^== Summary/ and last;
$opt_v and print ("line = $line\n");
# # parse the resulting filename # ($depotfilename, $revision, $change) = split(/#| - /,$line); $opt_v and print ("\tfilename: $depotfilename\n\trevision: $revision\n\tchange: $change\n\n");
$depotfilename = lc($depotfilename); $revisionlist{$depotfilename} = $revision; $changelist{$depotfilename} = $change; }
# # Now we have a list of depot names. Translate those into clientnames # by calling sdx where # # note: since the command line can only accept a limited # of files # to run "sdx where" on, we break up the command into multiple # smaller "sdx where" runs. # $s = ""; $r = [keys(%revisionlist)]; $maxArgSize = 200;
foreach $revision (0..$#$r) {
# get the combination of the existing list + the current revision $k = $s." ".$$r[$revision]; # if the list is too long then it's time to process it # if we are at the end of the list, then we need to flush the list if ((length($k) > $maxArgSize) || ($revision == $#$r)) {
# # pass: # 0: do the existing list in $s # 1: do the current revision # $firstPass = 1; while(1) {
# skip first iteration if $s is empty # this implies that the current revision # is > 200 chars and may not work if ($s ne "") { if (length($s) > $maxArgSize) { print "warning: attempting to process long revision: $revision\n"; } foreach $line (`sdx where $s`) { # # throw away blank lines, depot specifiers, "not found" lines, # and lines that start with "-" # $line =~ /^[\t\s]*$|^-------|file\(s\) not in client view|^-/ and next; chomp $line; $opt_v and print("mapping: $line\n"); ($depotfilename, $trash, $clientfilename) = split(/\s/,$line); $depotfilename = lc($depotfilename); $clientfilelist{$depotfilename} = lc($clientfilename); -e $clientfilename or die "file: $clientfilename should exist but doesn't!\n"; } }
if (! $firstPass) { last; } $s = $$r[$revision]; $firstPass = 0;
} $s = ""; } else { $s = $k; } }
# # make sure we have as many client file list entries as revision entries # $temp = [(keys %clientfilelist)]; if ($#$temp != $#$r) { print "error occured while compiling client file list\n"; print $#$temp ." vs. ". $#$r ."\n"; die; }
if ($backupdir) { if ($opt_d) { $backupdir .= "\\$opt_d"; } else { @time = localtime; $backupdir .= sprintf("\\%4d-%02d-%02d.%02d%02d",($time[5]+1900),$time[4]+1,$time[3],$time[2],$time[1]); $opt_v and print $backupdir."\n"; } mkpath($backupdir) unless -d $backupdir; open(LOGFILE, "+> $backupdir\\backup.log") or die "Couldn't open $backupdir\\backup.log: $!\n";
# # Write all the files to backup.log. Format is: # SDfilename #<versionnumber> clientfilename #
foreach $file (sort keys %clientfilelist) {
$clientfile = $clientfilelist{$file};
# # Each client filename is in the form X:<full pathname>\<filename> # Split this up into volume, path, filename components (we don't # care about the volume) # ($trash,$dir,$filename) = File::Spec->splitpath($clientfile);
# # Write this file's data to the logfile # $srcfile = File::Spec->catfile($dir, $filename); print LOGFILE "$file #$revisionlist{$file} $srcfile\n";
# # compute the destination directory and make sure it exists. # $destdir = File::Spec->catdir($backupdir, $dir); -d $destdir || mkpath($destdir) or die "Couldn't create destination directory $destdir: $!\n";
# # compute the full destination path and filename # $destfile = File::Spec->catfile($destdir, $filename); if ($opt_v) { print("copying $clientfile to $destfile\n"); } else { print("$clientfile\n"); } copy($clientfile, $destfile, 0) or die "Couldn't copy $clientfile -> $destfile: $!\n"; } } else { print join("\n", sort values %clientfilelist); }
|