Alt-App-makepatch
view release on metacpan or search on metacpan
script/applypatch view on Meta::CPAN
################ Program parameters ################
app_options();
$trace ||= $debug;
$verbose ||= $trace;
################ Presets ################
$patch .= " -s" unless $verbose;
my $tmpfile = IO::File->new_tmpfile;
################ The Process ################
# Validate input and copy to temp file.
copy_input ();
# Change dir if requested.
(defined $dir) && (chdir ($dir) || die ("Cannot change to $dir: $!\n"));
# Verify that we are in the right place.
verify_files ();
# Exit if just checking.
die ("Okay\n") if $test && $check;
exit (0) if $check;
# Pre patch: create directories and files.
pre_patch ();
# Run the patch program.
execute_patch ();
# Post patch: adjust timestamps, remove obsolete files and directories.
post_patch ();
die ("Okay\n") if $test;
exit (0);
################ Subroutines ################
sub copy_input () {
my $lines = 0; # checksum: #lines
my $bytes = 0; # checksum: #bytes
my $sum = 0; # checksum: system V sum
my $all_lines = 0; # overall checksum: #lines
my $all_bytes = 0; # overall checksum: #bytes
my $all_sum = 0; # overall checksum: system V sum
my $patchdata = 0; # saw patch data
my $pos = 0; # start of patch data
my $endkit = 0; # saw end of kit
my $fail = 0; # failed
my $patch_checksum_okay = 0;# checksum for the patch was okay
print STDERR ("Validate input.\n") if $verbose;
@ARGV = "-" if !@ARGV;
for my $file (@ARGV) {
my $argv = new IO::File;
open($argv, $file) or die "Can't open $file: $!";
binmode($argv);
while ( <$argv> ) {
chomp;
if ( /^#### Patch data follows ####/ ) {
print STDERR (": $_\n") if $trace;
$patchdata |= 1; # bit 0 means: start seen
$pos = $tmpfile->getpos;
$lines = $bytes = $sum = 0;
}
elsif ( /^#### End of Patch data ####/ ) {
print STDERR (": $_\n") if $trace;
$patchdata |= 2; # bit 1 means: end seen
}
elsif ( /^#### ApplyPatch data follows ####/ ) {
print STDERR (": $_\n") if $trace;
$applypatch |= 1;
}
elsif ( /^#### End of ApplyPatch data ####/ ) {
print STDERR (": $_\n") if $trace;
$applypatch |= 2;
}
elsif ( /^#### End of Patch kit (\[created: ([^\]]+)\] )?####/ ) {
print STDERR (": $_\n") if $trace;
$endkit = 1;
if ( defined $timestamp && defined $2 && $2 ne $timestamp ) {
warn ("Timestamp mismatch ",
"in \"#### End of Patch kit\" line.\n",
" expecting \"$timestamp\", got \"$2\".\n");
$fail = 1;
}
}
elsif ( /^#### Patch checksum: (\d+) (\d+) (\d+) ####/ ) {
# Checksum for patch data only.
# This _MUST_ preceed the overall checksum.
print STDERR (": $_\n") if $trace;
$patch_checksum_okay = 1;
if ( $1 != $lines ) {
warn ("Linecount error: expecting $1, got $lines.\n");
$fail = 1;
$patch_checksum_okay = 0;
}
if ( $2 != $bytes ) {
warn ("Bytecount error: expecting $2, got $bytes.\n");
$fail = 1;
$patch_checksum_okay = 0;
}
if ( $3 != $sum ) {
warn ("Checksum error: expecting $3, got $sum.\n");
$fail = 1;
$patch_checksum_okay = 0;
}
}
elsif ( /^#### Checksum: (\d+) (\d+) (\d+) ####/ ) {
print STDERR (": $_\n") if $trace;
if ( $patch_checksum_okay ) {
warn ("Warning: Overall linecount mismatch: ".
"expecting $1, got $all_lines.\n")
unless $1 == $all_lines || !$verbose;
warn ("Warning: Overall bytecount mismatch: ".
"expecting $2, got $all_bytes.\n")
unless $2 == $all_bytes || !$verbose;
script/applypatch view on Meta::CPAN
unless ( -d $fn ) {
warn ("Verify error: directory $fn must be removed, ",
"but does not exist.\n");
$fail = 1;
}
}
}
if ( $fail ) {
if ( $force ) {
warn ("WARNING: This does not look like expected source ",
"directory, continuing anyway.\n");
}
else {
warn ("Apparently this is not the expected source directory, ",
"aborting.\n");
die ("Use \"--force\" to override this.\n");
}
}
print STDERR ("Source directory apparently okay.\n") if $verbose;
}
sub pre_patch () {
foreach ( @workq ) {
my ($op, $fn, $size, $mtime, $mode) = @$_;
if ( $op eq 'C' ) {
$mode = oct($mode) & 0777;
$mode = 0777 unless $mode; # sanity
printf STDERR ("+ mkpath $fn 0%o\n", $mode) if $trace;
mkdir ($fn, $mode)
|| die ("Cannot create directory $fn: $!\n");
}
}
foreach ( @workq ) {
my ($op, $fn, $size, $mtime, $mode) = @$_;
if ( $op eq 'c' ) {
#$mode = oct($mode) & 0777;
#$mode = 0666 unless $mode; # sanity
print STDERR ("+ create $fn\n") if $trace;
open (F, '>'.$fn)
|| die ("Cannot create $fn: $!\n");
close (F);
#printf STDERR ("+ chmod 0%o $fn\n", $mode) if $trace;
#chmod ($mode, $fn)
# || warn sprintf ("WARNING: Cannot chmod 0%o $fn: $!\n", $mode);
}
}
}
sub _open_patch () {
my $p = new IO::File;
$p->open("|$patch") || die ("Cannot open pipe to \"$patch\": $!\n");
binmode($p);
return $p
}
sub execute_patch () {
my $p;
print STDERR ("+ $patch\n") if $trace;
if ( $applypatch ) {
my $lines = 0;
while ( <$tmpfile> ) {
chomp;
print STDERR ("++ ", $_, "\n") if $debug;
next if $_ eq "#### Patch data follows ####";
last if $_ eq "#### End of Patch data ####";
$p = _open_patch() unless $p;
print $p ($_, "\n");
$lines++;
}
print STDERR ("+ $lines lines sent to \"$patch\"\n") if $trace;
}
else {
while ( <$tmpfile> ) {
$p = _open_patch() unless $p;
print $p ($_)
}
}
defined $p and
$p->close || die ("Possible problems with \"$patch\", status = $?.\n");
}
sub set_utime ($$;$) {
my ($fn, $mtime, $mode) = @_;
$mode = (stat ($fn))[2] unless defined $mode;
chmod (0777, $fn)
|| warn ("WARNING: Cannot utime/chmod a+rwx $fn: $!\n");
print STDERR ("+ utime $fn $mtime (".localtime($mtime).")\n") if $trace;
# Set times. Ignore errors for directories since some systems
# (like MSWin32) do not allow directories to be stamped.
utime ($mtime, $mtime, $fn)
|| -d $fn || warn ("WARNING: utime($mtime,$fn): $!\n");
printf STDERR ("+ chmod 0%o $fn\n", $mode) if $trace;
chmod ($mode, $fn)
|| warn sprintf ("WARNING: Cannot utime/chmod 0%o $fn: $!\n", $mode);
}
sub do_unlink ($) {
my ($fn) = @_;
my $mode = (stat($fn))[2];
chmod (0777, $fn)
|| warn ("WARNING: Cannot unlink/chmod a+rwx $fn: $!\n");
print STDERR ("+ unlink $fn\n") if $verbose;
return if unlink ($fn);
warn ("WARNING: Cannot remove $fn: $!\n");
chmod ($mode, $fn)
|| warn sprintf ("WARNING: Cannot unlink/chmod 0%o $fn: $!\n", $mode);
}
( run in 0.494 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )