1# ex:ts=8 sw=4: 2# $OpenBSD: Dependencies.pm,v 1.23 2007/05/14 09:49:27 espie Exp $ 3# 4# Copyright (c) 2005-2007 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 18use strict; 19use warnings; 20 21package OpenBSD::Dependencies; 22 23use OpenBSD::PackageName; 24use OpenBSD::PackageInfo; 25use OpenBSD::SharedLibs; 26use OpenBSD::Error; 27use OpenBSD::Interactive; 28 29sub find_candidate 30{ 31 my $spec = shift; 32 my @candidates = $spec->match(@_); 33 if (@candidates >= 1) { 34 return $candidates[0]; 35 } else { 36 return undef; 37 } 38} 39 40sub solver 41{ 42 my $class = shift; 43 bless {}, $class; 44} 45 46sub solve 47{ 48 my ($self, $state, $handle, @extra) = @_; 49 my $plist = $handle->{plist}; 50 my $verbose = $state->{verbose}; 51 my $to_register = $handle->{solved_dependencies} = {}; 52 my $to_install = {}; 53 for my $fullname (@extra) { 54 $to_install->{OpenBSD::PackageName::url2pkgname($fullname)} = 55 $fullname; 56 } 57 58 my @deps; 59 60 for my $dep (@{$plist->{depend}}) { 61 my $spec = $dep->spec; 62 if ($state->{replace}) { 63 my $v = find_candidate($spec, keys %{$to_install}); 64 if ($v) { 65 push(@deps, $to_install->{$v}); 66 $to_register->{$v} = 1; 67 next; 68 } 69 } 70 71 my $v = find_candidate($spec, installed_packages()); 72 if ($v) { 73 $to_register->{$v} = 1; 74 next; 75 } 76 if (!$state->{replace}) { 77 my $v = find_candidate($spec, keys %{$to_install}); 78 if ($v) { 79 push(@deps, $to_install->{$v}); 80 $to_register->{$v} = 1; 81 next; 82 } 83 } 84 require OpenBSD::PackageLocator; 85 86 # try with list of available packages 87 my @candidates = OpenBSD::PackageLocator->match($spec); 88 if (!$state->{forced}->{allversions}) { 89 @candidates = OpenBSD::PackageName::keep_most_recent(@candidates); 90 } 91 # one single choice 92 if (@candidates == 1) { 93 push(@deps, $candidates[0]); 94 $to_register->{$candidates[0]} = 1; 95 next; 96 } 97 if (@candidates > 1) { 98 # put default first if available 99 @candidates = ((grep {$_ eq $dep->{def}} @candidates), 100 (sort (grep {$_ ne $dep->{def}} @candidates))); 101 my $choice = 102 OpenBSD::Interactive::ask_list('Ambiguous: choose dependency for '.$plist->pkgname().': ', 103 $state->{interactive}, @candidates); 104 push(@deps, $choice); 105 $to_register->{$choice} = 1; 106 next; 107 } 108 # can't get a list of packages, assume default 109 # will be there. 110 push(@deps, $dep->{def}); 111 $to_register->{$dep->{def}} = 1; 112 } 113 114 if ($verbose && %$to_register) { 115 print "Dependencies for ", $plist->pkgname, " resolve to: ", 116 join(', ', keys %$to_register); 117 print " (todo: ", join(',', @deps), ")" if @deps > 0; 118 print "\n"; 119 } 120 return @deps; 121} 122 123sub check_lib_spec 124{ 125 my ($base, $spec, $dependencies) = @_; 126 my @r = OpenBSD::SharedLibs::lookup_libspec($base, $spec); 127 for my $candidate (@r) { 128 if ($dependencies->{$candidate}) { 129 return $candidate; 130 } 131 } 132 return; 133} 134 135sub find_old_lib 136{ 137 my ($state, $base, $pattern, $lib, $dependencies) = @_; 138 139 my $spec = OpenBSD::PkgSpec->new(".libs-".$pattern); 140 for my $try ($spec->match(installed_packages())) { 141 OpenBSD::SharedLibs::add_package_libs($try); 142 if (check_lib_spec($base, $lib, {$try => 1})) { 143 $dependencies->{$try} = 1; 144 return "$try($lib)"; 145 } 146 } 147 return; 148} 149 150sub lookup_library 151{ 152 my ($state, $lib, $plist, $dependencies, $done) = @_; 153 154 my $r = check_lib_spec($plist->localbase, $lib, $dependencies); 155 if ($r) { 156 print "found libspec $lib in $r\n" if $state->{very_verbose}; 157 return 1; 158 } 159 if ($lib !~ m|/|) { 160 161 OpenBSD::SharedLibs::add_system_libs($state->{destdir}); 162 for my $dir (OpenBSD::SharedLibs::system_dirs()) { 163 if (check_lib_spec($dir, $lib, {system => 1})) { 164 print "found libspec $lib in $dir/lib\n" if $state->{very_verbose}; 165 return 1; 166 } 167 } 168 } 169 for my $dep (@{$plist->{depends}}) { 170 $r = find_old_lib($state, $plist->localbase, $dep->{pattern}, $lib, $dependencies); 171 if ($r) { 172 print "found libspec $lib in old package $r\n" if $state->{verbose}; 173 return 1; 174 } 175 } 176 # lookup through the full tree... 177 my @todo = keys %$dependencies; 178 while (my $dep = pop @todo) { 179 require OpenBSD::RequiredBy; 180 181 next if $done->{$dep}; 182 $done->{$dep} = 1; 183 for my $dep2 (OpenBSD::Requiring->new($dep)->list) { 184 push(@todo, $dep2) unless $done->{$dep2}; 185 } 186 next if $dependencies->{$dep}; 187 OpenBSD::SharedLibs::add_package_libs($dep); 188 if (check_lib_spec($plist->localbase, $lib, {$dep => 1})) { 189 print "found libspec $lib in dependent package $dep\n" if $state->{verbose}; 190 $dependencies->{$dep} = 1; 191 return 1; 192 } 193 } 194 195 print "libspec $lib not found\n" if $state->{very_verbose}; 196 return; 197} 198 199 2001; 201