# -*- perl -*- Lintian::Processable::Orig # # Copyright © 2020 Felix Lechner # # 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 . package Lintian::Processable::Orig; use v5.20; use warnings; use utf8; use Const::Fast; use List::SomeUtils qw(uniq); use List::UtilsBy qw(sort_by); use Path::Tiny; use Unicode::UTF8 qw(encode_utf8); use Lintian::Index; use Moo::Role; use namespace::clean; const my $EMPTY => q{}; const my $SPACE => q{ }; const my $SLASH => q{/}; =head1 NAME Lintian::Processable::Orig - access to collected data about the upstream (orig) sources =head1 SYNOPSIS use Lintian::Processable; =head1 DESCRIPTION Lintian::Processable::Orig provides an interface to collected data about the upstream (orig) sources. =head1 INSTANCE METHODS =over 4 =item orig Returns the index for orig.tar.gz. =cut my %DECOMPRESS_COMMAND = ( 'gz' => 'gzip --decompress --stdout', 'bz2' => 'bzip2 --decompress --stdout', 'xz' => 'xz --decompress --stdout', ); has orig => ( is => 'rw', lazy => 1, default => sub { my ($self) = @_; my $index = Lintian::Index->new; $index->identifier($self->path . ' (orig)'); $index->basedir($self->basedir . $SLASH . 'orig'); return $index if $self->native; # source packages can be unpacked anywhere; no anchored roots $index->anchored(0); my %components = %{$self->components}; # keep sort order; root is missing below otherwise my @tarballs = sort_by { $components{$_} } keys %components; for my $tarball (@tarballs) { my $component = $components{$tarball}; # so far, all archives with components had an extra level my $component_dir = $index->basedir; $component_dir .= $SLASH . $component if length $component; my $subindex = Lintian::Index->new; $subindex->basedir($component_dir); # source packages can be unpacked anywhere; no anchored roots $index->anchored(0); my ($extension) = ($tarball =~ /\.([^.]+)$/); die encode_utf8("Source component $tarball has no file exension\n") unless length $extension; my $decompress = $DECOMPRESS_COMMAND{lc $extension}; die encode_utf8("Don't know how to decompress $tarball") unless $decompress; my @command = (split($SPACE, $decompress), $self->basedir . $SLASH . $tarball); my $errors = $subindex->create_from_piped_tar(\@command); $self->hint('unpack-message-for-orig', $tarball, $_) for uniq split(/\n/, $errors); # treat hard links like regular files my @hardlinks = grep { $_->is_hardlink } @{$subindex->sorted_list}; for my $item (@hardlinks) { my $target = $subindex->lookup($item->link); $item->unpacked_path($target->unpacked_path); $item->size($target->size); $item->link($EMPTY); # turn into a regular file my $perm = $item->perm; $perm =~ s/^-/h/; $item->perm($perm); $item->path_info( ($item->path_info & ~Lintian::Index::Item::TYPE_HARDLINK) | Lintian::Index::Item::TYPE_FILE); } my @prefixes = @{$subindex->sorted_list}; # keep top level prefixes; no trailing slashes s{^([^/]+).*$}{$1}s for @prefixes; # squash identical values; ignore root entry ('') my @unique = grep { length } uniq @prefixes; # check for single common value if (@unique == 1) { # no trailing slash for directories my $common = $unique[0]; # proceed if no file with that name (lacks slash) my $conflict = $subindex->lookup($common); unless (defined $conflict) { if ($common ne $component || length $component) { # shortens paths; keeps same base directory my $sub_errors = $subindex->drop_common_prefix; $self->hint('unpack-message-for-orig', $tarball, $_) for uniq split(/\n/, $sub_errors); } } } # lowers base directory to match index being merged into $subindex->capture_common_prefix if length $component; $index->merge_in($subindex); } return $index; }); =back =head1 AUTHOR Originally written by Felix Lechner for Lintian. =head1 SEE ALSO lintian(1) =cut 1; # Local Variables: # indent-tabs-mode: nil # cperl-indent-level: 4 # End: # vim: syntax=perl sw=4 sts=4 sr et