Alt-App-makepatch
view release on metacpan or search on metacpan
script/applypatch view on Meta::CPAN
#!/usr/bin/perl -w
# applypatch -- apply a 'makepatch' generated patch kit.
# Author : Johan Vromans
# Created On : Sat Nov 14 14:34:28 1998
# Last Modified By: Johan Vromans
# Last Modified On: Fri Oct 26 21:52:01 2012
# Update Count : 149
# Status : Released
use strict;
use Getopt::Long 2.00;
use File::Basename;
use File::Spec;
use IO::File;
use Text::ParseWords;
################ Common stuff ################
my $my_package = 'Sciurix';
my $my_name = "applypatch";
my $my_version = "2.05";
my $data_version = '1.0';
################ Globals ################
## Options and defaults.
my $dir; # source directory
my $check = 0; # check only
my $retain = 0; # retain .orig files
my $patch = 'patch -p0 -N'; # patch command
my $verbose = 0; # verbose processing
my $force = 0; # allow continuation after trunc/corruption
# Development options (not shown with -help).
my $trace = 0; # trace (show process)
my $test = 0; # test (no actual processing)
my $debug = 0; # extensive debugging info
## Misc
my $applypatch = 0; # it's for us
my $timestamp; # create date/time of patch kit
my @workq = (); # work queue
## Subroutine prototypes
sub app_options ();
sub app_usage ($);
sub copy_input ();
sub execute_patch ();
sub post_patch ();
sub pre_patch ();
sub verify_files ();
################ 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;
}
script/applypatch view on Meta::CPAN
$all_bytes += length ($_);
# System V 'sum' checksum
$sum = ($sum + unpack ("%16C*", $_)) % 65535;
$all_sum = ($all_sum + unpack ("%16C*", $_)) % 65535;
# Copy the line to the temp file.
print $tmpfile ($_);
}
close($argv);
}
# If we saw an ApplyPatch data section, it must be reliable.
if ( $applypatch == 1 ) {
warn ("ApplyPatch data section not properly terminated.\n");
$fail = 1;
}
elsif ( $applypatch == 2 ) {
warn ("ApplyPatch data section not reliable.\n");
$fail = 1;
}
if ( $applypatch ) {
# If we saw a Patch data section, it must be reliable.
if ( $patchdata == 0 ) {
warn ("Patch data section not delimited.\n");
$fail = 1;
}
elsif ( $patchdata == 1 ) {
warn ("Patch data section not properly terminated.\n");
$fail = 1;
}
elsif ( $patchdata == 2 ) {
warn ("Patch data section not reliable.\n");
$fail = 1;
}
if ($endkit == 0 ) {
warn ("Missing \"#### End of Patch kit\" line.\n");
$fail = 1;
}
}
if ( $fail ) {
if ( $force ) {
warn ("WARNING: Verification of patch kit failed, ",
"continuing anyway.\n");
}
else {
die ("Verification of patch kit failed, aborting.\n",
"Use \"--force\" to override this.\n");
}
}
print STDERR ($applypatch == 3 ? "Apply" : "",
"Patch kit apparently okay.\n") if $verbose;
# Reset file to start of patch data.
$tmpfile->setpos ($pos);
}
sub verify_files () {
my $fail = 0;
print STDERR ("Verify source directory.\n") if $verbose;
foreach ( @workq ) {
my ($op, $fn, @args) = @$_;
if ( $op eq 'c' ) {
if ( -f $fn || -d _ ) {
warn ("Verify error: file $fn must be created, ",
"but already exists.\n");
$fail = 1;
}
}
elsif ( $op eq 'C' ) {
if ( -f $fn || -d _ ) {
warn ("Verify error: directory $fn must be created, ",
"but already exists.\n");
$fail = 1;
}
}
elsif ( $op eq 'r' || $op eq 'p' || $op eq 'v' ) {
my $sz = -s $fn;
if ( defined $sz ) {
if ( $sz != $args[0] ) {
warn ("Verify error: size of $fn should be $args[0], but is ",
"$sz.\n");
$fail = 1;
}
}
else {
warn ("Verify error: file $fn is missing.\n");
$fail = 1;
}
}
elsif ( $op eq 'R' ) {
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;
}
script/applypatch view on Meta::CPAN
# Process options, if any.
# Make sure defaults are set before returning!
return unless @ARGV > 0;
my @opts = ('check' => \$check,
'dir|d=s' => \$dir,
'retain' => \$retain,
'force' => \$force,
'verbose' => \$verbose,
'quiet' => sub { $verbose = 0; },
'patch=s' => \$patch,
'test' => \$test,
'trace' => \$trace,
'debug' => \$debug,
'help' => \$help);
(!GetOptions (@opts) || $help) && app_usage (2);
}
sub app_usage ($) {
my ($exit) = @_;
print STDERR <<EndOfUsage;
Usage: $0 [options] patch-kit
-help this message
-dir XXX change to this directory before executing
-check check, but does not execute
-retain retain .orig file after patching
-force continue after verification failures
-patch XXX the patch command, default "$patch"
-quiet no information
-verbose verbose information
EndOfUsage
exit $exit if defined $exit && $exit != 0;
}
1;
__END__
################ Documentation ################
=head1 NAME
applypatch - apply 'makepatch' generated script to update a source tree
=head1 SYNOPSIS
B<applypatch> [ I<options> ] I<patch-kit>
=head1 DESCRIPTION
B<Applypatch> applies a patch kit as generated by the B<makepatch>
program. It performs the following actions:
=over 4
=item *
First, it will extensively verify that the patch kit is complete and
did not get corrupted during transfer.
=item *
Then it will apply some heuristics to verify that the directory in
which the patch will be applied does indeed contain the expected
sources.
If a corruption or verification error is detected, B<applypatch> exits
without making changes.
=item *
If the kit is okay, and the directory seems to be the right one: it
creates new files and directories as necessary.
=item *
Then it runs the B<patch> program to apply the patch to the source files.
=item *
Upon completion, obsolete files, directories and .orig files are
removed, file modes of new files are set, and the timestamps of
all patched files are adjusted.
=back
=head1 Applypatch arguments
B<Applypatch> takes one argument, the name of the patch kit as
generated by B<makepatch>. If no name is specified, the patch kit is
read from standard input.
=head1 Applypatch options
Options are matched case insensitive, and may be abbreviated to uniqueness.
=over 4
=item B<-directory> I<dir>
The name of the source directory to be patched.
=item B<-check>
Perform the checks on the patch kit and patch directory, but do not
make any changes.
=item B<-force>
Force continuation of the patch process even when corruption or
verification errors are detected. This is very dangerous!
=item B<-retain>
Do not remove patch backup files (with extension C<.orig>) upon
completion.
=item B<-patch> I<cmd>
The patch command to be used. Default is "C<patch -p0 -N>".
Additionally, a "C<-s>" will be added unless option B<-verbose> was
specified.
( run in 0.826 second using v1.01-cache-2.11-cpan-39bf76dae61 )