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