#!/usr/bin/perl # $OpenBSD: find-all-conflicts,v 1.11 2005/12/12 13:37:21 espie Exp $ # Copyright (c) 2000-2005 # Marc Espie. All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Neither the name of OpenBSD nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY ITS AUTHOR AND THE OpenBSD project ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # check all packages in the current directory, and report conflicts which # are not apparent in @pkgcfl. use strict; use File::Spec; use File::Path; use OpenBSD::PackageLocator; use OpenBSD::PackageInfo; use OpenBSD::PackingList; use OpenBSD::Getopt; use OpenBSD::Error; use OpenBSD::PkgCfl; package OpenBSD::PackingElement; sub register { } package OpenBSD::PackingElement::FileBase; sub register { my ($self, $all_conflict, $all_deps, $pkgname) = @_; my $file= File::Spec->canonpath($self->fullname()); unless (defined $all_conflict->{$file}) { $all_conflict->{$file} = []; } push @{$all_conflict->{$file}}, $pkgname; } package OpenBSD::PackingElement::Depend; sub register { my ($self, $all_conflict, $all_deps, $pkgname) = @_; if (defined $self->{def}) { unless (defined $all_deps->{$pkgname}) { $all_deps->{$pkgname} = []; } push @{$all_deps->{$pkgname}}, $self->{def}; } } package main; my $cache = {}; my $cache2 = {}; sub find_a_conflict { my ($conflicts, $deps, $pkg, $pkg2) = @_; return 0 if $pkg eq $pkg2; if (defined $conflicts->{$pkg} && $conflicts->{$pkg}->conflicts_with($pkg2)) { return 1; } if (defined $deps->{$pkg}) { for my $dep (@{$deps->{$pkg}}) { if (find_a_conflict($conflicts, $deps, $dep, $pkg2)) { return 1; } } } if (defined $deps->{$pkg2}) { for my $dep (@{$deps->{$pkg2}}) { if (find_a_conflict($conflicts, $deps, $pkg, $dep)) { return 1; } } } return 0; } sub compute_problems { my ($h, $conflicts, $deps) = @_; while (my ($key, $l) = each %$h) { my %s = map {($_, 1)} @$l; @$l = sort keys %s; if (@$l > 1) { my $hv = join(',', @$l); if (!defined $cache->{$hv}) { # 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 (!(find_a_conflict($conflicts, $deps, $pkg, $pkg2) || find_a_conflict($conflicts, $deps, $pkg2, $pkg))) { $keepit = 1; last; } } if ($keepit) { push(@$l2, $pkg); } } $cache->{$hv} = $l2; } my $result = $cache->{$hv}; if (@$result != 0) { my $newkey = join(',', @$result); if (@$result == 1) { $newkey.="-> was ".join(',', @$l); } $cache2->{$newkey} = [] unless defined($cache2->{$newkey}); push(@{$cache2->{$newkey}}, $key); } } } } my $filehash={}; my %dirhash=(); my $conflicts={}; my $dephash={}; our ($opt_d, $opt_v); sub handle_file { my $filename = shift; my $plist = OpenBSD::PackingList->fromfile($filename); if (!defined $plist) { print STDERR "Error reading $filename\n"; return; } print "$filename -> ", $plist->pkgname(), "\n" if $opt_v; $plist->forget(); $conflicts->{$plist->pkgname()} = OpenBSD::PkgCfl->make_conflict_list($plist); $plist->visit('register', $filehash, $dephash, $plist->pkgname()); } set_usage('find-all-conflicts [-v] [-d plist_dir] [pkgname ...]'); try { getopts('d:v'); } catchall { Usage($_); }; print "Scanning packages\n" if $opt_v; print "-----------------\n" if $opt_v; if ($opt_d) { opendir(my $dir, $opt_d); while (my $pkgname = readdir($dir)) { next if $pkgname eq '.' or $pkgname eq '..'; handle_file("$opt_d/$pkgname"); } closedir($dir); } elsif (@ARGV==0) { @ARGV=(<*.tgz>); } for my $pkgname (@ARGV) { print STDERR "$pkgname\n"; my $true_package = OpenBSD::PackageLocator->find($pkgname); next unless $true_package; my $dir = $true_package->info(); $true_package->close(); handle_file($dir.CONTENTS); rmtree($dir); } print "File problems:\n"; print "-------------\n"; compute_problems($filehash, $conflicts, $dephash); for my $cfl (sort keys %$cache2) { print "$cfl\n"; for my $f (sort @{$cache2->{$cfl}}) { print "\t$f\n"; } }