|
|
@@ -1,241 +1,243 @@
|
|
|
#!/usr/bin/perl
|
|
|
|
|
|
-$version= '1.2.6'; # This line modified by Makefile
|
|
|
+use warnings;
|
|
|
+use strict;
|
|
|
|
|
|
-%kmap= ('optional','suggests',
|
|
|
- 'recommended','recommends',
|
|
|
- 'class','priority',
|
|
|
- 'package_revision','revision');
|
|
|
+use IO::Handle;
|
|
|
+use IO::File;
|
|
|
|
|
|
-@fieldpri= ('Package',
|
|
|
- 'Source',
|
|
|
- 'Version',
|
|
|
- 'Priority',
|
|
|
- 'Section',
|
|
|
- 'Essential',
|
|
|
- 'Maintainer',
|
|
|
- 'Pre-Depends',
|
|
|
- 'Depends',
|
|
|
- 'Recommends',
|
|
|
- 'Suggests',
|
|
|
- 'Conflicts',
|
|
|
- 'Provides',
|
|
|
- 'Replaces',
|
|
|
- 'Architecture',
|
|
|
- 'Filename',
|
|
|
- 'Size',
|
|
|
- 'Installed-Size',
|
|
|
- 'MD5sum',
|
|
|
- 'Description',
|
|
|
- 'Origin',
|
|
|
- 'Bugs');
|
|
|
+my $version= '1.2.6'; # This line modified by Makefile
|
|
|
|
|
|
-$written=0;
|
|
|
-$i=100; grep($pri{$_}=$i--,@fieldpri);
|
|
|
+my %kmap= (optional => 'suggests',
|
|
|
+ recommended => 'recommends',
|
|
|
+ class => 'priority',
|
|
|
+ package_revision => 'revision',
|
|
|
+ );
|
|
|
|
|
|
-$udeb = 0;
|
|
|
-$arch = '';
|
|
|
-while ($ARGV[0] =~ m/^-.*/) {
|
|
|
- my $opt = shift @ARGV;
|
|
|
- if ($opt eq '-u') {
|
|
|
- $udeb = 1;
|
|
|
- } elsif ($opt =~ m/-a(.*)/) {
|
|
|
- if ($1) {
|
|
|
- $arch = $1;
|
|
|
- } else {
|
|
|
- $arch = shift @ARGV;
|
|
|
- }
|
|
|
- } else {
|
|
|
- print STDERR "Unknown option($opt)!\n";
|
|
|
- exit(1);
|
|
|
- }
|
|
|
-}
|
|
|
-$ext = $udeb ? 'udeb' : 'deb';
|
|
|
-$pattern = $arch ? "'(' -name '*_all.$ext' -o -name '*_$arch.$ext' ')'" : "-name '*.$ext'";
|
|
|
-if ($ARGV[1] eq '-u') {
|
|
|
- $udeb = 1;
|
|
|
- shift @ARGV;
|
|
|
-}
|
|
|
+my @fieldpri= ('Package',
|
|
|
+ 'Source',
|
|
|
+ 'Version',
|
|
|
+ 'Priority',
|
|
|
+ 'Section',
|
|
|
+ 'Essential',
|
|
|
+ 'Maintainer',
|
|
|
+ 'Pre-Depends',
|
|
|
+ 'Depends',
|
|
|
+ 'Recommends',
|
|
|
+ 'Suggests',
|
|
|
+ 'Conflicts',
|
|
|
+ 'Provides',
|
|
|
+ 'Replaces',
|
|
|
+ 'Enhances',
|
|
|
+ 'Architecture',
|
|
|
+ 'Filename',
|
|
|
+ 'Size',
|
|
|
+ 'Installed-Size',
|
|
|
+ 'MD5sum',
|
|
|
+ 'Description',
|
|
|
+ 'Origin',
|
|
|
+ 'Bugs'
|
|
|
+ );
|
|
|
|
|
|
-$#ARGV == 1 || $#ARGV == 2
|
|
|
- or die "Usage: dpkg-scanpackages [-u] [-a<arch>] binarypath overridefile [pathprefix] > Packages\n";
|
|
|
-($binarydir, $override, $pathprefix) = @ARGV;
|
|
|
--d $binarydir or die "Binary dir $binarydir not found\n";
|
|
|
--e $override or die "Override file $override not found\n";
|
|
|
+# This maps the fields into the proper case
|
|
|
+my %field_case;
|
|
|
+@field_case{map{lc($_)} @fieldpri} = @fieldpri;
|
|
|
|
|
|
-sub vercmp {
|
|
|
- ($a,$b)=@_;
|
|
|
- return $vercache{$a,$b} if defined($vercache{$a,$b});
|
|
|
- system("dpkg --compare-versions $a le $b");
|
|
|
- $vercache{$a,$a}=$?;
|
|
|
- return $?;
|
|
|
-}
|
|
|
+use Getopt::Long;
|
|
|
|
|
|
-# The extra slash causes symlinks to be followed.
|
|
|
-open(F,"find $binarydir/ -follow $pattern -print |")
|
|
|
- or die "Couldn't open pipe to find: $!\n";
|
|
|
-while (<F>) {
|
|
|
- chomp($fn=$_);
|
|
|
- substr($fn,0,length($binarydir)) eq $binarydir
|
|
|
- or die "$fn not in binary dir $binarydir\n";
|
|
|
- $t= `dpkg-deb -I $fn control`;
|
|
|
- if ($t eq "") {
|
|
|
- warn "Couldn't call dpkg-deb on $fn: $!, skipping package\n";
|
|
|
- next;
|
|
|
- }
|
|
|
- if ($?) {
|
|
|
- warn "\`dpkg-deb -I $fn control' exited with $?, skipping package\n";
|
|
|
- next;
|
|
|
- }
|
|
|
+my %options = (help => 0,
|
|
|
+ udeb => 0,
|
|
|
+ arch => undef,
|
|
|
+ multiversion => 0,
|
|
|
+ );
|
|
|
|
|
|
- undef %tv;
|
|
|
- $o= $t;
|
|
|
- while ($t =~ s/^\n*(\S+):[ \t]*(.*(\n[ \t].*)*)\n//) {
|
|
|
- $k= lc $1; $v= $2;
|
|
|
- if (defined($kmap{$k})) { $k= $kmap{$k}; }
|
|
|
- if (@kn= grep($k eq lc $_, @fieldpri)) {
|
|
|
- @kn==1 || die $k;
|
|
|
- $k= $kn[0];
|
|
|
- }
|
|
|
- $v =~ s/\s+$//;
|
|
|
- $tv{$k}= $v;
|
|
|
- }
|
|
|
- $t =~ /^\n*$/
|
|
|
- or die "Unprocessed text from $fn control file; info:\n$o / $t\n";
|
|
|
+my $result = GetOptions(\%options,'help|h|?','udeb|u!','arch|a=s','multiversion|m!');
|
|
|
|
|
|
- defined($tv{'Package'})
|
|
|
- or die "No Package field in control file of $fn\n";
|
|
|
- $p= $tv{'Package'}; delete $tv{'Package'};
|
|
|
+print <<END and exit 1 if not $result or $options{help} or @ARGV < 2;
|
|
|
+dpkg-scanpackages [-u] [-a<arch>] [-m] binarypath overridefile [pathprefix] > Packages
|
|
|
|
|
|
- if (defined($p1{$p})) {
|
|
|
- if (&vercmp($tv{'Version'}, $pv{$p,'Version'})) {
|
|
|
- print(STDERR " ! Package $p (filename $fn) is repeat but newer version;\n".
|
|
|
- " used that one and ignored data from $pfilename{$p} !\n")
|
|
|
- || die $!;
|
|
|
- delete $p1{$p};
|
|
|
- for $k (keys %k1) {
|
|
|
- delete $pv{$p,$k};
|
|
|
- }
|
|
|
- } else {
|
|
|
- print(STDERR " ! Package $p (filename $fn) is repeat;\n".
|
|
|
- " ignored that one and using data from $pfilename{$p} !\n")
|
|
|
- || die $!;
|
|
|
- next;
|
|
|
- }
|
|
|
- }
|
|
|
- print(STDERR " ! Package $p (filename $fn) has Filename field!\n") || die $!
|
|
|
- if defined($tv{'Filename'});
|
|
|
-
|
|
|
- $tv{'Filename'}= "$pathprefix$fn";
|
|
|
+ Options:
|
|
|
+ --udeb, -u scan for udebs
|
|
|
+ --arch, -a architecture to scan for
|
|
|
+ --multiversion, -m allow multiple versions of a single package
|
|
|
+ --help, -h show this help
|
|
|
|
|
|
- open(C,"md5sum <$fn |") || die "$fn $!";
|
|
|
- chop($_=<C>); close(C); $? and die "\`md5sum < $fn' exited with $?\n";
|
|
|
- /^([0-9a-f]{32})\s*-?\s*$/ or die "Strange text from \`md5sum < $fn': \`$_'\n";
|
|
|
- $tv{'MD5sum'}= $1;
|
|
|
+END
|
|
|
|
|
|
- @stat= stat($fn) or die "Couldn't stat $fn: $!\n";
|
|
|
- $stat[7] or die "$fn is empty\n";
|
|
|
- $tv{'Size'}= $stat[7];
|
|
|
|
|
|
- if (length($tv{'Revision'})) {
|
|
|
- $tv{'Version'}.= '-'.$tv{'Revision'};
|
|
|
- delete $tv{'Revision'};
|
|
|
- }
|
|
|
+my $udeb = $options{udeb};
|
|
|
+my $arch = $options{arch};
|
|
|
|
|
|
- for $k (keys %tv) {
|
|
|
- $pv{$p,$k}= $tv{$k};
|
|
|
- $k1{$k}= 1;
|
|
|
- $p1{$p}= 1;
|
|
|
- }
|
|
|
+my $ext = $options{udeb} ? 'udeb' : 'deb';
|
|
|
+my @find_args;
|
|
|
+if ($options{arch}) {
|
|
|
+ @find_args = ('(','-name',"*_all.$ext",'-o','-name',"_${arch}.$ext",')',);
|
|
|
+}
|
|
|
+else {
|
|
|
+ @find_args = ('-name',"*.$ext");
|
|
|
+}
|
|
|
+my ($binarydir, $override, $pathprefix) = @ARGV;
|
|
|
+-d $binarydir or die "Binary dir $binarydir not found\n";
|
|
|
+-e $override or die "Override file $override not found\n";
|
|
|
|
|
|
- $_= substr($fn,length($binarydir));
|
|
|
- s#/[^/]+$##; s#^/*##;
|
|
|
- $psubdir{$p}= $_;
|
|
|
- $pfilename{$p}= $fn;
|
|
|
+$pathprefix = '' if not defined $pathprefix;
|
|
|
+
|
|
|
+our %vercache;
|
|
|
+sub vercmp {
|
|
|
+ my ($a,$b)=@_;
|
|
|
+ return $vercache{$a}{$b} if exists $vercache{$a}{$b};
|
|
|
+ system('dpkg','--compare-versions',$a,'le',$b);
|
|
|
+ $vercache{$a}{$b}=$?;
|
|
|
+ return $?;
|
|
|
}
|
|
|
-close(F);
|
|
|
-$? and warn "find exited with $?\n";
|
|
|
+
|
|
|
+my %packages;
|
|
|
+my $find_h = new IO::Handle;
|
|
|
+open($find_h,'-|','find',"$binarydir/",@find_args,'-print')
|
|
|
+ or die "Couldn't open $binarydir for reading: $!\n";
|
|
|
+FILE:
|
|
|
+ while (<$find_h>) {
|
|
|
+ chomp;
|
|
|
+ my $fn = $_;
|
|
|
+ my $control = `dpkg-deb -I $fn control`;
|
|
|
+ if ($control eq "") {
|
|
|
+ warn "Couldn't call dpkg-deb on $fn: $!, skipping package\n";
|
|
|
+ next;
|
|
|
+ }
|
|
|
+ if ($?) {
|
|
|
+ warn "\`dpkg-deb -I $fn control' exited with $?, skipping package\n";
|
|
|
+ next;
|
|
|
+ }
|
|
|
+
|
|
|
+ my %tv = ();
|
|
|
+ my $temp = $control;
|
|
|
+ while ($temp =~ s/^\n*(\S+):[ \t]*(.*(\n[ \t].*)*)\n//) {
|
|
|
+ my ($key,$value)= (lc $1,$2);
|
|
|
+ if (defined($kmap{$key})) { $key= $kmap{$key}; }
|
|
|
+ if (defined($field_case{$key})) { $key= $field_case{$key}; }
|
|
|
+ $value =~ s/\s+$//;
|
|
|
+ $tv{$key}= $value;
|
|
|
+ }
|
|
|
+ $temp =~ /^\n*$/
|
|
|
+ or die "Unprocessed text from $fn control file; info:\n$control / $temp\n";
|
|
|
+
|
|
|
+ defined($tv{'Package'})
|
|
|
+ or die "No Package field in control file of $fn\n";
|
|
|
+ my $p= $tv{'Package'}; delete $tv{'Package'};
|
|
|
+
|
|
|
+ if (defined($packages{$p}) and not $options{multiversion}) {
|
|
|
+ foreach (@{$packages{$p}}) {
|
|
|
+ if (&vercmp($tv{'Version'}, $_->{'Version'})) {
|
|
|
+ print(STDERR " ! Package $p (filename $fn) is repeat but newer version;\n".
|
|
|
+ " used that one and ignored data from $_->{Filename} !\n")
|
|
|
+ || die $!;
|
|
|
+ $packages{$p} = [];
|
|
|
+ } else {
|
|
|
+ print(STDERR " ! Package $p (filename $fn) is repeat;\n".
|
|
|
+ " ignored that one and using data from $_->{Filename} !\n")
|
|
|
+ or die $!;
|
|
|
+ next FILE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ print(STDERR " ! Package $p (filename $fn) has Filename field!\n") || die $!
|
|
|
+ if defined($tv{'Filename'});
|
|
|
+
|
|
|
+ $tv{'Filename'}= "$pathprefix$fn";
|
|
|
+
|
|
|
+ open(C,"md5sum <$fn |") || die "$fn $!";
|
|
|
+ chop($_=<C>); close(C); $? and die "\`md5sum < $fn' exited with $?\n";
|
|
|
+ /^([0-9a-f]{32})\s*-?\s*$/ or die "Strange text from \`md5sum < $fn': \`$_'\n";
|
|
|
+ $tv{'MD5sum'}= $1;
|
|
|
+
|
|
|
+ my @stat= stat($fn) or die "Couldn't stat $fn: $!\n";
|
|
|
+ $stat[7] or die "$fn is empty\n";
|
|
|
+ $tv{'Size'}= $stat[7];
|
|
|
+
|
|
|
+ if (defined $tv{Revision} and length($tv{Revision})) {
|
|
|
+ $tv{Version}.= '-'.$tv{Revision};
|
|
|
+ delete $tv{Revision};
|
|
|
+ }
|
|
|
+
|
|
|
+ push @{$packages{$p}}, {%tv};
|
|
|
+ }
|
|
|
+close($find_h);
|
|
|
|
|
|
select(STDERR); $= = 1000; select(STDOUT);
|
|
|
|
|
|
+sub writelist {
|
|
|
+ my $title= shift(@_);
|
|
|
+ return unless @_;
|
|
|
+
|
|
|
+ print(STDERR " $title\n") || die $!;
|
|
|
+ my $packages= join(' ',sort @_);
|
|
|
+
|
|
|
format STDERR =
|
|
|
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
$packages
|
|
|
.
|
|
|
-
|
|
|
-sub writelist {
|
|
|
- $title= shift(@_);
|
|
|
- return unless @_;
|
|
|
- print(STDERR " $title\n") || die $!;
|
|
|
- $packages= join(' ',sort @_);
|
|
|
while (length($packages)) { write(STDERR) || die $!; }
|
|
|
print(STDERR "\n") || die $!;
|
|
|
}
|
|
|
|
|
|
-@samemaint=();
|
|
|
+my (@samemaint,@changedmaint);
|
|
|
+
|
|
|
|
|
|
-open(O, $override)
|
|
|
+my %overridden;
|
|
|
+my $override_fh = new IO::File $override,'r'
|
|
|
or die "Couldn't open override file $override: $!\n";
|
|
|
-while (<O>) {
|
|
|
+while (<$override_fh>) {
|
|
|
s/\#.*//;
|
|
|
s/\s+$//;
|
|
|
- ($p,$priority,$section,$maintainer)= split(/\s+/,$_,4);
|
|
|
- next unless defined($p1{$p});
|
|
|
- if (length($maintainer)) {
|
|
|
- if ($maintainer =~ m/\s*=\>\s*/) {
|
|
|
- $oldmaint= $`; $newmaint= $'; $debmaint= $pv{$p,'Maintainer'};
|
|
|
- if (!grep($debmaint eq $_, split(m:\s*//\s*:, $oldmaint))) {
|
|
|
- push(@changedmaint,
|
|
|
- " $p (package says $pv{$p,'Maintainer'}, not $oldmaint)\n");
|
|
|
- } else {
|
|
|
- $pv{$p,'Maintainer'}= $newmaint;
|
|
|
- }
|
|
|
- } elsif ($pv{$p,'Maintainer'} eq $maintainer) {
|
|
|
- push(@samemaint," $p ($maintainer)\n");
|
|
|
- } else {
|
|
|
- print(STDERR " * Unconditional maintainer override for $p *\n") || die $!;
|
|
|
- $pv{$p,'Maintainer'}= $maintainer;
|
|
|
- }
|
|
|
+ my ($p,$priority,$section,$maintainer)= split(/\s+/,$_,4);
|
|
|
+ next unless defined($packages{$p});
|
|
|
+ for my $package (@{$packages{$p}}) {
|
|
|
+ if (defined $maintainer and length($maintainer)) {
|
|
|
+ if ($maintainer =~ m/(.+?)\s*=\>\s*(.+)/) {
|
|
|
+ my $oldmaint= $1;
|
|
|
+ my $newmaint= $2;
|
|
|
+ my $debmaint= $$package{Maintainer};
|
|
|
+ if (!grep($debmaint eq $_, split(m:\s*//\s*:, $oldmaint))) {
|
|
|
+ push(@changedmaint,
|
|
|
+ " $p (package says $$package{Maintainer}, not $oldmaint)\n");
|
|
|
+ } else {
|
|
|
+ $$package{Maintainer}= $newmaint;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } elsif ($$package{Maintainer} eq $maintainer) {
|
|
|
+ push(@samemaint," $p ($maintainer)\n");
|
|
|
+ } else {
|
|
|
+ print(STDERR " * Unconditional maintainer override for $p *\n") || die $!;
|
|
|
+ $$package{Maintainer}= $maintainer;
|
|
|
+ }
|
|
|
+ $packages{$p}{Priority}= $priority;
|
|
|
+ $packages{$p}{Section}= $section;
|
|
|
}
|
|
|
- $pv{$p,'Priority'}= $priority;
|
|
|
- $pv{$p,'Section'}= $section;
|
|
|
- ($sectioncut = $section) =~ s:^[^/]*/::;
|
|
|
- if (length($psubdir{$p}) && $section ne $psubdir{$p} &&
|
|
|
- $sectioncut ne $psubdir{$p}) {
|
|
|
- if (length($psubdir{$p}) && $section ne $psubdir{$p}) {
|
|
|
- print(STDERR " !! Package $p has \`Section: $section',".
|
|
|
- " but file is in \`$psubdir{$p}' !!\n") || die $!;
|
|
|
- $ouches++;
|
|
|
- }
|
|
|
- }
|
|
|
- $o1{$p}= 1;
|
|
|
+ $overridden{$p} = 1;
|
|
|
}
|
|
|
-close(O);
|
|
|
-print(STDERR "\n") || die $! if $ouches;
|
|
|
-
|
|
|
-$k1{'Maintainer'}= 1;
|
|
|
-$k1{'Priority'}= 1;
|
|
|
-$k1{'Section'}= 1;
|
|
|
+close($override_fh);
|
|
|
|
|
|
-@missingover=();
|
|
|
+my @missingover=();
|
|
|
|
|
|
-for $p (sort keys %p1) {
|
|
|
- if (!defined($o1{$p})) {
|
|
|
+my $records_written = 0;
|
|
|
+for my $p (sort keys %packages) {
|
|
|
+ if (not defined($overridden{$p})) {
|
|
|
push(@missingover,$p);
|
|
|
}
|
|
|
- $r= "Package: $p\n";
|
|
|
- for $k (sort { $pri{$b} <=> $pri{$a} } keys %k1) {
|
|
|
- next unless length($pv{$p,$k});
|
|
|
- $r.= "$k: $pv{$p,$k}\n";
|
|
|
+ for my $package (@{$packages{$p}}) {
|
|
|
+ my $record= "Package: $p\n";
|
|
|
+ for my $key (@fieldpri) {
|
|
|
+ next unless defined $$package{$key};
|
|
|
+ $record .= "$key: $$package{$key}\n";
|
|
|
+ }
|
|
|
+ $record .= "\n";
|
|
|
+ $records_written++;
|
|
|
+ print(STDOUT $record) or die "Failed when writing stdout: $!\n";
|
|
|
}
|
|
|
- $r.= "\n";
|
|
|
- $written++;
|
|
|
- $p1{$p}= 1;
|
|
|
- print(STDOUT $r) or die "Failed when writing stdout: $!\n";
|
|
|
}
|
|
|
close(STDOUT) or die "Couldn't close stdout: $!\n";
|
|
|
|
|
|
-@spuriousover= grep(!defined($p1{$_}),sort keys %o1);
|
|
|
+my @spuriousover= grep(!defined($packages{$_}),sort keys %overridden);
|
|
|
|
|
|
&writelist("** Packages in archive but missing from override file: **",
|
|
|
@missingover);
|
|
|
@@ -258,4 +260,4 @@ if (@spuriousover) {
|
|
|
"\n") || die $!;
|
|
|
}
|
|
|
|
|
|
-print(STDERR " Wrote $written entries to output Packages file.\n") || die $!;
|
|
|
+print(STDERR " Wrote $records_written entries to output Packages file.\n") || die $!;
|