1# ex:ts=8 sw=4:
2# $OpenBSD: RequiredBy.pm,v 1.26 2014/03/18 18:53:29 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 fill_entries
26{
27	my $self = shift;
28	if (!exists $self->{entries}) {
29		my $l = $self->{entries} = {};
30
31		if (-f $self->{filename}) {
32			open(my $fh, '<', $self->{filename}) or
33			    croak ref($self),
34			    	": reading $self->{filename}: $!";
35			while(<$fh>) {
36				s/\s+$//o;
37				next if /^$/o;
38				chomp;
39				$l->{$_} = 1;
40			}
41			close($fh);
42			$self->{nonempty} = 1;
43		} else {
44			$self->{nonempty} = 0;
45		}
46	}
47}
48
49sub synch
50{
51	my $self = shift;
52	return $self if $main::not;
53
54	if (!unlink $self->{filename}) {
55		if ($self->{nonempty}) {
56		    croak ref($self), ": erasing $self->{filename}: $!";
57		}
58	}
59	if (%{$self->{entries}}) {
60		open(my $fh, '>', $self->{filename}) or
61		    croak ref($self), ": writing $self->{filename}: $!";
62		while (my ($k, $v) = each %{$self->{entries}}) {
63			print $fh "$k\n";
64		}
65		close($fh) or
66		    croak ref($self), ": closing $self->{filename}: $!";
67		$self->{nonempty} = 1;
68	} else {
69		$self->{nonempty} = 0;
70	}
71	return $self;
72}
73
74sub list
75{
76	my $self = shift;
77
78	if (wantarray) {
79		$self->fill_entries;
80		return keys %{$self->{entries}};
81	} else {
82		if (exists $self->{entries}) {
83			return %{$self->{entries}} ? 1 : 0;
84		} elsif (!exists $self->{nonempty}) {
85			$self->{nonempty} = -f $self->{filename} ? 1 : 0;
86		}
87		return $self->{nonempty};
88	}
89}
90
91sub erase
92{
93	my $self = shift;
94	$self->{entries} = {};
95	$self->synch;
96}
97
98sub delete
99{
100	my ($self, @pkgnames) = @_;
101	$self->fill_entries($self);
102	for my $pkg (@pkgnames) {
103		delete $self->{entries}->{$pkg};
104	}
105	$self->synch;
106}
107
108sub add
109{
110	my ($self, @pkgnames) = @_;
111	$self->fill_entries($self);
112	for my $pkg (@pkgnames) {
113		$self->{entries}->{$pkg} = 1;
114	}
115	$self->synch;
116}
117
118my $cache = {};
119
120sub new
121{
122	my ($class, $pkgname) = @_;
123	my $f = installed_info($pkgname).$class->filename;
124	if (!exists $cache->{$f}) {
125		return $cache->{$f} = bless { filename => $f }, $class;
126	}
127	return $cache->{$f};
128}
129
130sub forget
131{
132	my ($class, $dir) = @_;
133	my $f = $dir.$class->filename;
134	if (exists $cache->{$f}) {
135		$cache->{$f}->{entries} = {};
136		$cache->{$f}->{nonempty} = 0;
137	}
138}
139
140sub compute_closure
141{
142	my ($class, @seed) = @_;
143
144	my @todo = @seed;
145	my %done = ();
146
147	while (my $pkgname = pop @todo) {
148		next if $done{$pkgname};
149		$done{$pkgname} = 1;
150		for my $dep ($class->new($pkgname)->list) {
151			next if defined $done{$dep};
152			push(@todo, $dep);
153		}
154	}
155	return keys %done;
156}
157
158package OpenBSD::RequiredBy;
159our @ISA=qw(OpenBSD::RequirementList);
160use OpenBSD::PackageInfo;
161
162sub filename() { REQUIRED_BY };
163
164package OpenBSD::Requiring;
165our @ISA=qw(OpenBSD::RequirementList);
166use OpenBSD::PackageInfo;
167
168sub filename() { REQUIRING };
169
1701;
171