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 )