1 # This module is part of debbugs, and is released
2 # under the terms of the GPL version 2, or any later
3 # version at your option.
4 # See the file README and COPYING for more information.
6 # Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
8 package Debbugs::DebArchive;
15 Debbugs::DebArchive -- Routines for reading files from Debian archives
19 use Debbugs::DebArchive;
21 read_packages('/srv/mirrors/ftp.debian.org/ftp/dist',
22 sub { print map {qq($_\n)} @_ },
23 Term::ProgressBar->new(),
29 This module implements a set of routines for reading Packages.gz, Sources.gz and
30 Release files from the dists directory of a Debian archive.
39 use vars qw($DEBUG $VERSION @EXPORT_OK %EXPORT_TAGS @EXPORT);
40 use base qw(Exporter);
44 $DEBUG = 0 unless defined $DEBUG;
47 %EXPORT_TAGS = (read => [qw(read_release_file read_packages),
51 Exporter::export_ok_tags(keys %EXPORT_TAGS);
52 $EXPORT_TAGS{all} = [@EXPORT_OK];
57 use Debbugs::Config qw(:config);
58 use Debbugs::Common qw(open_compressed_file make_list);
65 =item read_release_file
67 read_release_file('stable/Release')
69 Reads a Debian release file and returns a hashref of information about the
70 release file, including the Packages and Sources files for that distribution
74 sub read_release_file {
77 my $rfh = open_compressed_file($file) or
78 die "Unable to open $file for reading: $!";
85 if ($1 eq 'SHA1'or $1 eq 'SHA256') {
92 my ($sha,$size,$f) = split /\s+/,$_;
93 next unless $f =~ /(?:Packages|Sources)(?:\.gz|\.xz)$/;
94 next unless $f =~ m{^([^/]+)/([^/]+)/([^/]+)$};
95 my ($component,$arch,$package_source) = ($1,$2,$3);
97 next if exists $p_f{$component}{$arch} and
98 $p_f{$component}{$arch} =~ /\.xz$/;
99 $p_f{$component}{$arch} = File::Spec->catfile(dirname($file),$f);
102 return (\%dist_info,\%p_f);
107 read_packages($dist_dir,$callback,$progress)
113 Path to dists directory
117 Function which is called with key, value pairs of suite, arch, component,
118 Package, Source, Version, and Maintainer information for each package in the
123 Optional Term::ProgressBar object to output progress while reading packages.
131 my ($dist_dir,$callback,$p) = @_;
135 for my $dist (make_list($dist_dir)) {
136 my $dist_dir_h = IO::Dir->new($dist);
138 grep { $_ !~ /^\./ and
141 } $dist_dir_h->read or
142 die "Unable to read from dir: $!";
143 $dist_dir_h->close or
144 die "Unable to close dir: $!";
145 while (my $dist = shift @dist_names) {
146 my $dir = $dist_dir.'/'.$dist;
147 my ($dist_info,$package_files) =
148 read_release_file(File::Spec->catfile($dist_dir,
151 $s_p{$dist_info->{Codename}} = $package_files;
153 for my $suite (keys %s_p) {
154 for my $component (keys %{$s_p{$suite}}) {
155 $tot += scalar keys %{$s_p{$suite}{$component}};
159 $p->target($tot) if $p;
161 # parse packages files
162 for my $suite (keys %s_p) {
164 for my $component (keys %{$s_p{$suite}}) {
165 my @archs = keys %{$s_p{$suite}{$component}};
166 if (grep {$_ eq 'source'} @archs) {
167 @archs = ('source',grep {$_ ne 'source'} @archs);
169 for my $arch (@archs) {
170 my $pfh = open_compressed_file($s_p{$suite}{$component}{$arch}) or
171 die "Unable to open $s_p{$suite}{$component}{$arch} for reading: $!";
173 local $/ = ''; # paragraph mode
176 for my $field (qw(Package Maintainer Version Source)) {
177 /^\Q$field\E: (.*)/m;
180 next unless defined $pkg{Package} and
181 defined $pkg{Version};
182 $pkg{suite} = $suite;
184 $pkg{component} = $component;
187 $p->update(++$done_archs) if $p;
202 # indent-tabs-mode: nil
203 # cperl-indent-level: 4