# --------------------------------------------------------------------------- # Script: snapbin.pl # # (c) 2000 Microsoft Corporation. All rights reserved. # # Purpose: Snapshot US binaries tree to INTL. # # Version: 1.00 (05/10/2000) : (bensont) Snap the binaries tree # 1.01 (05/10/2000) : (bensont) Create __BldInfo__usa__ file #--------------------------------------------------------------------- # Set Package package SnapBin; # Set the script name $ENV{script_name} = 'snapbin.pl'; # Set version $VERSION = '1.01'; $DEBUG = 0; # Set required perl version require 5.003; # Use section use lib $ENV{ RazzleToolPath }; use lib "$ENV{ RazzleToolPath }\\PostBuildScripts"; use GetParams; use LocalEnvEx; use Logmsg; use strict; no strict 'vars'; use HashText; ($SourceTree, $TargetTree, $SnapList, $machines, $BldInfo, $RoboCopyLog, $BuildNum, %SnapList, @machines, $RoboCopyCmd, $LogRoboCopy)=( "\\\\ntdev\\release\\main\\usa\\\\<_BuildArch><_BuildType>\\bin", "$ENV{_NTTREE}", "$ENV{RazzleToolPath}\\PostBuildScripts\\SnapList.txt", "machines.txt", "$ENV{_NTROOT}\\__BldInfo__usa__", ".Robocopy" ); ($Mirror, $OtherOptions, $Incremental)=("/MIR"); ($ROBOCOPY_ERROR, $ROBOCOPY_SERIOS_ERROR)=(8, 16); # Require section # Main Function sub CmdMain { # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # Begin CmdMain code section # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # Return when you want to exit on error &PrepareRoboCopyCmd || return; print "$RoboCopyCmd\n"; $DEBUG or &ExecuteRoboCopy; { my @stack = ($RoboCopyCmd, $RoboCopyCmd, $SourceTree, $TargetTree); open (F, "$SnapList"); my $startParse = 0; my @blist = (); my $flist = (); my @a = ; foreach (@a){ next if /^;/; if (/^Additional *$/){ print "Robocopy: found additional directories to snap\n"; $startParse = 1; } $startParse=0 if ($startParse && $_ !~ /\S/); if ($startParse && /\S/){ my @alist = split(" ", $_); if ($#alist>=2){ # $f_ = undef; $alist[0] =~ s/(.*)\\([^\\]+)/$1/g and $f_=$2 if $alist[1]=~/F/; push @flist, $f_; push @blist, $alist[0]; $DEBUG and print STDERR scalar(@blist),"\n"; } } } close(F); foreach $cnt (0..$#blist){ $dir = $blist[$cnt]; $file = $flist[$cnt]; $DEBUG and print STDERR "$dir\n"; ($RoboCopyCmd, $RoboCopyLog, $SourceTree, $TargetTree) = @stack; $RoboCopyCmd =~ s/\\\\.*$//g; $RoboCopyLog =~ s|^.*(/LOG\+.*)$|$1.ADDED|g; chomp $RoboCopyLog; $SourceTree .= "\\$dir"; $TargetTree .= "\\$dir"; print "$SourceTree skipped\n" and next unless -d $SourceTree; $RoboCopyCmd = join(" ",$RoboCopyCmd, $SourceTree, $TargetTree, $RoboCopyLog, $file); print "$RoboCopyCmd\n"; $DEBUG or &ExecuteRoboCopy; } ($RoboCopyCmd, $RoboCopyLog, $SourceTree, $TargetTree) = @stack; } &CreateBldInfo; # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ # End CmdMain code section # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ } # PrepareRoboCopyCmd # Purpose : Reference $SourceTree, $TargetTree and file $SnapList to create Robocopy statement # # Input : none # Output : 0 for fails, 1 for success # # Note : The Robocopy statement is stored in $RoboCopyCmd sub PrepareRoboCopyCmd { my ($Excludedirs, $Excludefiles, $exclude, $Cmd)=(); -d $TargetTree or qx("md $TargetTree"); HashText::Read_Text_Hash(0, $SnapList, \%snaplist) if ((defined $SnapList) && ($SnapList ne '-')); # HashText::Read_Text_Hash(1, $machines, \@machines); # If defined in string, evaluate by the order: global variable, environment variable. Report error if can not evaluate $SourceTree =~ s/\<(\w+)\>/(eval "defined \$SnapBin::$1")?eval "\$SnapBin::$1":((exists $ENV{$1})?$ENV{$1}:errmsg("Unable to eval $1 in $SourceTree; verify your params and your razzle."))/ge; $TargetTree =~ s/\<(\w+)\>/(eval "defined \$SnapBin::$1")?eval "\$SnapBin::$1":((exists $ENV{$1})?$ENV{$1}:errmsg("Unable to eval $1 in $TargetTree; verify your params an your razzle."))/ge; # If source tree not exist if (!-e $SourceTree) { errmsg("Source Tree: $SourceTree not found."); } # Any above error should stop (Fail) if ($ENV{errors} > 0) {return 0;} # Parse the hash-hash table snaplist for $exclude (keys %snaplist) { $_ = $snaplist{$exclude}->{Type}; $Excludedirs .= ($exclude=~/\\/)? "$SourceTree\\$exclude ": "$exclude " if /\bD\b/; $Excludefiles .= "$exclude " if (/\bF\b/); } # Check if incremental run. &ChkBabTree($TargetTree, \%snaplist) and exit; # Create RoboCopyLogName as %logfile%.RoboCopy $RoboCopyLog = `uniqfile $ENV{logfile}\.Robocopy`; if (defined $Incremental) { $Mirror = ""; # non-Mirror $OtherOptions = "/XO"; # Exclude Older files } # Prepare the robocopy statement $Cmd = "Robocopy $Mirror /S /E $SourceTree $TargetTree $OtherOptions "; $Cmd .= "/XD $Excludedirs " if ($Excludedirs ne ''); $Cmd .= "/XF $Excludefiles " if ($Excludefiles ne ''); $RoboCopyCmd = $Cmd . " /LOG+:$RoboCopyLog"; # Success return 1; } # Verify that the snaplist.txt file does not contradict with # the actual contents of the %_NTTREE%. # usage: # &ChkBabTree($TargetTreel, \%SnapList) sub ChkBabTree{ my $parent = shift; my $snaplist = shift; my @children = grep {/\S/} split ("\n", qx ("dir /s/b/ad $parent")); $DEBUG and print STDERR "checking existing \%_NTTREE% subdirs: ",scalar (@children), "\n"; return 0 unless @children; print "Robocopy: \"$parent\" is not empty, possibly incremental run\n" if scalar(@children); map {$_ =~ s/\Q$parent\E\\//} @children; my %hashchildren = map {$_=>$_} @children; $childrenkeys = \%hashchildren; map {$childrenkeys->{$_} =~ s/^.*\\//} @children; my @report = (); foreach $subdir (@children){ my $lastdir = $childrenkeys->{$subdir}; push @report, sprintf("%-30s%-30s",$lastdir,$subdir) # and delete ($snaplist->{$lastdir}) if ($snaplist->{$lastdir}->{Type}=~/\bD\b$/) or () ; } foreach $lastdir (keys(%$snaplist)){ next unless $snaplist->{$lastdir}->{Type}=~/\bD\b/ && $lastdir=~/\\/; my @subdir = grep {/\Q$lastdir\E/} @children; push @report, sprintf("%-30s%-30s",$lastdir,$subdir[0]) if scalar (@subdir); } unshift @report, "snaplist.txt %_NTTREE%\n". "-----------------------------------------------------" and print join ("\n", @report ), "\n\n" if scalar(@report); scalar(@report); 0; } # ExecuteRoboCopy # Purpose : Execute Robocopy Command ($RoboCopyCmd) # # Input : none # Output : none # # Note : The serious error or fatal error will be logged. sub ExecuteRoboCopy { my $r; logmsg("RoboCopyCmd : $RoboCopyCmd"); logmsg("SOURCE : $SourceTree"); logmsg("TARGET : $TargetTree"); logmsg("RoboCopy LOGFILE : $RoboCopyLog"); $r = system($RoboCopyCmd) / 256; # Determine the return value if ($r > $ROBOCOPY_SERIOS_ERROR) { errmsg("Serious error while running robocopy."); # Robocopy did not copy all files. This is either a usage error or an error due to insufficient access privileges on the source or destination directions."; } elsif ($r > $ROBOCOPY_ERROR) { errmsg("Robocopy was not able to copy some files or directories."); } } # ParseLogFile # Purpose : Parse the log file which from argument and store to $ENV{logfile} with fully path # # Input : templogfile # Output : none # # Note : The log file will contain all file get copied and extra files removed. sub ParseLogFile { my ($templogfile) = @_; my ($type, $file, %slots, %fails)=(); local *F; # Read temp logfile open(F, $templogfile) || return; for() { next if (/^\s*\-*\s*$/); if (/^ROBOCOPY/) {(%slots,%fails)=(); next;} chomp; # If is error message, add to previous line if (!/^\s/) { if ($#{$fails{$type}} eq '-1') { errmsg($_); } else { ${$fails{$type}}[$#{$fails{$type}}] .= "\n$_"; } next; } logmsg($_) if (defined $LogRoboCopy); # Parse information according the format of robocopy log if (/^\s+(?:New Dir\s+)?(\d+)\s+([\w\:\\]+)$/) { $path = $2; next; } if (/^\s+((?:New File)|(?:Newer)|(?:\*EXTRA File)|(?:Older))\s+(\d+)\s+([\w\.]+)/) { ($type, $file) = ($1, $3); ((/100\%/)||(/\*EXTRA File/))?push(@{$slots{$type}}, $path . $file):push(@{$fails{$type}}, $path . $file); } } close(F); # Separate the log to success and fail logmsg("\n\[Copy Success\]"); for $type (keys %slots) { logmsg(" \[$type\]"); for $file (@{$slots{$type}}) { logmsg("\t$file"); } } if (scalar(%fails) ne 0) { errmsg("\n\[Copy Fails\]"); for $type (keys %fails) { errmsg(" \[$type\]"); for $file (@{$fails{$type}}) { errmsg("\t$file"); } } } # If Robocopy log include into the logfile, remove the robocopy its logfile if (defined $LogRoboCopy) { unlink($templogfile); } else { logmsg("See Robocopy's logfile for more details: $templogfile"); } } # CreateBldInfo # Purpose : Create build number and time stamps to $BldInfo # # Input : none # Output : none # # Note : The file $BldInfo contain one line: ',