PackageLocator.pm revision 1.43
1# ex:ts=8 sw=4: 2# $OpenBSD: PackageLocator.pm,v 1.43 2005/10/22 13:11:55 espie Exp $ 3# 4# Copyright (c) 2003-2004 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# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18use strict; 19use warnings; 20 21package OpenBSD::PackageRepository; 22 23sub _new 24{ 25 my ($class, $address) = @_; 26 bless { baseurl => $address }, $class; 27} 28 29sub new 30{ 31 my ($class, $baseurl) = @_; 32 if ($baseurl =~ m/^ftp\:/i) { 33 return OpenBSD::PackageRepository::FTP->_new($baseurl); 34 } elsif ($baseurl =~ m/^http\:/i) { 35 return OpenBSD::PackageRepository::HTTP->_new($baseurl); 36 } elsif ($baseurl =~ m/^scp\:/i) { 37 return OpenBSD::PackageRepository::SCP->_new($baseurl); 38 } elsif ($baseurl =~ m/src\:/i) { 39 return OpenBSD::PackageRepository::Source->_new($baseurl); 40 } else { 41 return OpenBSD::PackageRepository::Local->_new($baseurl); 42 } 43} 44 45sub available 46{ 47 my $self = shift; 48 49 return @{$self->list()}; 50} 51 52sub wipe_info 53{ 54 my ($self, $pkg) = @_; 55 56 require File::Path; 57 58 my $dir = $pkg->{dir}; 59 if (defined $dir) { 60 61 File::Path::rmtree($dir); 62 delete $pkg->{dir}; 63 } 64} 65 66# by default, all objects may exist 67sub may_exist 68{ 69 return 1; 70} 71 72# by default, we don't track opened files for this key 73 74sub opened 75{ 76 undef; 77} 78 79sub close 80{ 81 my ($self, $object) = @_; 82 close($object->{fh}) if defined $object->{fh}; 83 $self->parse_problems($object->{errors}) if defined $object->{errors}; 84 $object->deref(); 85} 86 87sub make_room 88{ 89 my $self = shift; 90 91 # kill old files if too many 92 my $already = $self->opened(); 93 if (defined $already) { 94 # gc old objects 95 if (@$already >= $self->maxcount()) { 96 @$already = grep { defined $_->{fh} } @$already; 97 } 98 while (@$already >= $self->maxcount()) { 99 my $o = shift @$already; 100 $self->close($o); 101 } 102 } 103 return $already; 104} 105 106# open method that tracks opened files per-host. 107sub open 108{ 109 my ($self, $object) = @_; 110 111 return undef unless $self->may_exist($object->{name}); 112 113 # kill old files if too many 114 my $already = $self->make_room(); 115 my $fh = $self->open_pipe($object); 116 if (!defined $fh) { 117 return undef; 118 } 119 $object->{fh} = $fh; 120 if (defined $already) { 121 push @$already, $object; 122 } 123 return $fh; 124} 125 126sub find 127{ 128 my ($repository, $name, $arch, $srcpath) = @_; 129 $name.=".tgz" unless $name =~ m/\.tgz$/; 130 my $self = OpenBSD::PackageLocation->new($repository, $name); 131 132 return $self->openPackage($name, $arch); 133} 134 135sub grabPlist 136{ 137 my ($repository, $name, $arch, $code) = @_; 138 $name.=".tgz" unless $name =~ m/\.tgz$/; 139 my $self = OpenBSD::PackageLocation->new($repository, $name); 140 141 return $self->grabPlist($name, $arch, $code); 142} 143 144sub parse_problems 145{ 146 my ($self, $filename) = @_; 147 CORE::open(my $fh, '<', $filename); 148 my $baseurl = $self->{baseurl}; 149 local $_; 150 while(<$fh>) { 151 next if m/^(?:200|220|230|227|250|331|500|150)[\s\-]/; 152 next if m/^EPSV command not understood/; 153 next if m/^Trying [\d\.\:]+\.\.\./; 154 next if m/^Requesting \Q$baseurl\E/; 155 next if m/^Remote system type is\s+/; 156 next if m/^Connected to\s+/; 157 next if m/^remote\:\s+/; 158 next if m/^Using binary mode to transfer files/; 159 next if m/^Retrieving\s+/; 160 print STDERR "Error from $baseurl:\n", $_; 161 } 162 CORE::close($fh); 163 unlink $filename; 164} 165 166package OpenBSD::PackageRepository::Installed; 167our @ISA=qw(OpenBSD::PackageRepository); 168use OpenBSD::PackageInfo; 169 170sub new 171{ 172 bless {}, shift; 173} 174 175sub find 176{ 177 my ($repository, $name, $arch, $srcpath) = @_; 178 my $self; 179 180 if (is_installed($name)) { 181 $self = OpenBSD::PackageLocation->new($repository, $name); 182 $self->{dir} = installed_info($name); 183 } 184 return $self; 185} 186 187sub grabPlist 188{ 189 my ($repository, $name, $arch, $code) = @_; 190 require OpenBSD::PackingList; 191 return OpenBSD::PackingList->from_installation($name, $code); 192} 193 194sub available 195{ 196 return installed_packages(); 197} 198 199sub list 200{ 201 my @list = installed_packages(); 202 return \@list; 203} 204 205sub wipe_info 206{ 207} 208 209sub may_exist 210{ 211 my ($self, $name) = @_; 212 return is_installed($name); 213} 214 215package PackageRepository::Source; 216 217sub find 218{ 219 my ($repository, $name, $arch, $srcpath) = @_; 220 my $dir; 221 my $make; 222 if (defined $ENV{'MAKE'}) { 223 $make = $ENV{'MAKE'}; 224 } else { 225 $make = '/usr/bin/make'; 226 } 227 if (defined $repository->{baseurl} && $repository->{baseurl} ne '') { 228 $dir = $repository->{baseurl} 229 } elsif (defined $ENV{PORTSDIR}) { 230 $dir = $ENV{PORTSDIR}; 231 } else { 232 $dir = '/usr/ports'; 233 } 234 # figure out the repository name and the pkgname 235 my $pkgfile = `cd $dir && SUBDIR=$srcpath ECHO_MSG=: $make show=PKGFILE`; 236 chomp $pkgfile; 237 if (! -f $pkgfile) { 238 system "cd $dir && SUBDIR=$srcpath $make package BULK=Yes"; 239 } 240 if (! -f $pkgfile) { 241 return undef; 242 } 243 $pkgfile =~ m|(.*/)([^/]*)|; 244 my ($base, $fname) = ($1, $2); 245 246 my $repo = OpenBSD::PackageRepository::Local->_new($base); 247 return $repo->find($fname); 248} 249 250package OpenBSD::PackageRepository::Local; 251our @ISA=qw(OpenBSD::PackageRepository); 252 253sub open_pipe 254{ 255 my ($self, $object) = @_; 256 my $pid = open(my $fh, "-|"); 257 if (!defined $pid) { 258 die "Cannot fork: $!"; 259 } 260 if ($pid) { 261 return $fh; 262 } else { 263 open STDERR, ">/dev/null"; 264 exec {"/usr/bin/gzip"} 265 "gzip", 266 "-d", 267 "-c", 268 "-q", 269 "-f", 270 $self->{baseurl}.$object->{name} 271 or die "Can't run gzip"; 272 } 273} 274 275sub may_exist 276{ 277 my ($self, $name) = @_; 278 return -r $self->{baseurl}.$name; 279} 280 281sub list 282{ 283 my $self = shift; 284 my $l = []; 285 my $dname = $self->{baseurl}; 286 opendir(my $dir, $dname) or return $l; 287 while (my $e = readdir $dir) { 288 next unless $e =~ m/\.tgz$/; 289 next unless -f "$dname/$e"; 290 push(@$l, $`); 291 } 292 close($dir); 293 return $l; 294} 295 296package OpenBSD::PackageRepository::Local::Pipe; 297our @ISA=qw(OpenBSD::PackageRepository::Local); 298 299sub may_exist 300{ 301 return 1; 302} 303 304sub open_pipe 305{ 306 my ($self, $object) = @_; 307 my $fullname = $self->{baseurl}.$object->{name}; 308 my $pid = open(my $fh, "-|"); 309 if (!defined $pid) { 310 die "Cannot fork: $!"; 311 } 312 if ($pid) { 313 return $fh; 314 } else { 315 open STDERR, ">/dev/null"; 316 exec {"/usr/bin/gzip"} 317 "gzip", 318 "-d", 319 "-c", 320 "-q", 321 "-f", 322 "-" 323 or die "can't run gzip"; 324 } 325} 326 327package OpenBSD::PackageRepository::Distant; 328our @ISA=qw(OpenBSD::PackageRepository); 329 330my $buffsize = 2 * 1024 * 1024; 331 332sub pkg_copy 333{ 334 my ($in, $dir, $name) = @_; 335 336 require File::Temp; 337 my $template = $name; 338 $template =~ s/\.tgz$/.XXXXXXXX/; 339 340 my ($copy, $filename) = File::Temp::tempfile($template, 341 DIR => $dir) or die "Can't write copy to cache"; 342 chmod 0644, $filename; 343 my $handler = sub { 344 my ($sig) = @_; 345 unlink $filename; 346 $SIG{$sig} = 'DEFAULT'; 347 kill $sig, $$; 348 }; 349 350 { 351 352 local $SIG{'PIPE'} = $handler; 353 local $SIG{'INT'} = $handler; 354 local $SIG{'HUP'} = $handler; 355 local $SIG{'QUIT'} = $handler; 356 local $SIG{'KILL'} = $handler; 357 local $SIG{'TERM'} = $handler; 358 359 my ($buffer, $n); 360 # copy stuff over 361 do { 362 $n = sysread($in, $buffer, $buffsize); 363 if (!defined $n) { 364 die "Error reading\n"; 365 } 366 syswrite $copy, $buffer; 367 syswrite STDOUT, $buffer; 368 } while ($n != 0); 369 close($copy); 370 } 371 372 rename $filename, "$dir/$name"; 373} 374 375sub open_pipe 376{ 377 require OpenBSD::Temp; 378 379 my ($self, $object) = @_; 380 $object->{errors} = OpenBSD::Temp::file(); 381 my $pid = open(my $fh, "-|"); 382 if (!defined $pid) { 383 die "Cannot fork: $!"; 384 } 385 if ($pid) { 386 return $fh; 387 } else { 388 open STDERR, '>', $object->{errors}; 389 390 my $pid2 = open(STDIN, "-|"); 391 392 if (!defined $pid2) { 393 die "Cannot fork: $!"; 394 } 395 if ($pid2) { 396 exec {"/usr/bin/gzip"} 397 "gzip", 398 "-d", 399 "-c", 400 "-q", 401 "-" 402 or die "can't run gzip"; 403 } else { 404 if (defined $ENV{'PKG_CACHE'}) { 405 my $pid3 = open(my $in, "-|"); 406 if (!defined $pid3) { 407 die "Cannot fork: $!"; 408 } 409 if ($pid3) { 410 pkg_copy($in, $ENV{'PKG_CACHE'}, 411 $object->{name}); 412 exit(0); 413 } else { 414 $self->grab_object($object); 415 } 416 } else { 417 $self->grab_object($object); 418 } 419 } 420 } 421} 422 423sub _list 424{ 425 my ($self, $cmd) = @_; 426 my $l =[]; 427 local $_; 428 open(my $fh, '-|', "$cmd") or return undef; 429 while(<$fh>) { 430 chomp; 431 next if m/^d.*\s+\S/; 432 next unless m/([^\s]+)\.tgz\s*$/; 433 push(@$l, $1); 434 } 435 close($fh); 436 return $l; 437} 438 439 440package OpenBSD::PackageRepository::SCP; 441our @ISA=qw(OpenBSD::PackageRepository::Distant); 442 443 444sub grab_object 445{ 446 my ($self, $object) = @_; 447 448 exec {"/usr/bin/scp"} 449 "scp", 450 $self->{host}.":".$self->{path}.$object->{name}, 451 "/dev/stdout" 452 or die "can't run scp"; 453} 454 455our %distant = (); 456 457sub maxcount 458{ 459 return 2; 460} 461 462sub opened 463{ 464 my $self = $_[0]; 465 my $k = $self->{key}; 466 if (!defined $distant{$k}) { 467 $distant{$k} = []; 468 } 469 return $distant{$k}; 470} 471 472sub _new 473{ 474 my ($class, $baseurl) = @_; 475 $baseurl =~ s/scp\:\/\///i; 476 $baseurl =~ m/\//; 477 bless { host => $`, key => $`, path => "/$'" }, $class; 478} 479 480sub list 481{ 482 my ($self) = @_; 483 if (!defined $self->{list}) { 484 my $host = $self->{host}; 485 my $path = $self->{path}; 486 $self->{list} = $self->_list("ssh $host ls -l $path"); 487 } 488 return $self->{list}; 489} 490 491package OpenBSD::PackageRepository::HTTPorFTP; 492our @ISA=qw(OpenBSD::PackageRepository::Distant); 493 494our %distant = (); 495 496 497sub grab_object 498{ 499 my ($self, $object) = @_; 500 my $ftp = defined $ENV{'FETCH_CMD'} ? $ENV{'FETCH_CMD'} : "/usr/bin/ftp"; 501 exec {$ftp} 502 "ftp", 503 "-o", 504 "-", $self->{baseurl}.$object->{name} 505 or die "can't run ftp"; 506} 507 508sub maxcount 509{ 510 return 1; 511} 512 513sub opened 514{ 515 my $self = $_[0]; 516 my $k = $self->{key}; 517 if (!defined $distant{$k}) { 518 $distant{$k} = []; 519 } 520 return $distant{$k}; 521} 522 523sub _new 524{ 525 my ($class, $baseurl) = @_; 526 my $distant_host; 527 if ($baseurl =~ m/^(http|ftp)\:\/\/(.*?)\//i) { 528 $distant_host = $&; 529 } 530 bless { baseurl => $baseurl, key => $distant_host }, $class; 531} 532 533 534package OpenBSD::PackageRepository::HTTP; 535our @ISA=qw(OpenBSD::PackageRepository::HTTPorFTP); 536 537sub list 538{ 539 my ($self) = @_; 540 if (!defined $self->{list}) { 541 my $error = OpenBSD::Temp::file(); 542 $self->make_room(); 543 my $fullname = $self->{baseurl}; 544 my $l = $self->{list} = []; 545 local $_; 546 open(my $fh, '-|', "ftp -o - $fullname 2>$error") or return undef; 547 # XXX assumes a pkg HREF won't cross a line. Is this the case ? 548 while(<$fh>) { 549 chomp; 550 for my $pkg (m/\<A\s+HREF=\"(.*?)\.tgz\"\>/gi) { 551 next if $pkg =~ m|/|; 552 push(@$l, $pkg); 553 } 554 } 555 close($fh); 556 $self->parse_problems($error); 557 } 558 return $self->{list}; 559} 560 561package OpenBSD::PackageRepository::FTP; 562our @ISA=qw(OpenBSD::PackageRepository::HTTPorFTP); 563 564 565sub list 566{ 567 my ($self) = @_; 568 if (!defined $self->{list}) { 569 require OpenBSD::Temp; 570 571 my $error = OpenBSD::Temp::file(); 572 $self->make_room(); 573 my $fullname = $self->{baseurl}; 574 $self->{list} = $self->_list("echo 'nlist *.tgz'|ftp -o - $fullname 2>$error"); 575 $self->parse_problems($error); 576 } 577 return $self->{list}; 578} 579 580package OpenBSD::PackageLocation; 581 582use OpenBSD::PackageInfo; 583use OpenBSD::Temp; 584 585sub new 586{ 587 my ($class, $repository, $name) = @_; 588 my $self = { repository => $repository, name => $name}; 589 bless $self, $class; 590} 591 592sub openArchive 593{ 594 my $self = shift; 595 596 my $fh = $self->{repository}->open($self); 597 if (!defined $fh) { 598 $self->{repository}->parse_problems($self->{errors}) 599 if defined $self->{errors}; 600 return undef; 601 } 602 require OpenBSD::Ustar; 603 604 my $archive = new OpenBSD::Ustar $fh; 605 $self->{_archive} = $archive; 606} 607 608sub grabInfoFiles 609{ 610 my $self = shift; 611 my $dir = $self->{dir} = OpenBSD::Temp::dir(); 612 613 if (defined $self->{contents} && ! -f $dir.CONTENTS) { 614 open my $fh, '>', $dir.CONTENTS or die "Permission denied"; 615 print $fh $self->{contents}; 616 close $fh; 617 } 618 619 while (my $e = $self->intNext()) { 620 if ($e->isFile() && is_info_name($e->{name})) { 621 $e->{name}=$dir.$e->{name}; 622 eval { $e->create(); }; 623 if ($@) { 624 unlink($e->{name}); 625 $@ =~ s/\s+at.*//; 626 print STDERR $@; 627 return 0; 628 } 629 } else { 630 $self->unput(); 631 last; 632 } 633 } 634 return 1; 635} 636 637sub scanPackage 638{ 639 my $self = shift; 640 while (my $e = $self->intNext()) { 641 if ($e->isFile() && is_info_name($e->{name})) { 642 if ($e->{name} eq CONTENTS && !defined $self->{dir}) { 643 $self->{contents} = $e->contents(); 644 last; 645 } 646 if (!defined $self->{dir}) { 647 $self->{dir} = OpenBSD::Temp::dir(); 648 } 649 $e->{name}=$self->{dir}.$e->{name}; 650 eval { $e->create(); }; 651 if ($@) { 652 unlink($e->{name}); 653 $@ =~ s/\s+at.*//; 654 print STDERR $@; 655 return 0; 656 } 657 } else { 658 $self->unput(); 659 last; 660 } 661 } 662 return 1; 663} 664 665sub grabPlist 666{ 667 my ($self, $pkgname, $arch, $code) = @_; 668 669 my $pkg = $self->openPackage($pkgname, $arch); 670 if (defined $pkg) { 671 my $plist = $self->plist($code); 672 $pkg->wipe_info(); 673 $pkg->close(); 674 return $plist; 675 } else { 676 return undef; 677 } 678} 679 680sub openPackage 681{ 682 my ($self, $pkgname, $arch) = @_; 683 if (!$self->openArchive()) { 684 return undef; 685 } 686 $self->scanPackage(); 687 688 if (defined $self->{contents}) { 689 return $self; 690 } 691 692 # maybe it's a fat package. 693 while (my $e = $self->intNext()) { 694 unless ($e->{name} =~ m/\/\+CONTENTS$/) { 695 last; 696 } 697 my $prefix = $`; 698 my $contents = $e->contents(); 699 require OpenBSD::PackingList; 700 701 $pkgname =~ s/\.tgz$//; 702 703 my $plist = OpenBSD::PackingList->fromfile(\$contents, 704 \&OpenBSD::PackingList::FatOnly); 705 next if defined $pkgname and $plist->pkgname() ne $pkgname; 706 if ($plist->has('arch')) { 707 if ($plist->{arch}->check($arch)) { 708 $self->{filter} = $prefix; 709 bless $self, "OpenBSD::FatPackageLocation"; 710 $self->{contents} = $contents; 711 return $self; 712 } 713 } 714 } 715 # hopeless 716 $self->close(); 717 $self->wipe_info(); 718 return undef; 719} 720 721sub wipe_info 722{ 723 my $self = shift; 724 $self->{repository}->wipe_info($self); 725} 726 727sub info 728{ 729 my $self = shift; 730 if (!defined $self->{dir}) { 731 $self->grabInfoFiles(); 732 } 733 return $self->{dir}; 734} 735 736sub plist 737{ 738 my ($self, $code) = @_; 739 740 require OpenBSD::PackingList; 741 742 if (defined $self->{contents}) { 743 my $value = $self->{contents}; 744 return OpenBSD::PackingList->fromfile(\$value, $code); 745 } elsif (defined $self->{dir} && -f $self->{dir}.CONTENTS) { 746 return OpenBSD::PackingList->fromfile($self->{dir}.CONTENTS, 747 $code); 748 } 749 # hopeless 750 $self->close(); 751 752 return undef; 753} 754 755sub close 756{ 757 my $self = shift; 758 $self->{repository}->close($self); 759} 760 761sub deref 762{ 763 my $self = shift; 764 $self->{fh} = undef; 765 $self->{_archive} = undef; 766} 767 768sub reopen 769{ 770 my $self = shift; 771 if (!$self->openArchive()) { 772 return undef; 773 } 774 while (my $e = $self->{_archive}->next()) { 775 if ($e->{name} eq $self->{_current}->{name}) { 776 $self->{_current} = $e; 777 return $self; 778 } 779 } 780 return undef; 781} 782 783# proxy for archive operations 784sub next 785{ 786 my $self = shift; 787 788 if (!defined $self->{dir}) { 789 $self->grabInfoFiles(); 790 } 791 return $self->intNext(); 792} 793 794sub intNext 795{ 796 my $self = shift; 797 798 if (!defined $self->{fh}) { 799 if (!$self->reopen()) { 800 return undef; 801 } 802 } 803 if (!$self->{_unput}) { 804 $self->{_current} = $self->getNext(); 805 } 806 $self->{_unput} = 0; 807 return $self->{_current}; 808} 809 810sub unput 811{ 812 my $self = shift; 813 $self->{_unput} = 1; 814} 815 816sub getNext 817{ 818 my $self = shift; 819 820 return $self->{_archive}->next(); 821} 822 823package OpenBSD::FatPackageLocation; 824our @ISA=qw(OpenBSD::PackageLocation); 825 826sub getNext 827{ 828 my $self = shift; 829 830 my $e = $self->SUPER::getNext(); 831 if ($e->{name} =~ m/^(.*?)\/(.*)$/) { 832 my ($beg, $name) = ($1, $2); 833 if (index($beg, $self->{filter}) == -1) { 834 return $self->next(); 835 } 836 $e->{name} = $name; 837 if ($e->isHardLink()) { 838 $e->{linkname} =~ s/^(.*?)\///; 839 } 840 } 841 return $e; 842} 843 844package OpenBSD::PackageRepositoryList; 845 846sub new 847{ 848 my $class = shift; 849 return bless {list => [], avail => undef }, $class; 850} 851 852sub add 853{ 854 my $self = shift; 855 push @{$self->{list}}, @_; 856 if (@_ > 0) { 857 $self->{avail} = undef; 858 } 859} 860 861sub find 862{ 863 my ($self, $pkgname, $arch, $srcpath) = @_; 864 865 for my $repo (@{$self->{list}}) { 866 my $pkg = $repo->find($pkgname, $arch, $srcpath); 867 return $pkg if defined $pkg; 868 } 869 return undef; 870} 871 872sub grabPlist 873{ 874 my ($self, $pkgname, $arch, $code) = @_; 875 876 for my $repo (@{$self->{list}}) { 877 my $plist = $repo->grabPlist($pkgname, $arch, $code); 878 return $plist if defined $plist; 879 } 880 return undef; 881} 882 883sub available 884{ 885 my $self = shift; 886 887 if (!defined $self->{avail}) { 888 my $available_packages = {}; 889 foreach my $loc (reverse @{$self->{list}}) { 890 foreach my $pkg (@{$loc->list()}) { 891 $available_packages->{$pkg} = $loc; 892 } 893 } 894 $self->{avail} = $available_packages; 895 } 896 return keys %{$self->{avail}}; 897} 898 899package OpenBSD::PackageLocator; 900 901# this returns an archive handle from an uninstalled package name, currently 902# There is a cache available. 903 904my %packages; 905my $pkgpath = OpenBSD::PackageRepositoryList->new(); 906 907if (defined $ENV{PKG_PATH}) { 908 my $v = $ENV{PKG_PATH}; 909 $v =~ s/^\:+//; 910 $v =~ s/\:+$//; 911 my @tentative = split /\/\:/, $v; 912 while (my $i = shift @tentative) { 913 $i =~ m|/$| or $i.='/'; 914 $pkgpath->add(OpenBSD::PackageRepository->new($i)); 915 } 916} else { 917 $pkgpath->add(OpenBSD::PackageRepository->new("./")); 918} 919 920sub find 921{ 922 my $class = shift; 923 local $_ = shift; 924 my $arch = shift; 925 my $srcpath = shift; 926 927 if ($_ eq '-') { 928 my $repository = OpenBSD::PackageRepository::Local::Pipe->_new('./'); 929 my $package = $repository->find(undef, $arch, $srcpath); 930 return $package; 931 } 932 if (exists $packages{$_}) { 933 return $packages{$_}; 934 } 935 my $package; 936 if (m/\//) { 937 use File::Basename; 938 939 my ($pkgname, $path) = fileparse($_); 940 my $repository = OpenBSD::PackageRepository->new($path); 941 $package = $repository->find($pkgname, $arch, $srcpath); 942 if (defined $package) { 943 $pkgpath->add($repository); 944 } 945 } else { 946 $package = $pkgpath->find($_, $arch, $srcpath); 947 } 948 $packages{$_} = $package if defined($package); 949 return $package; 950} 951 952sub available 953{ 954 return $pkgpath->available(); 955} 956 957sub grabPlist 958{ 959 my $class = shift; 960 local $_ = shift; 961 my $arch = shift; 962 my $code = shift; 963 964 if ($_ eq '-') { 965 my $repository = OpenBSD::PackageRepository::Local::Pipe->_new('./'); 966 my $plist = $repository->grabPlist(undef, $arch, $code); 967 return $plist; 968 } 969 my $plist; 970 if (m/\//) { 971 use File::Basename; 972 973 my ($pkgname, $path) = fileparse($_); 974 my $repository = OpenBSD::PackageRepository->new($path); 975 $plist = $repository->grabPlist($pkgname, $arch, $code); 976 if (defined $plist) { 977 $pkgpath->add($repository); 978 } 979 } else { 980 $plist = $pkgpath->grabPlist($_, $arch, $code); 981 } 982 return $plist; 983} 984 9851; 986