Mon, 28 Jan 2013 17:37:18 +0100
Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.
michael@428 | 1 | ## |
michael@428 | 2 | ## search.pl -- OpenPKG Package Searching |
michael@428 | 3 | ## Copyright (c) 2011-2012 OpenPKG GmbH <http://openpkg.com/> |
michael@428 | 4 | ## |
michael@428 | 5 | ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. |
michael@428 | 6 | ## All rights reserved. Licenses which grant limited permission to use, |
michael@428 | 7 | ## copy, modify and distribute this software are available from the |
michael@428 | 8 | ## OpenPKG GmbH. |
michael@428 | 9 | ## |
michael@428 | 10 | ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
michael@428 | 11 | ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
michael@428 | 12 | ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
michael@428 | 13 | ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR |
michael@428 | 14 | ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@428 | 15 | ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@428 | 16 | ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
michael@428 | 17 | ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
michael@428 | 18 | ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
michael@428 | 19 | ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
michael@428 | 20 | ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
michael@428 | 21 | ## SUCH DAMAGE. |
michael@428 | 22 | ## |
michael@428 | 23 | |
michael@428 | 24 | require 5.003; |
michael@428 | 25 | |
michael@428 | 26 | # OpenPKG instance prefix and RPM |
michael@428 | 27 | my $my_prefix = $ENV{'OPENPKG_PREFIX'}; |
michael@428 | 28 | my $my_rpm = "$my_prefix/bin/openpkg rpm"; |
michael@428 | 29 | delete $ENV{'OPENPKG_PREFIX'}; |
michael@428 | 30 | |
michael@428 | 31 | # program identification |
michael@428 | 32 | my $progname = "search"; |
michael@428 | 33 | my $progvers = "0.1.0"; |
michael@428 | 34 | |
michael@428 | 35 | # home-brewn getopt(3) style option parser |
michael@428 | 36 | sub getopts ($$@) { |
michael@428 | 37 | my ($opt_spec, $opts, @argv_orig) = @_; |
michael@428 | 38 | my (%optf) = map { m/(\w)/; $1 => $_ } $opt_spec =~ m/(\w:|\w)/g; |
michael@428 | 39 | my (@argv, $optarg); |
michael@428 | 40 | |
michael@428 | 41 | foreach (@argv_orig) { |
michael@428 | 42 | if (@argv) { |
michael@428 | 43 | push @argv, $_; |
michael@428 | 44 | } elsif (defined $optarg) { |
michael@428 | 45 | if (exists $opts->{$optarg}) { |
michael@428 | 46 | $opts->{$optarg} .= " $_"; |
michael@428 | 47 | } else { |
michael@428 | 48 | $opts->{$optarg} = $_; |
michael@428 | 49 | } |
michael@428 | 50 | $optarg = undef; |
michael@428 | 51 | } elsif (!/^[-]/) { |
michael@428 | 52 | push @argv, $_; |
michael@428 | 53 | } else { |
michael@428 | 54 | while (/^\-(\w)(.*)/) { |
michael@428 | 55 | if (exists $optf{$1}) { |
michael@428 | 56 | if (length($optf{$1}) > 1) { |
michael@428 | 57 | if ($2 ne '') { |
michael@428 | 58 | if (exists $opts->{$1}) { |
michael@428 | 59 | $opts->{$1} .= " $2"; |
michael@428 | 60 | } else { |
michael@428 | 61 | $opts->{$1} = $2; |
michael@428 | 62 | } |
michael@428 | 63 | } else { |
michael@428 | 64 | $optarg = $1; |
michael@428 | 65 | } |
michael@428 | 66 | last; |
michael@428 | 67 | } else { |
michael@428 | 68 | $opts->{$1} = 1; |
michael@428 | 69 | } |
michael@428 | 70 | } else { |
michael@428 | 71 | warn "openpkg:$prog_name:WARNING: unknown option $_\n"; |
michael@428 | 72 | } |
michael@428 | 73 | $_ = "-$2"; |
michael@428 | 74 | } |
michael@428 | 75 | } |
michael@428 | 76 | } |
michael@428 | 77 | if (defined $optarg) { |
michael@428 | 78 | warn "openpkg:$prog_name:WARNING: option $optarg requires an argument\n"; |
michael@428 | 79 | } |
michael@428 | 80 | foreach my $opt (keys %optf) { |
michael@428 | 81 | if (not exists $opts->{$opt}) { |
michael@428 | 82 | $opts->{$opt} = (length($optf{$opt}) > 1 ? "" : 0); |
michael@428 | 83 | } |
michael@428 | 84 | } |
michael@428 | 85 | return @argv; |
michael@428 | 86 | } |
michael@428 | 87 | |
michael@428 | 88 | # execute a command |
michael@428 | 89 | my $run_cache = {}; |
michael@428 | 90 | sub run ($) { |
michael@428 | 91 | my ($cmd) = @_; |
michael@428 | 92 | my $out = $run_cache->{$cmd}; |
michael@428 | 93 | if (not defined($out)) { |
michael@428 | 94 | my @out = `$cmd`; |
michael@428 | 95 | $out = [ @out ]; |
michael@428 | 96 | $run_cache->{$cmd} = $out; |
michael@428 | 97 | } |
michael@428 | 98 | return (wantarray ? @{$out} : join(//, @{$out})); |
michael@428 | 99 | } |
michael@428 | 100 | |
michael@428 | 101 | # determine reasonable temporary directory |
michael@428 | 102 | my $tmpdir = ($ENV{"TMPDIR"} || "/tmp"); |
michael@428 | 103 | |
michael@428 | 104 | # parse command line options |
michael@428 | 105 | my $opts = {}; |
michael@428 | 106 | @ARGV = getopts("hvr:", $opts, @ARGV); |
michael@428 | 107 | |
michael@428 | 108 | # usage sanity check and usage help |
michael@428 | 109 | sub usage { |
michael@428 | 110 | my ($rc) = @_; |
michael@428 | 111 | my $usage = "openpkg:$prog_name:USAGE: openpkg search <regex>\n"; |
michael@428 | 112 | if ($rc == 0) { |
michael@428 | 113 | print STDOUT $usage; |
michael@428 | 114 | } |
michael@428 | 115 | else { |
michael@428 | 116 | print STDERR $usage; |
michael@428 | 117 | } |
michael@428 | 118 | exit($rc); |
michael@428 | 119 | } |
michael@428 | 120 | if ($opts->{"h"}) { |
michael@428 | 121 | usage(0); |
michael@428 | 122 | } |
michael@428 | 123 | if (@ARGV == 0) { |
michael@428 | 124 | usage(1); |
michael@428 | 125 | } |
michael@428 | 126 | |
michael@428 | 127 | # take command line arguments |
michael@428 | 128 | my $keyword = $ARGV[0]; |
michael@428 | 129 | |
michael@428 | 130 | # determine start URL |
michael@428 | 131 | my $url = $opts->{"r"} || ""; |
michael@428 | 132 | if ($url eq "") { |
michael@428 | 133 | $url = run("$my_prefix/bin/openpkg release --fmt='%u' 2>/dev/null"); |
michael@428 | 134 | $url =~ s/^\s+//s; |
michael@428 | 135 | $url =~ s/\s+$//s; |
michael@428 | 136 | } |
michael@428 | 137 | if ($url eq "") { |
michael@428 | 138 | print STDERR "openpkg:$prog_name:ERROR: no repository URL known\n"; |
michael@428 | 139 | exit(1); |
michael@428 | 140 | } |
michael@428 | 141 | |
michael@428 | 142 | # recursively download XML/RDF index |
michael@428 | 143 | sub relurl ($$) { |
michael@428 | 144 | my ($url, $suburl) = @_; |
michael@428 | 145 | if ($suburl =~ m/^\w+:\/\//) { |
michael@428 | 146 | $url = $suburl; |
michael@428 | 147 | } |
michael@428 | 148 | elsif ($suburl =~ m/^\//) { |
michael@428 | 149 | $url = "file://$suburl"; |
michael@428 | 150 | } |
michael@428 | 151 | else { |
michael@428 | 152 | $url =~ s/(\/)?\/*[^\/]*$/$1$suburl/; |
michael@428 | 153 | } |
michael@428 | 154 | 1 while ($url =~ s/\/\.\//\//s); |
michael@428 | 155 | 1 while ($url =~ s/\/[^\/]+\/\.\.\//\//s); |
michael@428 | 156 | return $url; |
michael@428 | 157 | } |
michael@428 | 158 | sub get_index ($) { |
michael@428 | 159 | my ($url) = @_; |
michael@428 | 160 | if ($url =~ m/^\//) { |
michael@428 | 161 | $url = "file://$url"; |
michael@428 | 162 | } |
michael@428 | 163 | if ($url =~ m/\/$/) { |
michael@428 | 164 | $url .= "00INDEX.rdf"; |
michael@428 | 165 | } |
michael@428 | 166 | my $cmd = "$my_prefix/bin/openpkg curl -s -o- \"$url\" 2>/dev/null"; |
michael@428 | 167 | if ($url =~ m/\.bz2$/) { |
michael@428 | 168 | $cmd .= " | $my_prefix/lib/openpkg/bzip2 -d -c"; |
michael@428 | 169 | } |
michael@428 | 170 | my $xml = run($cmd); |
michael@428 | 171 | my @includes = (); |
michael@428 | 172 | while ($xml =~ m/<Repository\s+[^>]*href="([^"]*)"/gs) { |
michael@428 | 173 | push(@includes, $1); |
michael@428 | 174 | } |
michael@428 | 175 | foreach my $include (@includes) { |
michael@428 | 176 | $xml .= get_index(relurl($url, $include)); |
michael@428 | 177 | } |
michael@428 | 178 | return $xml; |
michael@428 | 179 | } |
michael@428 | 180 | my $xml = get_index($url); |
michael@428 | 181 | |
michael@428 | 182 | # parse XML/RDF index |
michael@428 | 183 | my $x = $xml; |
michael@428 | 184 | $x =~ s/<rdf:Description\s+about="([^"]+)".*?>(.+?)<\/rdf:Description>/do1($1, $2), ''/sge; |
michael@428 | 185 | sub do1 { |
michael@428 | 186 | my ($nvr, $xml) = @_; |
michael@428 | 187 | my ($name) = ($xml =~ m|<Name>(.+?)</Name>|s); |
michael@428 | 188 | my ($vers) = ($xml =~ m|<Version>(.+?)</Version>|s); |
michael@428 | 189 | my ($rele) = ($xml =~ m|<Release>(.+?)</Release>|s); |
michael@428 | 190 | my ($summ) = ($xml =~ m|<Summary>(.+?)</Summary>|s); |
michael@428 | 191 | my ($desc) = ($xml =~ m|<Description>(.+?)</Description>|s); |
michael@428 | 192 | if ( $name =~ m|$keyword|si |
michael@428 | 193 | or $summ =~ m|$keyword|si |
michael@428 | 194 | or $desc =~ m|$keyword|si) { |
michael@428 | 195 | do2($nvr, $name, $vers, $rele, $summ, $desc, $xml); |
michael@428 | 196 | } |
michael@428 | 197 | } |
michael@428 | 198 | sub do2 { |
michael@428 | 199 | my ($nvr, $name, $vers, $rele, $summ, $desc, $xml) = @_; |
michael@428 | 200 | return if ($name eq "openpkg"); |
michael@428 | 201 | if ($opts->{"v"}) { |
michael@428 | 202 | # itemized verbose output |
michael@428 | 203 | my ($dist) = ($xml =~ m|<Distribution>(.+?)</Distribution>|s); |
michael@428 | 204 | my ($class) = ($xml =~ m|<Class>(.+?)</Class>|s); |
michael@428 | 205 | my ($group) = ($xml =~ m|<Group>(.+?)</Group>|s); |
michael@428 | 206 | my ($license) = ($xml =~ m|<License>(.+?)</License>|s); |
michael@428 | 207 | my ($packager) = ($xml =~ m|<Packager>(.+?)</Packager>|s); |
michael@428 | 208 | my ($url) = ($xml =~ m|<URL>(.+?)</URL>|s); |
michael@428 | 209 | my ($vendor) = ($xml =~ m|<Vendor>(.+?)</Vendor>|s); |
michael@428 | 210 | |
michael@428 | 211 | print "Name: $name\n"; |
michael@428 | 212 | print "Version: $vers\n"; |
michael@428 | 213 | print "Release: $rele\n"; |
michael@428 | 214 | print "Group: $group\n"; |
michael@428 | 215 | print "Class: $class\n"; |
michael@428 | 216 | print "Distrib: $dist\n"; |
michael@428 | 217 | print "License: $license\n"; |
michael@428 | 218 | print "Packager: $packager\n"; |
michael@428 | 219 | print "Vendor: $vendor\n"; |
michael@428 | 220 | print "Summary: $summ\n"; |
michael@428 | 221 | print "URL: $url\n"; |
michael@428 | 222 | |
michael@428 | 223 | print "Description:\n"; |
michael@428 | 224 | $desc =~ s/^\s+//mg; |
michael@428 | 225 | $desc =~ s/\s+$//mg; |
michael@428 | 226 | $desc =~ s/^/ /mg; |
michael@428 | 227 | print "$desc\n"; |
michael@428 | 228 | |
michael@428 | 229 | my ($prov) = ($xml =~ m|<Provides>(.+?)</Provides>|s); |
michael@428 | 230 | if (($prov || "") ne "") { |
michael@428 | 231 | print "Provides:\n"; |
michael@428 | 232 | $prov =~ s/<resource\s+equ="([^"]*)">(.+?)<\/resource>/do3($1, $2), ''/sge; |
michael@428 | 233 | sub do3 { |
michael@428 | 234 | my ($val, $name) = @_; |
michael@428 | 235 | print " $name = $val\n"; |
michael@428 | 236 | } |
michael@428 | 237 | } |
michael@428 | 238 | |
michael@428 | 239 | print "\n"; |
michael@428 | 240 | } |
michael@428 | 241 | else { |
michael@428 | 242 | # tabular brief output |
michael@428 | 243 | printf("%-20s %-10s %-9s %s\n", $name, $vers, $rele, $summ); |
michael@428 | 244 | } |
michael@428 | 245 | } |
michael@428 | 246 |