PackageLocator.pm revision 1.5
1# $OpenBSD: PackageLocator.pm,v 1.5 2003/11/06 17:59:23 espie Exp $ 2# 3# Copyright (c) 2003 Marc Espie. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 14# THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 15# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 18# PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26use strict; 27use warnings; 28 29# XXX we don't want to load Ustar all the time 30package OpenBSD::Ustar; 31 32our $AUTOLOAD; 33 34sub AUTOLOAD { 35 eval { require OpenBSD::Ustar; 36 }; 37 goto &$AUTOLOAD; 38} 39 40package OpenBSD::PackageLocation; 41 42sub _new 43{ 44 my ($class, $location) = @_; 45 bless { location => $location }, $class; 46} 47 48sub new 49{ 50 my ($class, $location) = @_; 51 if ($location =~ m/^ftp\:/i) { 52 return OpenBSD::PackageLocation::FTP->_new($location); 53 } elsif ($location =~ m/^http\:/i) { 54 return OpenBSD::PackageLocation::HTTP->_new($location); 55 } elsif ($location =~ m/^scp\:/i) { 56 return OpenBSD::PackageLocation::SCP->_new($location); 57 } else { 58 return OpenBSD::PackageLocation::Local->_new($location); 59 } 60} 61 62package OpenBSD::PackageLocation::SCP; 63our @ISA=qw(OpenBSD::PackageLocation OpenBSD::PackageLocation::FTPorSCP); 64 65sub _new 66{ 67 my ($class, $location) = @_; 68 $location =~ s/scp\:\/\///i; 69 $location =~ m/\//; 70 bless { host => $`, path => "/$'" }, $class; 71} 72 73sub open 74{ 75 my ($self, $name) = @_; 76 my $host = $self->{host}; 77 my $path = $self->{path}; 78 open(my $fh, '-|', "scp $host:$path$name /dev/stdout 2> /dev/null|gzip -d -c -q - 2> /dev/null") or return undef; 79 return $fh; 80} 81 82sub list 83{ 84 my ($self) = @_; 85 my $host = $self->{host}; 86 my $path = $self->{path}; 87 return _list("ssh $host ls -l $path"); 88} 89 90package OpenBSD::PackageLocation::Local; 91our @ISA=qw(OpenBSD::PackageLocation); 92 93sub open 94{ 95 my ($self, $name) = @_; 96 my $fullname = $self->{location}.$name; 97 open(my $fh, '-|', "gzip -d -c -q -f 2>/dev/null $fullname") or return undef; 98 return $fh; 99} 100 101sub list 102{ 103 my $self = shift; 104 my @l = (); 105 opendir(my $dir, $self->{location}) or return undef; 106 while (my $e = readdir $dir) { 107 next unless -f "$dir/$e"; 108 next unless $e = ~ m/\.tgz$/; 109 push(@l, $`); 110 } 111 close($dir); 112 return @l; 113} 114 115package OpenBSD::PackageLocation::FTPorSCP; 116 117sub _list 118{ 119 my ($self, $cmd) = @_; 120 my @l =(); 121 local $_; 122 open(my $fh, '-|', "$cmd") or return undef; 123 while(<$fh>) { 124 chomp; 125 next if m/^d.*\s+\S/; 126 next unless m/([^\s]+)\.tgz\s*$/; 127 push(@l, $1); 128 } 129 close($fh); 130 return @l; 131} 132 133package OpenBSD::PackageLocation::HTTPorFTP; 134sub open 135{ 136 my ($self, $name) = @_; 137 my $fullname = $self->{location}.$name; 138 open(my $fh, '-|', "ftp -o - $fullname 2>/dev/null|gzip -d -c -q - 2>/dev/null") or return undef; 139 return $fh; 140} 141 142package OpenBSD::PackageLocation::HTTP; 143our @ISA=qw(OpenBSD::PackageLocation::HTTPorFTP OpenBSD::PackageLocation); 144sub list 145{ 146 my ($self) = @_; 147 my $fullname = $self->{location}; 148 my @l =(); 149 local $_; 150 open(my $fh, '-|', "echo ls|ftp -o - $fullname 2>/dev/null") or return undef; 151 # XXX assumes a pkg HREF won't cross a line. Is this the case ? 152 while(<$fh>) { 153 chomp; 154 for my $pkg (m/\<A\s+HREF=\"(.*?)\.tgz\"\>/gi) { 155 next if $pkg =~ m|/|; 156 push(@l, $pkg); 157 } 158 } 159 close($fh); 160 return @l; 161} 162 163package OpenBSD::PackageLocation::FTP; 164our @ISA=qw(OpenBSD::PackageLocation::HTTPorFTP OpenBSD::PackageLocation OpenBSD::PackageLocation::FTPorSCP); 165 166sub list 167{ 168 my ($self) = @_; 169 my $fullname = $self->{location}; 170 return _list("echo ls|ftp -o - $fullname 2>/dev/null"); 171} 172 173 174package OpenBSD::PackageLocator; 175 176# this returns an archive handle from an uninstalled package name, currently 177# There is a cache available. 178 179use OpenBSD::PackageInfo; 180use OpenBSD::Temp; 181 182my %packages; 183my @pkgpath; 184 185if (defined $ENV{PKG_PATH}) { 186 my @tentative = split /\:/, $ENV{PKG_PATH}; 187 @pkgpath = (); 188 while (my $i = shift @tentative) { 189 if ($i =~ m/^(?:ftp|http|scp)$/i) { 190 $i.= ":".(shift @tentative); 191 } 192 $i =~ m|/$| or $i.='/'; 193 push @pkgpath, OpenBSD::PackageLocation->new($i); 194 } 195} else { 196 @pkgpath=(OpenBSD::PackageLocation->new("./")); 197} 198 199sub find 200{ 201 my $class = shift; 202 local $_ = shift; 203 204 if ($_ eq '-') { 205 my $location = OpenBSD::PackageLocation->new('-'); 206 my $package = openAbsolute($location, ''); 207 bless $package, $class; 208 return $package; 209 } 210 $_.=".tgz" unless m/\.tgz$/; 211 if (exists $packages{$_}) { 212 return $packages{$_}; 213 } 214 my $package; 215 if (m/\//) { 216 use File::Basename; 217 218 my ($pkgname, $path) = fileparse($_); 219 my $location = OpenBSD::PackageLocation->new($path); 220 $package = openAbsolute($location, $pkgname); 221 if (defined $package) { 222 push(@pkgpath, $location); 223 } 224 } else { 225 for my $p (@pkgpath) { 226 $package = openAbsolute($p, $_); 227 last if defined $package; 228 } 229 } 230 return $package unless defined $package; 231 $packages{$_} = $package; 232 bless $package, $class; 233} 234 235sub info 236{ 237 my $self = shift; 238 return $self->{dir}; 239} 240 241sub close 242{ 243 my $self = shift; 244 close($self->{fh}) if defined $self->{fh}; 245 $self->{fh} = undef; 246 $self->{archive} = undef; 247} 248 249sub openAbsolute 250{ 251 my ($location, $name) = @_; 252 my $fh = $location->open($name); 253 if (!defined $fh) { 254 return undef; 255 } 256 my $archive = new OpenBSD::Ustar $fh; 257 my $dir = OpenBSD::Temp::dir(); 258 259 my $self = { name => $_, fh => $fh, archive => $archive, dir => $dir }; 260 # check that Open worked 261 while (my $e = $archive->next()) { 262 if ($e->isFile() && is_info_name($e->{name})) { 263 $e->{name}=$dir.$e->{name}; 264 $e->create(); 265 } else { 266 $archive->unput(); 267 last; 268 } 269 } 270 if (-f $dir.CONTENTS) { 271 return $self; 272 } else { 273 CORE::close($fh); 274 return undef; 275 } 276} 277 278# allows the autoloader to work correctly 279sub DESTROY 280{ 281} 282 2831; 284