1 # This module is part of debbugs, and
2 # is released under the terms of the GPL version 3, or any later
3 # version (at your option). See the file README and COPYING for more
5 # Copyright 2018 by Don Armstrong <don@donarmstrong.com>.
7 package Debbugs::Package;
11 Debbugs::Package -- OO interface to packages
16 Debbugs::Package->new(schema => $s,binaries => [qw(foo)],sources => [qw(bar)]);
26 use v5.10; # for state
27 use namespace::autoclean;
29 use List::AllUtils qw(uniq pairmap);
30 use Debbugs::Config qw(:config);
31 use Debbugs::Version::Source;
32 use Debbugs::Version::Binary;
34 extends 'Debbugs::OOBase';
42 name if binary, name prefixed with C<src:> if source
46 has name => (is => 'ro', isa => 'Str',
53 # src: if source, nothing if binary
54 ($self->_type eq 'source' ? 'src:':'') .
61 Type of the package; either C<binary> or C<source>
65 has type => (is => 'bare', isa => 'Str',
67 builder => '_build_type',
68 clearer => '_clear_type',
70 writer => '_set_type',
75 if ($self->name !~ /^src:/) {
88 return $config{web_domain}.'/'.$self->qualified_name;
91 around BUILDARGS => sub {
95 if (@_==1 and ref($_[0]) eq 'HASH') {
100 $args{name} //= '(unknown)';
101 if ($args{name} =~ /src:(.+)/) {
103 $args{type} = 'source';
105 $args{type} = 'binary' unless
108 return $class->$orig(%args);
113 true if the package is a source package
117 true if the package is a binary package
122 return $_[0]->_type eq 'source'
126 return $_[0]->_type eq 'binary'
129 =head2 valid -- true if the package has any valid versions
133 has valid => (is => 'ro', isa => 'Bool',
135 builder => '_build_valid',
136 writer => '_set_valid',
141 if ($self->_valid_versioninfo > 0) {
147 # this contains source name, source version, binary name, binary version, arch,
148 # and dist which have been selected from the database. It is used to build
149 # versions and anything else which are known as required.
150 has 'valid_version_info' =>
151 (is => 'bare', isa => 'ArrayRef',
154 builder => '_build_valid_versioninfo',
155 predicate => '_has_valid_versioninfo',
156 clearer => '_clear_valid_versioninfo',
157 handles => {'_get_valid_versioninfo' => 'get',
158 '_grep_valid_versioninfo' => 'grep',
159 '_valid_versioninfo' => 'elements',
163 sub _build_valid_versioninfo {
165 my $pkgs = $self->_get_valid_version_info_from_db;
166 for my $invalid_version (@{$pkgs->{$self->qualified_name}->{invalid_versions}}) {
167 $self->_mark_invalid_version($invalid_version,1);
169 return $pkgs->{$self->qualified_name}->{valid_version_info} // [];
172 state $common_dists = [@{$config{distributions}}];
173 sub _get_valid_version_info_from_db {
175 if ((@_ % 2) == 1 and
183 if ($self->has_schema) {
188 @packages = $self->qualified_name;
191 @packages = @{$args{packages}};
193 if (not defined $s) {
194 confess("get_info_from_db not implemented without schema");
197 my %src_ver_packages;
199 my %bin_ver_packages;
200 # split packages into src/ver, bin/ver, src, and bin so we can select them
203 for my $pkg (@packages) {
205 if ($pkg->[0] =~ /^src:(.+)$/) {
206 for my $ver (@{$pkg}[1..$#{$pkg}]) {
207 $src_ver_packages{$1}{$ver} = 0;
210 for my $ver (@{$pkg}[1..$#{$pkg}]) {
211 $bin_ver_packages{$pkg->[0]}{$ver} = 0;
214 } elsif ($pkg =~ /^src:(.+)$/) {
215 $src_packages{$1} = 0;
217 $bin_packages{$pkg} = 0;
220 # calculate searches for packages where we want specific versions. We
221 # calculate this here so add_result_to_package can stomp over
222 # %src_ver_packages and %bin_ver_packages
224 for my $sp (keys %src_ver_packages) {
225 push @src_ver_search,
226 (-and => {'src_pkg.pkg' => $sp,
227 'me.ver' => [keys %{$src_ver_packages{$sp}}],
233 for my $sp (keys %bin_ver_packages) {
234 push @bin_ver_search,
235 (-and => {'bin_pkg.pkg' => $sp,
236 'me.ver' => [keys %{$bin_ver_packages{$sp}}],
241 sub _default_pkg_info {
242 return {name => $_[0],
243 type => $_[1]//'source',
245 valid_version_info => [],
246 invalid_versions => {},
249 sub add_result_to_package {
250 my ($pkgs,$rs,$svp,$bvp,$sp,$bp) = @_;
251 while (my $pkg = $rs->next) {
252 my $n = 'src:'.$pkg->{src_pkg};
253 if (not exists $pkgs->{$n}) {
255 _default_pkg_info($pkg->{src_pkg});
257 push @{$pkgs->{$n}{valid_version_info}},
259 $n = $pkg->{bin_pkg};
260 if (not exists $pkgs->{$n}) {
262 _default_pkg_info($pkg->{bin_pkg},'binary');
264 push @{$pkgs->{$n}{valid_version_info}},
266 # this is a package with a valid src_ver
267 $svp->{$pkg->{src_pkg}}{$pkg->{src_ver}}++;
268 $sp->{$pkg->{src_pkg}}++;
269 # this is a package with a valid bin_ver
270 $bvp->{$pkg->{bin_pkg}}{$pkg->{bin_ver}}++;
271 $bp->{$pkg->{bin_pkg}}++;
274 if (keys %src_packages) {
275 my $src_rs = $s->resultset('SrcVer')->
276 search({-or => [-and => {'src_pkg.pkg' => [keys %src_packages],
277 -or => {'suite.codename' => $common_dists,
278 'suite.suite_name' => $common_dists,
286 'src_associations' => 'suite'},
288 'bin_vers' => ['bin_pkg','arch']},
291 'select' => [qw(src_pkg.pkg),
293 qw(suite.suite_name),
294 qw(src_associations.modified),
296 q(CONCAT(src_pkg.pkg,'/',me.ver)),
297 qw(bin_vers.ver bin_pkg.pkg arch.arch),
300 'as' => [qw(src_pkg codename suite_name),
301 qw(modified_time src_ver src_pkg_ver),
302 qw(bin_ver bin_pkg arch maintainer),
304 result_class => 'DBIx::Class::ResultClass::HashRefInflator',
307 add_result_to_package($packages,$src_rs,
314 if (keys %bin_packages) {
316 $s->resultset('BinAssociation')->
317 search({-and => {'bin_pkg.pkg' => [keys %bin_packages],
318 -or => {'suite.codename' => $common_dists,
319 'suite.suite_name' => $common_dists,
323 [{'src_ver' => ['src_pkg',
330 'select' => [qw(src_pkg.pkg),
332 qw(suite.suite_name),
335 q(CONCAT(src_pkg.pkg,'/',src_ver.ver)),
336 qw(bin.ver bin_pkg.pkg arch.arch),
339 'as' => [qw(src_pkg codename suite_name),
340 qw(modified_time src_ver src_pkg_ver),
341 qw(bin_ver bin_pkg arch maintainer),
343 result_class => 'DBIx::Class::ResultClass::HashRefInflator',
346 add_result_to_package($packages,$bin_assoc_rs,
353 if (@bin_ver_search) {
354 my $bin_rs = $s->resultset('BinVer')->
355 search({-or => [@bin_ver_search,
360 'bin_associations' => 'suite'},
361 {'src_ver' => ['src_pkg',
366 'select' => [qw(src_pkg.pkg),
368 qw(suite.suite_name),
369 qw(bin_associations.modified),
371 q(CONCAT(src_pkg.pkg,'/',src_ver.ver)),
372 qw(me.ver bin_pkg.pkg arch.arch),
375 'as' => [qw(src_pkg codename suite_name),
376 qw(modified_time src_ver src_pkg_ver),
377 qw(bin_ver bin_pkg arch maintainer),
379 result_class => 'DBIx::Class::ResultClass::HashRefInflator',
382 add_result_to_package($packages,$bin_rs,
389 for my $sp (keys %src_ver_packages) {
390 if (not exists $packages->{'src:'.$sp}) {
391 $packages->{'src:'.$sp} =
392 _default_pkg_info($sp,'source',0);
394 for my $sv (keys %{$src_ver_packages{$sp}}) {
395 next if $src_ver_packages{$sp}{$sv} > 0;
396 $packages->{'src:'.$sp}{invalid_versions}{$sv} = 1;
399 for my $bp (keys %bin_ver_packages) {
400 if (not exists $packages->{$bp}) {
402 _default_pkg_info($bp,'binary',0);
404 for my $bv (keys %{$bin_ver_packages{$bp}}) {
405 next if $bin_ver_packages{$bp}{$bv} > 0;
406 $packages->{$bp}{invalid_versions}{$bv} = 1;
409 for my $sp (keys %src_packages) {
410 next if $src_packages{$sp} > 0;
411 $packages->{'src:'.$sp} =
412 _default_pkg_info($sp,'source',0);
414 for my $bp (keys %bin_packages) {
415 next if $bin_packages{$bp} > 0;
417 _default_pkg_info($bp,'binary',0);
422 has 'source_version_to_info' =>
423 (is => 'bare', isa => 'HashRef',
426 builder => '_build_source_version_to_info',
427 handles => {_get_source_version_to_info => 'get',
431 sub _build_source_version_to_info {
435 for my $v ($self->_valid_versioninfo) {
436 push @{$info->{$v->{src_ver}}}, $i;
442 has 'binary_version_to_info' =>
443 (is => 'bare', isa => 'HashRef',
446 builder => '_build_binary_version_to_info',
447 handles => {_get_binary_version_to_info => 'get',
451 sub _build_binary_version_to_info {
455 for my $v ($self->_valid_versioninfo) {
456 push @{$info->{$v->{bin_ver}}}, $i;
462 has 'dist_to_info' =>
463 (is => 'bare', isa => 'HashRef',
466 builder => '_build_dist_to_info',
467 handles => {_get_dist_to_info => 'get',
470 sub _build_dist_to_info {
474 for my $v ($self->_valid_versioninfo) {
475 push @{$info->{$v->{dist}}}, $i;
481 # this is a hashref of versions that we know are invalid
482 has 'invalid_versions' =>
483 (is => 'bare',isa => 'HashRef[Bool]',
486 clearer => '_clear_invalid_versions',
488 handles => {_invalid_version => 'exists',
489 _mark_invalid_version => 'set',
493 has 'binaries' => (is => 'ro',
494 isa => 'Debbugs::Collection::Package',
496 builder => '_build_binaries',
497 predicate => '_has_binaries',
500 sub _build_binaries {
502 if ($self->is_binary) {
503 return $self->package_collection->limit($self);
505 # OK, walk through the valid_versions for this package
507 uniq map {$_->{bin_pkg}} $self->_valid_versioninfo;
508 return $self->package_collection->limit(@binaries);
511 has 'sources' => (is => 'ro',
512 isa => 'Debbugs::Collection::Package',
514 builder => '_build_sources',
515 predicate => '_has_sources',
520 if ($self->is_source) {
521 return $self->package_collection->limit($self);
523 # OK, walk through the valid_versions for this package
525 uniq map {'src:'.$_->{src_pkg_name}} $self->_valid_versioninfo;
526 return $self->package_collection->limit(@sources);
529 has 'versions' => (is => 'bare',
530 isa => 'HashRef[Debbugs::Version]',
532 handles => {_exists_version => 'exists',
533 _get_version => 'get',
534 _set_version => 'set',
537 builder => '_build_versions',
540 sub _build_versions {
552 $self->_set_version(@set);
555 sub get_source_version_distribution {
558 my %src_pkg_vers = @_;
562 $self->_get_dist_to_info($dist);
564 _get_valid_versioninfo(@ver_loc)) {
565 $src_pkg_vers{$v->{src_pkg_ver}} = 1;
568 return $self->package_collection->
569 get_source_versions(keys %src_pkg_vers)->members;
572 # returns the source version(s) corresponding to the version of *this* package; the
573 # version passed may be binary or source, depending.
574 sub get_source_version {
576 if ($self->is_source) {
577 return $self->get_version(@_);
584 ($ver,@archs) = @{$ver};
585 @archs{@archs} = (1) x @archs;
588 @{$self->_get_binary_version_to_info($ver)//[]};
589 next unless @ver_loc;
590 my @vers = map {$self->
591 _get_valid_versioninfo($_)}
595 next unless exists $archs{$v->{arch}};
597 $src_pkg_vers{$v->{src_pkg_ver}} = 1;
600 return $self->package_collection->
601 get_source_versions(keys %src_pkg_vers)->members;
608 if ($self->_exists_version($v)) {
609 push @ret,$self->_get_version($v);
612 $self->_create_version($v);
618 sub _create_version {
621 if ($self->is_source) {
625 Debbugs::Version::Source->
626 new(package => $self,
628 package_collection => $self->package_collection,
629 $self->schema_argument,
636 Debbugs::Version::Binary->
637 new(package => $self,
639 package_collection => $self->package_collection,
640 $self->schema_argument,
644 $self->_set_version(@versions);
647 =head2 package_collection
649 L<Debbugs::Collection::Package> to get additional packages required
653 # gets used to retrieve packages
654 has 'package_collection' => (is => 'ro',
655 isa => 'Debbugs::Collection::Package',
656 builder => '_build_package_collection',
660 sub _build_package_collection {
662 return Debbugs::Collection::Package->new($self->schema_argument)
667 return 'Debbugs::Package={package='.$self->qualified_name.'}';
670 __PACKAGE__->meta->make_immutable;
678 # indent-tabs-mode: nil
679 # cperl-indent-level: 4