This will make it easy to add support for flat deltas, etc.
#!/usr/bin/perl
# pristine-tar delta file library
+# See delta-format.txt for details about the contents of delta files.
package Pristine::Tar::Delta;
use Pristine::Tar;
use warnings;
use strict;
-use File::Basename;
-# See delta-format.txt for details about the contents of delta files.
-#
-# Some of the delta contents are treated as files. Things not listed here
-# are treated as fields with short values.
+# Checks if a field of a delta should be stored in the delta hash using
+# a filename. (Normally the hash stores the whole field value, but
+# using filenames makes sense for a few fields.)
my %delta_files=map { $_ => 1 } qw(manifest delta wrapper);
+sub is_filename {
+ my $field=shift;
+ return $delta_files{$field};
+}
-# After the filename to create, this takes a hashref containing
-# the contents of the delta file to create.
+sub handler {
+ my $action=shift;
+ my $type=shift;
+
+ my $class="Pristine::Tar::Delta::$type";
+ eval "use $class";
+ if ($@) {
+ error "unsupported delta file format $type";
+ }
+ $class->$action(@_);
+}
+
+# After the type of delta and the file to create (which can be "-"
+# to send it to stdout), this takes a hashref containing the contents of
+# the delta to write.
sub write {
+ my $type=shift;
my $deltafile=shift;
my $delta=shift;
$stdout=1;
$deltafile="$tempdir/tmpout";
}
-
- foreach my $field (keys %$delta) {
- if ($delta_files{$field}) {
- link($delta->{$field}, "$tempdir/$field") || die "link $tempdir/$field: $!";
- }
- else {
- open (my $out, ">", "$tempdir/$field") || die "$tempdir/$field: $!";
- print $out $delta->{$field}."\n";
- close $out;
- }
- }
-
- doit("tar", "czf", $deltafile, "-C", $tempdir, keys %$delta);
+
+ handler('write', $type, $deltafile, $delta);
if ($stdout) {
doit("cat", $deltafile);
# Returns a hashref of the contents of the delta.
sub read {
+ my $type=shift;
my $deltafile=shift;
my $tempdir=tempdir();
}
close $out;
}
- doit("tar", "xf", File::Spec->rel2abs($deltafile), "-C", $tempdir);
- unlink($deltafile) if $stdin;
- my %delta;
- foreach my $file (glob("$tempdir/*")) {
- if (-f $file) {
- my $field=basename($file);
- if ($delta_files{$field}) {
- $delta{$field}=$file;
- }
- else {
- open (my $in, "<", $file) || die "$file: $!";
- {
- local $/=undef;
- $delta{$field}=<$in>;
- }
- chomp $delta{$field};
- close $in;
- }
- }
- }
- # TODO read all files
+ my $delta=handler('read', $type, $deltafile);
- return \%delta;
+ unlink($deltafile) if $stdin;
+
+ return $delta;
}
# Checks the type, maxversion, minversion of a delta hashref.
--- /dev/null
+#!/usr/bin/perl
+# pristine-tar delta files formatted as tarballs
+package Pristine::Tar::Delta::Tarball;
+
+use Pristine::Tar;
+use Pristine::Tar::Delta;
+use File::Basename;
+use warnings;
+use strict;
+
+sub write {
+ my $class=shift;
+ my $deltafile=shift;
+ my $delta=shift;
+
+ my $tempdir=tempdir();
+
+ foreach my $field (keys %$delta) {
+ if (Pristine::Tar::Delta::is_filename($field)) {
+ link($delta->{$field}, "$tempdir/$field") || die "link $tempdir/$field: $!";
+ }
+ else {
+ open (my $out, ">", "$tempdir/$field") || die "$tempdir/$field: $!";
+ print $out $delta->{$field}."\n";
+ close $out;
+ }
+ }
+
+ doit("tar", "czf", $deltafile, "-C", $tempdir, keys %$delta);
+
+ return $delta;
+}
+
+sub read {
+ my $class=shift;
+ my $deltafile=shift;
+
+ my $tempdir=tempdir();
+ doit("tar", "xf", File::Spec->rel2abs($deltafile), "-C", $tempdir);
+
+ my %delta;
+ foreach my $file (glob("$tempdir/*")) {
+ if (-f $file) {
+ my $field=basename($file);
+ if (Pristine::Tar::Delta::is_filename($field)) {
+ $delta{$field}=$file;
+ }
+ else {
+ open (my $in, "<", $file) || die "$file: $!";
+ {
+ local $/=undef;
+ $delta{$field}=<$in>;
+ }
+ chomp $delta{$field};
+ close $in;
+ }
+ }
+ }
+
+ return \%delta;
+}
+
+1
my $deltafile=shift;
my $file=shift;
- my $delta=Pristine::Tar::Delta::read($deltafile);
+ my $delta=Pristine::Tar::Delta::read(Tarball => $deltafile);
Pristine::Tar::Delta::assert($delta, type => "bz2", maxversion => 2,
fields => [qw{params program}]);
my ($program, @params) = reproducebzip2($bzip2file);
- Pristine::Tar::Delta::write($deltafile, {
+ Pristine::Tar::Delta::write(Tarball => $deltafile, {
version => '2.0',
type => 'bz2',
params => "@params",
my $deltafile=shift;
my $file=shift;
- my $delta=Pristine::Tar::Delta::read($deltafile);
+ my $delta=Pristine::Tar::Delta::read(Tarball => $deltafile);
Pristine::Tar::Delta::assert($delta, type => "gz", maxversion => 3,
fields => [qw{params filename timestamp}]);
my ($filename, $timestamp, $xdelta, @params)=
reproducegz($gzfile, $tempdir, "$tempdir/test");
- Pristine::Tar::Delta::write($deltafile, {
+ Pristine::Tar::Delta::write(Tarball => $deltafile, {
version => (defined $xdelta ? "3.0" : "2.0"),
type => 'gz',
params => "@params",
my $tarball=shift;
my %opts=@_;
- my $delta=Pristine::Tar::Delta::read($deltafile);
+ my $delta=Pristine::Tar::Delta::read(Tarball => $deltafile);
Pristine::Tar::Delta::assert($delta, type => "tar", maxversion => 2,
minversion => 2, fields => [qw{manifest delta}]);
doit("xdelta", "patch", $delta->{delta}, $recreatetarball, $out);
if (defined $delta->{wrapper}) {
- my $delta_wrapper=Pristine::Tar::Delta::read($delta->{wrapper});
+ my $delta_wrapper=Pristine::Tar::Delta::read(Tarball => $delta->{wrapper});
if ($delta_wrapper->{type} eq 'gz') {
doit("pristine-gz",
($verbose ? "-v" : "--no-verbose"),
error "xdelta failed with return code $ret";
}
- Pristine::Tar::Delta::write($deltafile, {
+ Pristine::Tar::Delta::write(Tarball => $deltafile, {
version => 2,
type => 'tar',
%delta,