138727c08Sespie# ex:ts=8 sw=4: 2*35d93a1aSespie# $OpenBSD: Update.pm,v 1.171 2023/10/07 09:10:03 espie Exp $ 338727c08Sespie# 445019a4aSespie# Copyright (c) 2004-2014 Marc Espie <espie@openbsd.org> 538727c08Sespie# 638727c08Sespie# Permission to use, copy, modify, and distribute this software for any 738727c08Sespie# purpose with or without fee is hereby granted, provided that the above 838727c08Sespie# copyright notice and this permission notice appear in all copies. 938727c08Sespie# 1038727c08Sespie# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1138727c08Sespie# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1238727c08Sespie# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1338727c08Sespie# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1438727c08Sespie# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1538727c08Sespie# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 160fbefeddSespie 17039cbdaaSespieuse v5.36; 1838727c08Sespie 19e05ce761Sespiepackage OpenBSD::Handle; 20039cbdaaSespiesub update($self, $updater, $set, $state) 21e05ce761Sespie{ 22e05ce761Sespie 23e05ce761Sespie return $updater->process_handle($set, $self, $state); 24e05ce761Sespie} 25e05ce761Sespie 26d47afce4Sespie# TODO hint and hint2 are horrible names 27e05ce761Sespiepackage OpenBSD::hint; 28039cbdaaSespiesub update($self, $updater, $set, $state) 29e05ce761Sespie{ 30e05ce761Sespie 31e05ce761Sespie return $updater->process_hint($set, $self, $state); 32e05ce761Sespie} 33e05ce761Sespie 34e05ce761Sespiepackage OpenBSD::hint2; 35039cbdaaSespiesub update($self, $updater, $set, $state) 36e05ce761Sespie{ 37e05ce761Sespie return $updater->process_hint2($set, $self, $state); 38e05ce761Sespie} 39e05ce761Sespie 4038727c08Sespiepackage OpenBSD::Update; 41646f71ecSespieuse OpenBSD::PackageInfo; 42646f71ecSespieuse OpenBSD::PackageName; 437ba739cfSbernduse OpenBSD::Error; 44eb5eab35Sespieuse OpenBSD::UpdateSet; 4538727c08Sespie 46039cbdaaSespiesub new($class) 4738727c08Sespie{ 48eb5eab35Sespie return bless {}, $class; 4959ccc3c8Sespie} 5059ccc3c8Sespie 51039cbdaaSespiesub add_handle($self, $set, $old, $n) 52e05ce761Sespie{ 5328dfaf57Sespie $old->{update_found} = $n; 54e05ce761Sespie $set->add_newer($n); 55e05ce761Sespie} 56e05ce761Sespie 57039cbdaaSespiesub add_location($self, $set, $handle, $location) 5859ccc3c8Sespie{ 59e05ce761Sespie $self->add_handle($set, $handle, 60e05ce761Sespie OpenBSD::Handle->from_location($location)); 6159ccc3c8Sespie} 6259ccc3c8Sespie 63039cbdaaSespiesub look_for_debug($self, $set, $oldname, $newname, $state) 6492bd379cSespie{ 6592bd379cSespie # hurdles to pass before adding debug packages 6692bd379cSespie return unless $state->{debug_packages}; 6792bd379cSespie 6892bd379cSespie return if $state->tracker->is_to_update("debug-".$oldname); 6992bd379cSespie my $dbg = "debug-".$newname; 7092bd379cSespie my $l = $set->match_locations(OpenBSD::Search::Exact->new($dbg)); 7192bd379cSespie # TODO if @$l == 0, I should look for other packages with similar names 7292bd379cSespie # just so I can warn for out-of-date/shearing in the mirrors. 7392bd379cSespie return if @$l != 1; 7492bd379cSespie $set->add_newer(OpenBSD::Handle->from_location($l->[0])); 7592bd379cSespie} 7692bd379cSespie 77039cbdaaSespiesub found_update($self, $set, $old, $location, $state) 7892bd379cSespie{ 7992bd379cSespie $self->add_location($set, $old, $location); 8092bd379cSespie $self->look_for_debug($set, $old->pkgname, $location->name, $state); 8192bd379cSespie} 8292bd379cSespie 83039cbdaaSespiesub progress_message($self, $state, @r) 84b7510ac8Sespie{ 854b4be44cSespie my $msg = $state->f(@r); 862d4feb81Sespie $msg .= $state->ntogo_string; 87b7510ac8Sespie $state->progress->message($msg); 88e74b30b0Sespie $state->say($msg) if $state->verbose >= 2; 89b7510ac8Sespie} 90b7510ac8Sespie 91039cbdaaSespiesub process_handle($self, $set, $h, $state) 9259ccc3c8Sespie{ 93cc96d067Sespie my $pkgname = $h->pkgname; 9459ccc3c8Sespie 95c9826cdbSespie if ($pkgname =~ m/^\.libs\d*\-/o) { 96eb5eab35Sespie return 0; 971548337dSespie } 98bb4ec1ceSespie 996fe055f5Sespie if (!$set->{quirks}) { 10042cea554Sespie my $base = 0; 101875cde4bSespie $state->run_quirks( 102039cbdaaSespie sub($quirks) { 103875cde4bSespie $base = $quirks->is_base_system($h, $state); 104875cde4bSespie }); 10542cea554Sespie if ($base) { 10642cea554Sespie $h->{update_found} = OpenBSD::Handle->system; 10742cea554Sespie $set->{updates}++; 10842cea554Sespie return 1; 10942cea554Sespie } 1106fe055f5Sespie } 111f5729cc1Sespie 112bb4ec1ceSespie my $plist = OpenBSD::PackingList->from_installation($pkgname, 113bb4ec1ceSespie \&OpenBSD::PackingList::UpdateInfoOnly); 114bb4ec1ceSespie if (!defined $plist) { 1157e83eca3Sespie $state->fatal("can't locate #1", $pkgname); 116bb4ec1ceSespie } 117bb4ec1ceSespie 118afe6de13Sespie if ($plist->has('firmware') && !$state->defines('FW_UPDATE')) { 119d2decf4fSespie $set->move_kept($h); 120*35d93a1aSespie $h->{is_firmware} = 1; 121d2decf4fSespie return 0; 122d2decf4fSespie } 123d2decf4fSespie 124d2decf4fSespie# if (defined $plist->{url}) { 125d2decf4fSespie# my $repo; 12601734cf0Sespie# ($repo, undef) = $state->repo->path_parse($plist->{url}->name); 127d2decf4fSespie# $set->add_repositories($repo); 128d2decf4fSespie# } 1296f68aac1Sespie my @search = (); 130fdd1f733Sespie 131fdd1f733Sespie my $sname = $pkgname; 132fdd1f733Sespie while ($sname =~ s/^partial\-//o) { 133fdd1f733Sespie } 134fdd1f733Sespie push(@search, OpenBSD::Search::Stem->split($sname)); 1350fe785c3Sespie 1366fe055f5Sespie if (!$set->{quirks}) { 137875cde4bSespie $state->run_quirks( 138039cbdaaSespie sub($quirks) { 139875cde4bSespie $quirks->tweak_search(\@search, $h, $state); 140875cde4bSespie }); 1416fe055f5Sespie } 14224dd5be2Sespie my $oldfound = 0; 1432f37e678Sjeremy my @skipped_locs = (); 1445b0d5555Sespie 1455bd96a97Sespie # XXX this is nasty: maybe we added an old set to update 1465bd96a97Sespie # because of conflicts, in which case the pkgpath + 1475bd96a97Sespie # conflict should be enough to "match". 1485bd96a97Sespie for my $n ($set->newer) { 149d7c67ec8Sespie if (($state->{hard_replace} || 150d7c67ec8Sespie $n->location->update_info->match_pkgpath($plist)) && 15146373398Sespie $n->conflict_list->conflicts_with($sname)) { 1525bd96a97Sespie $self->add_handle($set, $h, $n); 1535bd96a97Sespie return 1; 1545bd96a97Sespie } 1555bd96a97Sespie } 156fb5688e8Sespie # XXX all that code conveniently forgets about old versions, while 157fb5688e8Sespie # marking them as "normal". 1583a50f0a9Sjmc # there should be some error path when we consistently fail to find 159fb5688e8Sespie # an equal-or-newer version in our repository, so that pkg_add has 160fb5688e8Sespie # consistent exit codes. 161a409537dSespie if (!$state->defines('downgrade')) { 162fdd1f733Sespie push(@search, OpenBSD::Search::FilterLocation->more_recent_than($sname, \$oldfound)); 163b6a296a5Sespie } 164e451b54dSespie push(@search, OpenBSD::Search::FilterLocation->new( 165039cbdaaSespie sub($l) { 166e451b54dSespie if (@$l == 0) { 167e451b54dSespie return $l; 16825f8e080Sespie } 1695b0d5555Sespie my @l2 = (); 170fc9f0195Sespie for my $loc (@$l) { 171fc9f0195Sespie if (!$loc) { 172646f71ecSespie next; 173646f71ecSespie } 174fc9f0195Sespie my $p2 = $loc->update_info; 175646f71ecSespie if (!$p2) { 176646f71ecSespie next; 177646f71ecSespie } 178646f71ecSespie if ($p2->has('arch')) { 179646f71ecSespie unless ($p2->{arch}->check($state->{arch})) { 1803ecf5ca9Sespie $loc->forget; 181646f71ecSespie next; 182646f71ecSespie } 183646f71ecSespie } 1845004679dSespie if (!$plist->match_pkgpath($p2)) { 1852f37e678Sjeremy push(@skipped_locs, $loc); 1865004679dSespie next 1875004679dSespie } 1888b437e75Sespie my $r = $plist->signature->compare($p2->signature, $state); 189a409537dSespie if (defined $r && $r > 0 && !$state->defines('downgrade')) { 190f11e17d2Sespie $oldfound = 1; 1913ecf5ca9Sespie $loc->forget; 1925b0d5555Sespie next; 193646f71ecSespie } 194fc9f0195Sespie push(@l2, $loc); 195646f71ecSespie } 196e451b54dSespie return \@l2; 1976f68aac1Sespie })); 198646f71ecSespie 199a409537dSespie if (!$state->defines('allversions')) { 200e451b54dSespie push(@search, OpenBSD::Search::FilterLocation->keep_most_recent); 201e451b54dSespie } 2025b0d5555Sespie 20388e41ea0Sespie my $l = $set->match_locations(@search); 2042f37e678Sjeremy 2052f37e678Sjeremy for my $loc (@skipped_locs) { 2062f37e678Sjeremy if (@$l == 0 && $state->verbose) { 2072f37e678Sjeremy $self->say_skipped_packages($state, $plist, 2082f37e678Sjeremy $loc->update_info); 2092f37e678Sjeremy } 2102f37e678Sjeremy $loc->forget; 2112f37e678Sjeremy } 2122f37e678Sjeremy 213e451b54dSespie if (@$l == 0) { 21424dd5be2Sespie if ($oldfound) { 2152172b28bSespie $set->move_kept($h); 216b7510ac8Sespie $self->progress_message($state, 2174b4be44cSespie "No need to update #1", $pkgname); 21892bd379cSespie $self->look_for_debug($set, $pkgname, $pkgname, $state); 21924dd5be2Sespie return 0; 22024dd5be2Sespie } 221eb5eab35Sespie return undef; 2225b0d5555Sespie } 2232d4feb81Sespie $state->say("Update candidates: #1 -> #2#3", $pkgname, 2242d4feb81Sespie join(' ', map {$_->name} @$l), $state->ntogo_string) 2252d4feb81Sespie if $state->verbose; 226646f71ecSespie 22781dcf8b8Sespie my $r = $state->choose_location($pkgname, $l); 22881dcf8b8Sespie if (defined $r) { 22992bd379cSespie $self->found_update($set, $h, $r, $state); 230eb5eab35Sespie return 1; 231646f71ecSespie } else { 232646f71ecSespie $state->{issues} = 1; 233eb5eab35Sespie return undef; 23495cbd9edSespie } 23595cbd9edSespie} 236023fe338Sespie 237039cbdaaSespiesub say_skipped_packages($self, $state, $o, $n) 2382f37e678Sjeremy{ 2392f37e678Sjeremy my $o_name = $o->pkgname; 2402f37e678Sjeremy my @o_ps = map { @{$o->pkgpath->{$_}} } keys %{$o->pkgpath}; 2412f37e678Sjeremy my $o_pp = join(" ", map {$_->fullpkgpath} @o_ps); 2422f37e678Sjeremy 2432f37e678Sjeremy my $n_name = $n->pkgname; 2442f37e678Sjeremy my @n_ps = map { @{$n->pkgpath->{$_}} } keys %{$n->pkgpath}; 2452f37e678Sjeremy my $n_pp= join(" ", map {$_->fullpkgpath} @n_ps); 2462f37e678Sjeremy 2472f37e678Sjeremy my $t = "Skipping #1 (update candidate for #2)"; 2482f37e678Sjeremy $t .= "\n\t#2 pkgpaths: #4\n\t#1 pkgpaths: #3"; 2492f37e678Sjeremy 2502f37e678Sjeremy $state->say($t, $n_name, $o_name, $n_pp, $o_pp); 2512f37e678Sjeremy} 2522f37e678Sjeremy 253039cbdaaSespiesub find_nearest($base, $locs) 254612a857cSespie{ 255612a857cSespie my $pkgname = OpenBSD::PackageName->from_string($base); 256612a857cSespie return undef if !defined $pkgname->{version}; 257612a857cSespie my @sorted = sort {$a->pkgname->{version}->compare($b->pkgname->{version}) } @$locs; 258612a857cSespie if ($sorted[0]->pkgname->{version}->compare($pkgname->{version}) > 0) { 259612a857cSespie return $sorted[0]; 260612a857cSespie } 261612a857cSespie if ($sorted[-1]->pkgname->{version}->compare($pkgname->{version}) < 0) { 262612a857cSespie return $sorted[-1]; 263612a857cSespie } 264612a857cSespie return undef; 265612a857cSespie} 266612a857cSespie 267039cbdaaSespiesub process_hint($self, $set, $hint, $state) 2687d63c3f8Sespie{ 2697d63c3f8Sespie my $l; 27042caadbcSespie my $hint_name = $hint->pkgname; 2717d63c3f8Sespie my $k = OpenBSD::Search::FilterLocation->keep_most_recent; 2727d63c3f8Sespie # first try to find us exactly 2737d63c3f8Sespie 2744b4be44cSespie $self->progress_message($state, "Looking for #1", $hint_name); 27588e41ea0Sespie $l = $set->match_locations(OpenBSD::Search::Exact->new($hint_name), $k); 2767d63c3f8Sespie if (@$l == 0) { 27742caadbcSespie my $t = $hint_name; 2787d63c3f8Sespie $t =~ s/\-\d([^-]*)\-?/--/; 2798b6f798cSespie my @search = (OpenBSD::Search::Stem->new($t)); 2808b6f798cSespie $state->run_quirks( 281039cbdaaSespie sub($quirks) { 2828b6f798cSespie $quirks->tweak_search(\@search, $hint, $state); 2838b6f798cSespie }); 2848b6f798cSespie $l = $set->match_locations(@search, $k); 2857d63c3f8Sespie } 286612a857cSespie if (@$l > 1) { 287612a857cSespie my $r = find_nearest($hint_name, $l); 288612a857cSespie if (defined $r) { 28992bd379cSespie $self->found_update($set, $hint, $r, $state); 290612a857cSespie return 1; 291612a857cSespie } 292612a857cSespie } 29342caadbcSespie my $r = $state->choose_location($hint_name, $l); 2947d63c3f8Sespie if (defined $r) { 29592bd379cSespie $self->found_update($set, $hint, $r, $state); 2967d4e60deSespie OpenBSD::Add::tag_user_packages($set); 2977d63c3f8Sespie return 1; 2987d63c3f8Sespie } else { 2997d63c3f8Sespie return 0; 3007d63c3f8Sespie } 3017d63c3f8Sespie} 3027d63c3f8Sespie 303e05ce761Sespiemy $cache = {}; 304e05ce761Sespie 305039cbdaaSespiesub process_hint2($self, $set, $hint, $state) 306e05ce761Sespie{ 307e05ce761Sespie my $pkgname = $hint->pkgname; 308396f4403Sespie my $pkg2; 3093eadd976Sespie if ($pkgname =~ m/[\/\:]/o) { 31088e41ea0Sespie my $repo; 311396f4403Sespie ($repo, $pkg2) = $state->repo->path_parse($pkgname); 31288e41ea0Sespie $set->add_repositories($repo); 313396f4403Sespie } else { 314396f4403Sespie $pkg2 = $pkgname; 315396f4403Sespie } 316396f4403Sespie if (OpenBSD::PackageName::is_stem($pkg2)) { 317396f4403Sespie my $l = $state->updater->stem2location($set, $pkg2, $state, 318f5729cc1Sespie $set->{quirks}); 319e05ce761Sespie if (defined $l) { 3202338bd65Sespie $self->add_location($set, $hint, $l); 321e9bfaee7Sespie $self->look_for_debug($set, $l->name, $l->name, $state); 322e05ce761Sespie } else { 323e05ce761Sespie return undef; 324e05ce761Sespie } 325e05ce761Sespie } else { 326e05ce761Sespie if (!defined $cache->{$pkgname}) { 327e05ce761Sespie $self->add_handle($set, $hint, OpenBSD::Handle->create_new($pkgname)); 328e05ce761Sespie $cache->{$pkgname} = 1; 329396f4403Sespie $pkg2 =~ s/\.tgz$//; 330396f4403Sespie $self->look_for_debug($set, $pkg2, $pkg2, $state); 331e05ce761Sespie } 332e05ce761Sespie } 333e05ce761Sespie OpenBSD::Add::tag_user_packages($set); 334e05ce761Sespie return 1; 335e05ce761Sespie} 336e05ce761Sespie 337039cbdaaSespiesub process_set($self, $set, $state) 338f1088463Sespie{ 33998b10e60Sespie my @problems = (); 340e05ce761Sespie for my $h ($set->older, $set->hints) { 34128dfaf57Sespie next if $h->{update_found}; 3425bd96a97Sespie if (!defined $h->update($self, $set, $state)) { 34398b10e60Sespie push(@problems, $h->pkgname); 344f1088463Sespie } 345f1088463Sespie } 34698b10e60Sespie if (@problems > 0) { 3477dd5c23bSespie $state->tracker->cant($set) if !$set->{quirks}; 348b7510ac8Sespie if ($set->{updates} != 0) { 349861c3ddfSespie $state->say("Can't update #1: no update found for #2", 3507e83eca3Sespie $set->print, join(',', @problems)); 351b7510ac8Sespie } 352f1088463Sespie return 0; 3530849d6feSespie } elsif ($set->{updates} == 0) { 3547dd5c23bSespie $state->tracker->uptodate($set); 355f1088463Sespie return 0; 356f1088463Sespie } 357e05ce761Sespie $state->tracker->add_set($set); 358f1088463Sespie return 1; 359f1088463Sespie} 360f1088463Sespie 361039cbdaaSespiesub stem2location($self, $locator, $name, $state, $is_quirks = 0) 362e05ce761Sespie{ 36388e41ea0Sespie my $l = $locator->match_locations(OpenBSD::Search::Stem->new($name)); 364a409537dSespie if (@$l > 1 && !$state->defines('allversions')) { 365e05ce761Sespie $l = OpenBSD::Search::FilterLocation->keep_most_recent->filter_locations($l); 366e05ce761Sespie } 367f5729cc1Sespie return $state->choose_location($name, $l, $is_quirks); 368e05ce761Sespie} 369e05ce761Sespie 37038727c08Sespie1; 371