1# ex:ts=8 sw=4:
2# $OpenBSD: ForwardDependencies.pm,v 1.18 2023/06/13 09:07:17 espie Exp $
3#
4# Copyright (c) 2009 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
17# handling of forward dependency adjustments
18
19use v5.36;
20
21package OpenBSD::ForwardDependencies;
22
23require OpenBSD::RequiredBy;
24
25sub find($class, $set)
26{
27	my $forward = {};
28	for my $old ($set->older) {
29		for my $f (OpenBSD::RequiredBy->new($old->pkgname)->list) {
30			next if defined $set->{older}{$f};
31			$forward->{$f} = 1;
32		}
33	}
34	bless { forward => $forward, set => $set}, $class;
35}
36
37sub find_belated_update($set, $state, $old)
38{
39	for my $n ($set->newer) {
40		if ($n->conflict_list->conflicts_with($old->pkgname)) {
41			if (defined $old->{update_found}) {
42				$state->errsay("Ambiguous update #1 vs #2",
43				    $n->pkgname,
44				    $old->{update_found}->pkgname);
45			} else {
46				$old->{update_found} = $n;
47			}
48		}
49	}
50	return $old->{update_found};
51}
52
53sub adjust($self, $state)
54{
55	my $set = $self->{set};
56
57	for my $f (keys %{$self->{forward}}) {
58		my $deps_f = OpenBSD::Requiring->new($f);
59		for my $check ($deps_f->list) {
60			my $h = $set->{older}{$check};
61			next unless defined $h;
62			my $r = $h->{update_found};
63			if (!defined $r) {
64				$r =find_belated_update($set, $state, $h);
65			}
66			if (!defined $r) {
67				$state->errsay("XXX #1", $check);
68				$deps_f->delete($check);
69				next;
70			}
71			# XXX is_real corresponds to actual package dependencies
72			# for stuff moving to the base system, we got
73			# a pseudo handle which shouldn't be recorded.
74			my $p = $r->pkgname;
75			$state->say("Adjusting #1 to #2 in #3", $check, $p, $f)
76				if $state->verbose >= 3;
77			if ($check ne $p) {
78				if ($r->is_real) {
79					$deps_f->delete($check)->add($p);
80				} else {
81					$deps_f->delete($check);
82				}
83			}
84			if ($r->is_real) {
85				OpenBSD::RequiredBy->new($p)->add($f);
86			}
87		}
88	}
89}
90
91sub dump($self, $result, $state)
92{
93	$state->say("#1 forward dependencies:", $self->{set}->print);
94	while (my ($pkg, $l) = each %$result) {
95		if (@$l == 1) {
96			$state->say("| Dependency of #1 on #2 doesn't match",
97			    $pkg, $l->[0]{pattern});
98		} else {
99			my $deps = join(',', map {$_->{pattern}} @$l);
100			$state->say("| Dependencies of #1 on #2 don't match",
101			    $pkg, $deps);
102		}
103	}
104}
105
106sub check($self, $state)
107{
108	my @r = keys %{$self->{forward}};
109	my $set = $self->{set};
110	my $result = {};
111	return $result if @r == 0;
112	$state->say("Verifying dependencies still match for #1",
113	    join(', ', @r)) if $state->verbose >= 2;
114
115	my @new = ($set->newer_names, $set->kept_names);
116	my @old = $set->older_names;
117
118	for my $f (@r) {
119		my $p2 = OpenBSD::PackingList->from_installation(
120		    $f, \&OpenBSD::PackingList::DependOnly);
121		if (!defined $p2) {
122			$state->errsay("Error: #1 missing from installation",
123			    $f);
124		} else {
125			$p2->check_forward_dependency($f, \@old, \@new,
126			    $result);
127		}
128	}
129	if (%$result) {
130		$self->dump($result, $state);
131	}
132	return $result;
133}
134
135package OpenBSD::PackingElement;
136sub check_forward_dependency($, $, $, $, $)
137{
138}
139
140package OpenBSD::PackingElement::Dependency;
141sub check_forward_dependency($self, $f, $old, $new, $r)
142{
143	# nothing to validate if old dependency doesn't concern us.
144	return unless $self->spec->filter(@$old);
145	# nothing to do if new dependency just matches
146	return if $self->spec->filter(@$new);
147
148	push(@{$r->{$f}}, $self);
149}
150
1511;
152