1# ex:ts=8 sw=4: 2# $OpenBSD: RequiredBy.pm,v 1.27 2015/08/13 16:34:11 espie Exp $ 3# 4# Copyright (c) 2003-2005 Marc Espie <espie@openbsd.org> 5# 6# Permission to use, copy, modify, and distribute this software for any 7# purpose with or without fee is hereby granted, provided that the above 8# copyright notice and this permission notice appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18use strict; 19use warnings; 20 21package OpenBSD::RequirementList; 22use OpenBSD::PackageInfo; 23use Carp; 24 25sub fatal_error 26{ 27 my ($self, $msg) = @_; 28 require OpenBSD::Tracker; 29 OpenBSD::Tracker->dump; 30 confess ref($self), ": $msg $self->{filename}: $!"; 31} 32 33sub fill_entries 34{ 35 my $self = shift; 36 if (!exists $self->{entries}) { 37 my $l = $self->{entries} = {}; 38 39 if (-f $self->{filename}) { 40 open(my $fh, '<', $self->{filename}) or 41 $self->fatal_error("reading"); 42 while(<$fh>) { 43 s/\s+$//o; 44 next if /^$/o; 45 chomp; 46 $l->{$_} = 1; 47 } 48 close($fh); 49 $self->{nonempty} = 1; 50 } else { 51 $self->{nonempty} = 0; 52 } 53 } 54} 55 56sub synch 57{ 58 my $self = shift; 59 return $self if $main::not; 60 61 if (!unlink $self->{filename}) { 62 if ($self->{nonempty}) { 63 croak ref($self), ": erasing $self->{filename}: $!"; 64 } 65 } 66 if (%{$self->{entries}}) { 67 open(my $fh, '>', $self->{filename}) or 68 $self->fatal_error("writing"); 69 while (my ($k, $v) = each %{$self->{entries}}) { 70 print $fh "$k\n"; 71 } 72 close($fh) or 73 croak ref($self), ": closing $self->{filename}: $!"; 74 $self->{nonempty} = 1; 75 } else { 76 $self->{nonempty} = 0; 77 } 78 return $self; 79} 80 81sub list 82{ 83 my $self = shift; 84 85 if (wantarray) { 86 $self->fill_entries; 87 return keys %{$self->{entries}}; 88 } else { 89 if (exists $self->{entries}) { 90 return %{$self->{entries}} ? 1 : 0; 91 } elsif (!exists $self->{nonempty}) { 92 $self->{nonempty} = -f $self->{filename} ? 1 : 0; 93 } 94 return $self->{nonempty}; 95 } 96} 97 98sub erase 99{ 100 my $self = shift; 101 $self->{entries} = {}; 102 $self->synch; 103} 104 105sub delete 106{ 107 my ($self, @pkgnames) = @_; 108 $self->fill_entries($self); 109 for my $pkg (@pkgnames) { 110 delete $self->{entries}->{$pkg}; 111 } 112 $self->synch; 113} 114 115sub add 116{ 117 my ($self, @pkgnames) = @_; 118 $self->fill_entries($self); 119 for my $pkg (@pkgnames) { 120 $self->{entries}->{$pkg} = 1; 121 } 122 $self->synch; 123} 124 125my $cache = {}; 126 127sub new 128{ 129 my ($class, $pkgname) = @_; 130 my $f = installed_info($pkgname).$class->filename; 131 if (!exists $cache->{$f}) { 132 return $cache->{$f} = bless { filename => $f }, $class; 133 } 134 return $cache->{$f}; 135} 136 137sub forget 138{ 139 my ($class, $dir) = @_; 140 my $f = $dir.$class->filename; 141 if (exists $cache->{$f}) { 142 $cache->{$f}->{entries} = {}; 143 $cache->{$f}->{nonempty} = 0; 144 } 145} 146 147sub compute_closure 148{ 149 my ($class, @seed) = @_; 150 151 my @todo = @seed; 152 my %done = (); 153 154 while (my $pkgname = pop @todo) { 155 next if $done{$pkgname}; 156 $done{$pkgname} = 1; 157 for my $dep ($class->new($pkgname)->list) { 158 next if defined $done{$dep}; 159 push(@todo, $dep); 160 } 161 } 162 return keys %done; 163} 164 165package OpenBSD::RequiredBy; 166our @ISA=qw(OpenBSD::RequirementList); 167use OpenBSD::PackageInfo; 168 169sub filename() { REQUIRED_BY }; 170 171package OpenBSD::Requiring; 172our @ISA=qw(OpenBSD::RequirementList); 173use OpenBSD::PackageInfo; 174 175sub filename() { REQUIRING }; 176 1771; 178