diff options
Diffstat (limited to 'scripts/Dpkg/Dist/Files.pm')
-rw-r--r-- | scripts/Dpkg/Dist/Files.pm | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/scripts/Dpkg/Dist/Files.pm b/scripts/Dpkg/Dist/Files.pm new file mode 100644 index 0000000..1a9fa1f --- /dev/null +++ b/scripts/Dpkg/Dist/Files.pm @@ -0,0 +1,219 @@ +# Copyright © 2014-2015 Guillem Jover <guillem@debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +=encoding utf8 + +=head1 NAME + +Dpkg::Dist::Files - handle built artifacts to distribute + +=head1 DESCRIPTION + +This module provides a class used to parse and write the F<debian/files> +file, as part of the list of built artifacts to include in an upload. + +B<Note>: This is a private module, its API can change at any time. + +=cut + +package Dpkg::Dist::Files 0.01; + +use strict; +use warnings; + +use IO::Dir; + +use Dpkg::Gettext; +use Dpkg::ErrorHandling; + +use parent qw(Dpkg::Interface::Storable); + +sub new { + my ($this, %opts) = @_; + my $class = ref($this) || $this; + + my $self = { + options => [], + files => {}, + }; + foreach my $opt (keys %opts) { + $self->{$opt} = $opts{$opt}; + } + bless $self, $class; + + return $self; +} + +sub reset { + my $self = shift; + + $self->{files} = {}; +} + +sub parse_filename { + my ($self, $fn) = @_; + + my $file; + + if ($fn =~ m/^(([-+:.0-9a-z]+)_([^_]+)_([-\w]+)\.([a-z0-9.]+))$/) { + # Artifact using the common <name>_<version>_<arch>.<type> pattern. + $file->{filename} = $1; + $file->{package} = $2; + $file->{version} = $3; + $file->{arch} = $4; + $file->{package_type} = $5; + } elsif ($fn =~ m/^([-+:.,_0-9a-zA-Z~]+)$/) { + # Artifact with no common pattern, usually called byhand or raw, as + # they might require manual processing on the server side, or custom + # actions per file type. + $file->{filename} = $1; + } else { + $file = undef; + } + + return $file; +} + +sub parse { + my ($self, $fh, $desc) = @_; + my $count = 0; + + local $_; + binmode $fh; + + while (<$fh>) { + chomp; + + my $file; + + if (m/^(\S+) (\S+) (\S+)((?:\s+[0-9a-z-]+=\S+)*)$/) { + $file = $self->parse_filename($1); + error(g_('badly formed file name in files list file, line %d'), $.) + unless defined $file; + $file->{section} = $2; + $file->{priority} = $3; + my $attrs = $4; + $file->{attrs} = { map { split /=/ } split ' ', $attrs }; + } else { + error(g_('badly formed line in files list file, line %d'), $.); + } + + if (defined $self->{files}->{$file->{filename}}) { + warning(g_('duplicate files list entry for file %s (line %d)'), + $file->{filename}, $.); + } else { + $count++; + $self->{files}->{$file->{filename}} = $file; + } + } + + return $count; +} + +sub load_dir { + my ($self, $dir) = @_; + + my $count = 0; + my $dh = IO::Dir->new($dir) or syserr(g_('cannot open directory %s'), $dir); + + while (defined(my $file = $dh->read)) { + my $pathname = "$dir/$file"; + next unless -f $pathname; + $count += $self->load($pathname); + } + + return $count; +} + +sub get_files { + my $self = shift; + + return map { $self->{files}->{$_} } sort keys %{$self->{files}}; +} + +sub get_file { + my ($self, $filename) = @_; + + return $self->{files}->{$filename}; +} + +sub add_file { + my ($self, $filename, $section, $priority, %attrs) = @_; + + my $file = $self->parse_filename($filename); + error(g_('invalid filename %s'), $filename) unless defined $file; + $file->{section} = $section; + $file->{priority} = $priority; + $file->{attrs} = \%attrs; + + $self->{files}->{$filename} = $file; + + return $file; +} + +sub del_file { + my ($self, $filename) = @_; + + delete $self->{files}->{$filename}; +} + +sub filter { + my ($self, %opts) = @_; + my $remove = $opts{remove} // sub { 0 }; + my $keep = $opts{keep} // sub { 1 }; + + foreach my $filename (keys %{$self->{files}}) { + my $file = $self->{files}->{$filename}; + + if (not $keep->($file) or $remove->($file)) { + delete $self->{files}->{$filename}; + } + } +} + +sub output { + my ($self, $fh) = @_; + my $str = ''; + + binmode $fh if defined $fh; + + foreach my $filename (sort keys %{$self->{files}}) { + my $file = $self->{files}->{$filename}; + my $entry = "$filename $file->{section} $file->{priority}"; + + if (exists $file->{attrs}) { + foreach my $attr (sort keys %{$file->{attrs}}) { + $entry .= " $attr=$file->{attrs}->{$attr}"; + } + } + + $entry .= "\n"; + + print { $fh } $entry if defined $fh; + $str .= $entry; + } + + return $str; +} + +=head1 CHANGES + +=head2 Version 0.xx + +This is a private module. + +=cut + +1; |