123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- #!/usr/bin/perl
- # $OpenBSD: check-problems,v 1.4 2016/09/14 15:02:41 espie Exp $
- # Copyright (c) 2004, 2010 Marc Espie <espie@openbsd.org>
- #
- # Permission to use, copy, modify, and distribute this software for any
- # purpose with or without fee is hereby granted, provided that the above
- # copyright notice and this permission notice appear in all copies.
- #
- # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- # check all packages in the current directory, and report common directory
- # issues
- use strict;
- use warnings;
- my ($ports1);
- use FindBin;
- BEGIN {
- $ports1 = $ENV{PORTSDIR} || '/usr/ports';
- }
- use lib ("$ports1/infrastructure/lib", "$FindBin::Bin/../lib");
- use File::Spec;
- use File::Path;
- use File::Basename;
- use OpenBSD::PkgCfl;
- use OpenBSD::Mtree;
- use OpenBSD::PlistScanner;
- # code for checking directories
- sub register_dir
- {
- my ($d, $h) = @_;
- return if defined $h->{$d};
- $h->{$d} = 1;
- register_dir(dirname($d), $h);
- }
- package OpenBSD::PackingElement;
- sub check_common_dirs
- {
- }
- package OpenBSD::PackingElement::FileBase;
- use File::Basename;
- sub check_common_dirs
- {
- my ($item, $t) = @_;
- my $d = File::Spec->canonpath($item->fullname);
- main::register_dir(dirname($d), $t->{need_dirs});
- }
- package OpenBSD::PackingElement::DirlikeObject;
- sub check_common_dirs
- {
- my ($item, $t) = @_;
- my $d = File::Spec->canonpath($item->fullname);
- $t->{dirs}->{$d} = 1;
- }
- package OpenBSD::PackingElement::Dependency;
- sub check_common_dirs
- {
- my ($item, $t, $o) = @_;
- $t->{deps}{$item->{def}} = 1;
- $o->{wanted}{$item->{def}} //= $o->{currentname};
- }
- # code for checking conflicts
- package OpenBSD::PackingElement;
- sub register
- {
- }
- sub known_page
- {
- }
- sub add_extra_manpage
- {
- }
- package OpenBSD::PackingElement::FileBase;
- my $pkg_list = {};
- my $seen = {};
- sub register
- {
- my ($self, $o, $pkgname) = @_;
- my $all_conflict = $o->{filehash};
- my $file = File::Spec->canonpath($self->fullname);
- # build one single list for each pkgnames combination
- if (exists $all_conflict->{$file}) {
- $pkg_list->{$all_conflict->{$file}}{$pkgname} ||=
- [@{$all_conflict->{$file}}, $pkgname ];
- $all_conflict->{$file} =
- $pkg_list->{$all_conflict->{$file}}{$pkgname};
- } elsif (exists $seen->{$file}) {
- $pkg_list->{$seen->{$file}}{$pkgname} ||=
- [ @{$seen->{$file}}, $pkgname ];
- $all_conflict->{$file} =
- $pkg_list->{$seen->{$file}}{$pkgname};
- delete $seen->{$file};
- } else {
- $pkg_list->{$pkgname} ||= [$pkgname];
- $seen->{$file} = $pkg_list->{$pkgname};
- }
- }
- package OpenBSD::PackingElement::Dependency;
- sub register
- {
- my ($self, $o, $pkgname) = @_;
- $o->{wanted}{$self->{def}} //= $o->{currentname};
- push @{$o->{all_deps}{$pkgname}}, $self->{def};
- }
- package OpenBSD::PackingElement::Manpage;
- sub is_dest
- {
- my $self = shift;
- return $self->name =~ m/man\/cat[^\/]+\/[^\/]+\.0$/o;
- }
- sub dest_to_source
- {
- my $self = shift;
- my $v = $self->name;
- $v =~ s/(man\/)cat([^\/]+)(\/[^\/]+)\.0$/$1man$2$3.$2/;
- return $v;
- }
- sub known_page
- {
- my ($self, $h) = @_;
- $h->{File::Spec->canonpath($self->fullname)} = 1;
- }
- sub add_extra_manpage
- {
- my ($self, $known, $plist) = @_;
- if ($self->is_source) {
- my $dest = $self->source_to_dest;
- my $fullname = $self->cwd."/".$dest;
- my $file = File::Spec->canonpath($fullname);
- if (!$known->{$file}) {
- OpenBSD::PackingElement::Manpage->add($plist, $dest);
- $known->{$file} = 1;
- }
- }
- if ($self->is_dest) {
- my $src = $self->dest_to_source;
- my $fullname = $self->cwd."/".$src;
- my $file = File::Spec->canonpath($fullname);
- if (!$known->{$file}) {
- OpenBSD::PackingElement::Manpage->add($plist, $src);
- $known->{$file} = 1;
- }
- }
- }
- package CheckProblemsScanner;
- our @ISA = (qw(OpenBSD::PlistScanner));
- use OpenBSD::PackageInfo;
- sub add_more_man
- {
- my ($self, $plist) = @_;
- my $knownman = {};
- $plist->known_page($knownman);
- $plist->add_extra_manpage($knownman, $plist);
- }
- sub register_plist
- {
- my ($self, $plist) = @_;
- my $pkgname = $plist->pkgname;
- $self->{got}{$pkgname} = 1;
- if ($self->{do_dirs}) {
- $self->{db}{$pkgname} //= {
- pkgname => $pkgname,
- missing_deps => {},
- dirs => {},
- need_dirs => {},
- deps => {},
- problems => {}
- };
- $plist->check_common_dirs($self->{db}{$pkgname}, $self);
- }
- if ($self->{do_conflicts}) {
- $self->{conflicts}{$pkgname} =
- OpenBSD::PkgCfl->make_conflict_list($plist);
- if ($self->ui->opt('e')) {
- $self->add_more_man($plist);
- }
- $plist->register($self, $pkgname);
- }
- }
- sub handle_options
- {
- my $self = shift;
- $self->{signature_style} = 'unsigned';
- $self->SUPER::handle_options('CD',
- "[-CDeSv] [-d plist_dir] [-o output] [-p ports_dir] [pkgname ...]");
- }
- sub new
- {
- my ($class) = @_;
- my $o = $class->SUPER::new('check-problems');
- if ($o->ui->opt('D') && $o->ui->opt('C')) {
- $o->ui->usage("Won't compute anything");
- }
- $o->{do_dirs} = !$o->ui->opt('D');
- $o->{do_conflicts} = !$o->ui->opt('C');
- if ($o->{do_dirs}) {
- $o->{db} = {};
- $o->{mtree} = {
- '/usr/local/lib/X11' => 1,
- '/usr/local/include/X11' => 1,
- '/usr/local/lib/X11/app-defaults' => 1
- };
- OpenBSD::Mtree::parse($o->{mtree}, '/',
- '/etc/mtree/4.4BSD.dist');
- OpenBSD::Mtree::parse($o->{mtree}, '/',
- '/etc/mtree/BSD.x11.dist');
- }
- if ($o->{do_conflicts}) {
- $o->{filehash} = {};
- $o->{conflicts} = {};
- $o->{all_deps} = {};
- }
- return $o;
- }
- # for common dirs
- sub parent_has_dir
- {
- my ($self, $db, $t, $dir) = @_;
- for my $dep (keys %{$t->{deps}}) {
- if (!defined $db->{$dep}) {
- if (!defined $self->{missing_deps}{$dep}) {
- $self->ui->errsay("#1 : #2 not found", $t->{pkgname},
- $dep);
- $self->{missing_deps}{$dep} = 1;
- }
- next;
- }
- if ($db->{$dep}->{dirs}->{$dir} ||
- $self->parent_has_dir($db, $db->{$dep}, $dir)) {
- $t->{dirs}{$dir} = 1;
- return 1;
- }
- }
- return 0;
- }
- sub parent_has_problem
- {
- my ($db, $t, $dir) = @_;
- for my $dep (keys %{$t->{deps}}) {
- next if !defined $db->{$dep};
- if ($db->{$dep}->{problems}->{$dir}) {
- return 1;
- }
- }
- return 0;
- }
- sub build_common_dirs
- {
- my ($self) = @_;
- my $db = $self->{db};
- my $mtree = $self->{mtree};
- my @l = keys %$db;
- $self->progress->for_list("Checking common dirs", \@l,
- sub {
- my $pkgname = shift;
- my $t = $db->{$pkgname};
- for my $dir (keys(%{$t->{need_dirs}})) {
- return if $t->{dirs}{$dir};
- return if $mtree->{$dir};
- return if $self->parent_has_dir($db, $t, $dir);
- $t->{problems}{$dir} = 1;
- }
- });
- $self->progress->next;
- }
- sub show_common_dirs
- {
- my ($self) = @_;
- my $db = $self->{db};
- for my $pkgname (sort {$self->fullname($a) cmp $self->fullname($b)}
- keys %$db) {
- my @l=();
- my $t = $db->{$pkgname};
- for my $dir (keys %{$t->{problems}}) {
- next if parent_has_problem($db, $t, $dir);
- push(@l, $dir);
- }
- if (@l != 0) {
- $self->say("#1: #2", $self->fullname($pkgname),
- join(', ', sort @l));
- }
- }
- }
- # for conflicts
- my $cache3 = {};
- my $cache4 = {};
- sub direct_conflict
- {
- my ($conflicts, $pkg, $pkg2) = @_;
- return $cache3->{$pkg}{$pkg2} //= $conflicts->{$pkg}->conflicts_with($pkg2);
- }
- sub has_a_conflict
- {
- my ($conflicts, $deps, $pkg, $pkg2) = @_;
- return $cache4->{$pkg}{$pkg2} //= find_a_conflict($conflicts, $deps, $pkg, $pkg2);
- }
- sub find_a_conflict
- {
- my ($conflicts, $deps, $pkg, $pkg2) = @_;
- return 0 if $pkg eq $pkg2;
-
- if (defined $conflicts->{$pkg} &&
- direct_conflict($conflicts, $pkg, $pkg2)) {
- return 1;
- }
- if (defined $deps->{$pkg}) {
- for my $dep (@{$deps->{$pkg}}) {
- if (has_a_conflict($conflicts, $deps, $dep, $pkg2)) {
- return 1;
- }
- }
- }
- if (defined $deps->{$pkg2}) {
- for my $dep (@{$deps->{$pkg2}}) {
- if (has_a_conflict($conflicts, $deps, $pkg, $dep)) {
- return 1;
- }
- }
- }
- return 0;
- }
- sub compute_true_conflicts
- {
- my ($self, $l) = @_;
- my $conflicts = $self->{conflicts};
- my $deps = $self->{all_deps};
- # create a list of unconflicting packages.
- my $l2 = [];
- for my $pkg (@$l) {
- my $keepit = 0;
- for my $pkg2 (@$l) {
- next if $pkg eq $pkg2;
- if (!(has_a_conflict($conflicts, $deps, $pkg, $pkg2) ||
- has_a_conflict($conflicts, $deps, $pkg2, $pkg))) {
- $keepit = 1;
- last;
- }
- }
- if ($keepit) {
- push(@$l2, $pkg);
- }
- }
- return $l2;
- }
- sub compute_conflicts
- {
- my ($self) = @_;
- $self->progress->set_header("Compute file problems");
- my $c = {};
- my $c2 = {};
- my $r = {};
- my $cache = {};
- my $h = $self->{filehash};
- my $total = scalar(keys %$h);
- my $i =0;
- while (my ($key, $l) = each %$h) {
- $self->progress->show(++$i, $total);
- if (!defined $c->{$l}) {
- my %s = map {($_, 1)} @$l;
- $c->{$l} = [sort keys %s];
- $c2->{$l} = join(',', @{$c->{$l}});
- }
- my $hv = $c2->{$l};
- $l = $c->{$l};
- next if @$l == 1;
- $cache->{$hv} //= $self->compute_true_conflicts($l);
- my $result = $cache->{$hv};
- if (@$result != 0) {
- my $newkey = join(',',
- sort map { $self->fullname($_) } @$result);
- if (@$result == 1) {
- $newkey.="-> was ".join(',', @$l);
- }
- push(@{$r->{$newkey}}, $key);
- }
- }
- $self->progress->next;
- return $r;
- }
- sub show_conflicts
- {
- my ($self, $result) = @_;
- for my $cfl (sort keys %$result) {
- $self->say("#1", $cfl);
- for my $f (sort @{$result->{$cfl}}) {
- $self->say("\t#1", $f);
- }
- }
- }
- sub display_results
- {
- my $self = shift;
- if ($self->{do_dirs}) {
- $self->build_common_dirs;
- $self->say("Common dirs:");
- $self->show_common_dirs;
- }
- if ($self->{do_conflicts}) {
- my $result = $self->compute_conflicts;
- $self->say("Conflicts:");
- $self->show_conflicts($result);
- }
- }
- package main;
- my $o = CheckProblemsScanner->new;
- $o->run;
|