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