From: Joey Hess Date: Mon, 9 Jan 2012 16:20:59 +0000 (-0400) Subject: pristine-xz X-Git-Tag: 1.18~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0fffffa296c0cd691f4330d3473a3c7d6b5cd919;p=tools%2Fpristine-tar.git pristine-xz works, at least minimally --- diff --git a/Pristine/Tar/Formats.pm b/Pristine/Tar/Formats.pm index a141a3d..42afca1 100644 --- a/Pristine/Tar/Formats.pm +++ b/Pristine/Tar/Formats.pm @@ -6,7 +6,7 @@ package Pristine::Tar::Formats; use warnings; use strict; use Exporter q{import}; -our @EXPORT=qw{is_gz is_bz2 %fconstants}; +our @EXPORT=qw{is_gz is_bz2 is_xz %fconstants}; our %fconstants=( # magic identification @@ -14,6 +14,12 @@ our %fconstants=( GZIP_ID2 => 0x8B, BZIP2_ID1 => 0x42, BZIP2_ID2 => 0x5a, + XZ_ID1 => 0xFD, + XZ_ID2 => 0x37, + XZ_ID3 => 0x7A, + XZ_ID4 => 0x58, + XZ_ID5 => 0x5A, + XZ_ID6 => 0x00, # compression methods # 0x00-0x07 are reserved @@ -78,4 +84,10 @@ sub is_bz2 { $fconstants{BZIP2_METHOD_HUFFMAN}); } +sub is_xz { + magic(shift, $fconstants{XZ_ID1}, $fconstants{XZ_ID2}, + $fconstants{XZ_ID3}, $fconstants{XZ_ID4}, + $fconstants{XZ_ID5}, $fconstants{XZ_ID6}); +} + 1 diff --git a/debian/changelog b/debian/changelog index 074d2b1..3133f38 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +pristine-tar (1.18) UNRELEASED; urgency=low + + * pristine-xz: A very simplistic xz recreator. + + -- Joey Hess Mon, 09 Jan 2012 12:36:57 -0400 + pristine-tar (1.17) unstable; urgency=low * pristine-tar: Fail when the delta is excessively large, probably diff --git a/delta-format.txt b/delta-format.txt index 4060631..644a7c0 100644 --- a/delta-format.txt +++ b/delta-format.txt @@ -45,3 +45,10 @@ program It may also be zgz (the params will include --old-bzip2 in this case). + +For xz files, the wrapper contains: + +params + Typically, only the compression level is needed. +program + Program used to compress. Almost everytime, it is xz. diff --git a/pristine-tar b/pristine-tar index 06dae6b..e3c2a11 100755 --- a/pristine-tar +++ b/pristine-tar @@ -27,8 +27,9 @@ the I branch, thus allowing Debian packages to be built entirely using sources in version control, without the need to keep copies of upstream tarballs. -pristine-tar supports compressed tarballs, calling out to pristine-gz(1) -and pristine-bz2(1) to produce the pristine gzip and bzip2 files. +pristine-tar supports compressed tarballs, calling out to pristine-gz(1), +pristine-bz2(1), and pristine-xz(1) to produce the pristine gzip, bzip2, +and xz files. =head1 COMMANDS @@ -145,8 +146,8 @@ available. =head1 LIMITATIONS -Only tarballs, gzipped tarballs, and bzip2ed tarballs are currently -supported. +Only tarballs, gzipped tarballs, bzip2ed tarballs, and xzed tarballs +are currently supported. Currently only the git revision control system is supported by the "checkout" and "commit" commands. It's ok if the working copy @@ -395,21 +396,14 @@ sub gentar { if (defined $delta->{wrapper}) { my $delta_wrapper=Pristine::Tar::Delta::read(Tarball => $delta->{wrapper}); - if ($delta_wrapper->{type} eq 'gz') { - doit("pristine-gz", + if (grep { $_ eq $delta_wrapper->{type} } qw{gz bz2 xz}) { + doit("pristine-".$delta_wrapper->{type}, ($verbose ? "-v" : "--no-verbose"), ($debug ? "-d" : "--no-debug"), ($keep ? "-k" : "--no-keep"), - "gengz", $delta->{wrapper}, $out); - doit("mv", "-f", $out.".gz", $tarball); - } - elsif ($delta_wrapper->{type} eq 'bz2') { - doit("pristine-bz2", - ($verbose ? "-v" : "--no-verbose"), - ($debug ? "-d" : "--no-debug"), - ($keep ? "-k" : "--no-keep"), - "genbz2", $delta->{wrapper}, $out); - doit("mv", "-f", $out.".bz2", $tarball); + "gen".$delta_wrapper->{type}, + $delta->{wrapper}, $out); + doit("mv", "-f", $out.".".$delta_wrapper->{type}, $tarball); } else { error "unknown wrapper file type: ". @@ -460,6 +454,14 @@ sub gendelta { close IN || die "bzcat: $!"; close OUT || die "$tempdir/origtarball: $!"; } + elsif (is_xz($tarball)) { + $compression='xz'; + open(IN, "-|", "xzcat", $tarball) || die "xzcat: $!"; + open(OUT, ">", "$tempdir/origtarball") || die "$tempdir/origtarball: $!"; + print OUT $_ while ; + close IN || die "xzcat: $!"; + close OUT || die "$tempdir/origtarball: $!"; + } close IN; # Generate a wrapper file to recreate the compressed file. diff --git a/pristine-xz b/pristine-xz new file mode 100755 index 0000000..a0365b3 --- /dev/null +++ b/pristine-xz @@ -0,0 +1,212 @@ +#!/usr/bin/perl + +=head1 NAME + +pristine-xz - regenerate pristine xz files + +=head1 SYNOPSIS + +B [-vdk] gendelta I I + +B [-vdk] genxz I I + +=head1 DESCRIPTION + +This is a complement to the pristine-tar(1) command. Normally you +don't need to run it by hand, since pristine-tar calls it as necessary +to handle .tar.xz files. + +pristine-xz gendelta takes the specified I file, and generates a +small binary I file that can later be used by pristine-xz genxz +to recreate the original file. + +pristine-xz genxz takes the specified I file, and compresses the +specified input I (which must be identical to the contents of the +original xz file). The resulting file will be identical to +the original gz file used to create the delta. + +The approach used to regenerate the original xz file is to figure out +how it was produced -- what compression level was used, etc. Currently +support is poor for xz files produced with unusual compression options. + +If the delta filename is "-", pristine-xz reads or writes it to stdio. + +=head1 OPTIONS + +=over 4 + +=item -v + +Verbose mode, show each command that is run. + +=item -d + +Debug mode. + +=item -k + +Don't clean up the temporary directory on exit. + +=item -t + +Try harder to determine how to generate deltas of difficult xz files. + +=back + +=head1 ENVIRONMENT + +=over 4 + +=item B + +Specifies a location to place temporary files, other than the default. + +=back + +=head1 AUTHOR + +Joey Hess , +Faidon Liambotis , +Cyril Brulebois + +Licensed under the GPL, version 2. + +=cut + +use warnings; +use strict; +use Pristine::Tar; +use Pristine::Tar::Delta; +use Pristine::Tar::Formats; +use File::Basename qw/basename/; +use IO::Handle; + +my @supported_xz_programs = qw(xz); + +my $try=0; + +dispatch( + commands => { + usage => [\&usage], + genxz => [\&genxz, 2], + gendelta => [\&gendelta, 2], + }, + options => { + "t|try!" => \$try, + }, +); + +sub usage { + print STDERR "Usage: pristine-xz [-vdkt] gendelta file.xz delta\n"; + print STDERR " pristine-xz [-vdkt] genxz delta file\n"; +} + +sub readxz { + my $filename = shift; + + if (! is_xz($filename)) { + error "This is not a valid xz archive."; + } + + # XXX This is the default compression level; we don't currently have + # a way to guess the level from the file format, as this level only + # presets several other tunables. Correct handling would involve + # finding as many preset values as possible, and reconstructing the + # compression level from that. + my $level = 6; + + return ($level); +} + +sub predictxzargs { + my ($level, $program) = @_; + + my @args=["-z", "-$level"]; + + return @args; +} + +sub testvariant { + my ($old, $tmpin, $xz_program, @args) = @_; + + my $new=$tmpin.'.xz'; + unlink($new); + + # Note that file name, mode, mtime do not matter to xz. + + # try xz'ing with the arguments passed + doit_redir($tmpin, $new, $xz_program, @args); + + unless (-e $new) { + die("$xz_program failed, aborting"); + } + + # and compare the generated with the original + return !comparefiles($old, $new); +} + +sub reproducexz { + my $orig=shift; + + my $wd=tempdir(); + + my $tmpin="$wd/test"; + doit_redir($orig, $tmpin, "xz", "-dc"); + + # read fields from xz headers + my ($level) = readxz($orig); + debug("level: $level"); + + foreach my $program (@supported_xz_programs) { + # try to guess the xz arguments that are needed by the + # header information + foreach my $args (predictxzargs($level, $program)) { + testvariant($orig, $tmpin, $program, @$args) + && return $program, @$args; + } + } + + print STDERR "pristine-xz failed to reproduce build of $orig\n"; + print STDERR "(Please file a bug report.)\n"; + exit 1; +} + +sub genxz { + my $deltafile=shift; + my $file=shift; + + my $delta=Pristine::Tar::Delta::read(Tarball => $deltafile); + Pristine::Tar::Delta::assert($delta, type => "xz", maxversion => 2, + fields => [qw{params program}]); + + my @params=split(' ', $delta->{params}); + while (@params) { + my $param=shift @params; + + next if $param=~/^(-[1-9])$/; + next if $param eq '-z'; + die "paranoia check failed on params from delta (@params)"; + } + @params=split(' ', $delta->{params}); + + my $program=$delta->{program}; + if (! grep { $program eq $_ } @supported_xz_programs) { + die "paranoia check failed on program from delta ($program)"; + } + + doit($program, @params, $file); +} + +sub gendelta { + my $xzfile=shift; + my $deltafile=shift; + + my ($program, @params) = reproducexz($xzfile); + + Pristine::Tar::Delta::write(Tarball => $deltafile, { + version => '2.0', + type => 'xz', + params => "@params", + program => $program, + }); +}