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