xref: /openbsd/usr.sbin/pkg_add/OpenBSD/Tracker.pm (revision e5dd7070)
1# ex:ts=8 sw=4:
2# $OpenBSD: Tracker.pm,v 1.29 2018/10/22 10:29:06 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# In order to deal with dependencies, we have to know what's actually installed,
18# and what can actually be updated.
19# Specifically, to solve a dependency:
20# - look at packages to_install
21# - look at installed packages
22#   - if it's marked to_update, then we must process the update first
23#   - if it's marked as installed, or as cant_update, or uptodate, then
24#   we can use the installed packages.
25#   - otherwise, in update mode, put a request to update the package (e.g.,
26#   create a new UpdateSet.
27
28# the Tracker object does maintain that information globally so that
29# Update/Dependencies can do its job.
30
31use strict;
32use warnings;
33
34package OpenBSD::Tracker;
35our $s;
36
37sub new
38{
39	my $class = shift;
40	return $s = bless {}, $class;
41}
42
43sub dump2
44{
45	my $set = shift;
46	if (defined $set->{merged}) {
47		return "merged from ".dump2($set->{merged});
48	}
49	return join("/",
50	    join(",", $set->newer_names),
51	    join(",", $set->older_names),
52	    join(",", $set->kept_names),
53	    join(",", $set->hint_names));
54}
55
56sub dump
57{
58	return unless defined $s;
59	for my $l ('to_install', 'to_update') {
60		next unless defined $s->{$l};
61		print STDERR "$l:\n";
62		while (my ($k, $e) = each %{$s->{$l}}) {
63			print STDERR "\t$k => ", dump2($e), "\n";
64		}
65	}
66	for my $l ('uptodate', 'can_install', 'cant_update') {
67		next unless defined $s->{$l};
68		print STDERR "$l: ", join(' ', keys %{$s->{$l}}), "\n";
69	}
70}
71
72sub sets_todo
73{
74	my ($self, $offset) = @_;
75	return sprintf("%u/%u", (scalar keys %{$self->{done}})-$offset,
76		scalar keys %{$self->{total}});
77}
78
79sub handle_set
80{
81	my ($self, $set) = @_;
82	$self->{total}{$set} = 1;
83	if ($set->{finished}) {
84		$self->{done}{$set} = 1;
85	}
86}
87
88sub known
89{
90	my ($self, $set) = @_;
91	for my $n ($set->newer, $set->older, $set->hints) {
92		$self->{known}{$n->pkgname} = 1;
93	}
94}
95
96sub add_set
97{
98	my ($self, $set) = @_;
99	for my $n ($set->newer) {
100		$self->{to_install}{$n->pkgname} = $set;
101	}
102	for my $n ($set->older, $set->hints) {
103		$self->{to_update}{$n->pkgname} = $set;
104	}
105	for my $n ($set->kept) {
106		delete $self->{to_update}{$n->pkgname};
107		$self->{uptodate}{$n->pkgname} = 1;
108	}
109	$self->known($set);
110	$self->handle_set($set);
111	return $self;
112}
113
114sub todo
115{
116	my ($self, @sets) = @_;
117	for my $set (@sets) {
118		$self->add_set($set);
119	}
120	return $self;
121}
122
123sub remove_set
124{
125	my ($self, $set) = @_;
126	for my $n ($set->newer) {
127		delete $self->{to_install}{$n->pkgname};
128		delete $self->{cant_install}{$n->pkgname};
129	}
130	for my $n ($set->kept, $set->older, $set->hints) {
131		delete $self->{to_update}{$n->pkgname};
132		delete $self->{cant_update}{$n->pkgname};
133	}
134	$self->handle_set($set);
135}
136
137sub uptodate
138{
139	my ($self, $set) = @_;
140	$set->{finished} = 1;
141	$self->remove_set($set);
142	for my $n ($set->older, $set->kept) {
143		$self->{uptodate}{$n->pkgname} = 1;
144	}
145}
146
147sub cant
148{
149	my ($self, $set) = @_;
150	$set->{finished} = 1;
151	$self->remove_set($set);
152	$self->known($set);
153	for my $n ($set->older) {
154		$self->{cant_update}{$n->pkgname} = 1;
155	}
156	for my $n ($set->newer) {
157		$self->{cant_install}{$n->pkgname} = 1;
158	}
159	for my $n ($set->kept) {
160		$self->{uptodate}{$n->pkgname} = 1;
161	}
162}
163
164sub done
165{
166	my ($self, $set) = @_;
167
168	$set->{finished} = 1;
169	$self->remove_set($set);
170	$self->known($set);
171
172	for my $n ($set->newer) {
173		$self->{uptodate}{$n->pkgname} = 1;
174		$self->{installed}{$n->pkgname} = 1;
175	}
176	for my $n ($set->kept) {
177		$self->{uptodate}{$n->pkgname} = 1;
178	}
179}
180
181sub is
182{
183	my ($self, $k, $pkg) = @_;
184
185	my $set = $self->{$k}{$pkg};
186	if (ref $set) {
187		return $set->real_set;
188	} else {
189		return $set;
190	}
191}
192
193sub is_known
194{
195	my ($self, $pkg) = @_;
196	return $self->is('known', $pkg);
197}
198
199sub is_installed
200{
201	my ($self, $pkg) = @_;
202	return $self->is('installed', $pkg);
203}
204
205sub is_to_update
206{
207	my ($self, $pkg) = @_;
208	return $self->is('to_update', $pkg);
209}
210
211sub cant_list
212{
213	my $self = shift;
214	return keys %{$self->{cant_update}};
215}
216
217sub cant_install_list
218{
219	my $self = shift;
220	return keys %{$self->{cant_install}};
221}
222
2231;
224