X-Git-Url: https://git.deb.at/?a=blobdiff_plain;f=lib%2FPackages%2FSearch.pm;h=c6a521ad65385d2cf11daa6f9ca95e8f00f3eb40;hb=a38d98d27880c8fc0f4d98646e318ecc1d39884f;hp=931747c618ed84b4863f9d3a183fbff349983835;hpb=56d4b3ed57e20359e5ea46feabb850cf4a94caf2;p=deb%2Fpackages.git diff --git a/lib/Packages/Search.pm b/lib/Packages/Search.pm index 931747c..c6a521a 100644 --- a/lib/Packages/Search.pm +++ b/lib/Packages/Search.pm @@ -43,7 +43,6 @@ package Packages::Search; use strict; use warnings; -#use CGI (); use POSIX; use HTML::Entities; use DB_File; @@ -62,293 +61,31 @@ our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] ); our $VERSION = 0.01; -our $USE_PAGED_MODE = 1; -use constant DEFAULT_PAGE => 1; -use constant DEFAULT_RES_PER_PAGE => 50; -our %page_params = ( page => { default => DEFAULT_PAGE, - match => '(\d+)' }, - number => { default => DEFAULT_RES_PER_PAGE, - match => '(\d+)' } ); - our $too_many_hits = 0; -sub parse_params { - my ( $cgi, $params_def, $opts ) = @_; - - my %params_ret = ( values => {}, errors => {} ); - my %params; - if ($USE_PAGED_MODE) { - debug( "Use PAGED_MODE", 2 ); - %params = %$params_def; - foreach (keys %page_params) { - delete $params{$_}; - } - %params = ( %params, %page_params ); - } else { - %params = %$params_def; - } - - foreach my $param ( keys %params ) { - - debug( "Param $param", 2 ); - - my $p_value_orig = $cgi->param($param); - - if (!defined($p_value_orig) - && defined $params_def->{$param}{alias} - && defined $cgi->param($params_def->{$param}{alias})) { - $p_value_orig = $cgi->param($params_def->{$param}{alias}); - debug( "Used alias $params_def->{$param}{alias}", - 2 ); - } - - my @p_value = ($p_value_orig); - - debug( "Value (Orig) ".($p_value_orig||""), 2 ); - - if ($params_def->{$param}{array} && defined $p_value_orig) { - @p_value = split /$params_def->{$param}{array}/, $p_value_orig; - debug( "Value (Array Split) ". join('##',@p_value), 2 ); - } - - if ($params_def->{$param}{match} && defined $p_value_orig) { - @p_value = map - { $_ =~ m/$params_def->{$param}{match}/; $_ = $1 } - @p_value; - } - @p_value = grep { defined $_ } @p_value; - - debug( "Value (Match) ". join('##',@p_value), 2 ); - - unless (@p_value) { - if (defined $params{$param}{default}) { - @p_value = ($params{$param}{default}); - } else { - @p_value = undef; - $params_ret{errors}{$param} = "undef"; - next; - } - } - - debug( "Value (Default) ". join('##',@p_value), 2 ); - my @p_value_no_replace = @p_value; - - if ($params{$param}{replace} && @p_value) { - foreach my $pattern (keys %{$params{$param}{replace}}) { - my @p_value_tmp = @p_value; - @p_value = (); - foreach (@p_value_tmp) { - if ($_ eq $pattern) { - my $replacement = $params{$param}{replace}{$_}; - if (ref $replacement) { - push @p_value, @$replacement; - } else { - push @p_value, $replacement; - } - } else { - push @p_value, $_; - } - } - } - } - - debug( "Value (Final) ". join('##',@p_value), 2 ); - - if ($params_def->{$param}{array}) { - $params_ret{values}{$param} = { - orig => $p_value_orig, - no_replace => \@p_value_no_replace, - final => \@p_value, - }; - @{$params_def->{$param}{var}} = @p_value - if $params_def->{$param}{var}; +sub read_entry_all { + my ($hash, $key, $results, $non_results, $opts) = @_; + my ($virt, $result) = split /\000/o, $hash->{$key} || "-\01-", 2; + + my %virt = split /\01/o, $virt; + while (my ($suite, $provides) = each %virt) { + next if $suite eq '-'; + if ($opts->{h_suites}{$suite}) { + push @$results, [ $key, "-", $suite, 'virtual', 'v', 'v', 'v', 'v', + $provides]; } else { - $params_ret{values}{$param} = { - orig => $p_value_orig, - no_replace => $p_value_no_replace[0], - final => $p_value[0], - }; - ${$params_def->{$param}{var}} = $p_value[0] - if $params_def->{$param}{var}; + push @$non_results, [ $key, "-", $suite, 'virtual', 'v', 'v', 'v', 'v', + $provides]; } - $opts->{$param} = $params_ret{values}{$param}{final} if $opts; - } - - if ($USE_PAGED_MODE) { - $cgi->delete( "page" ); - $cgi->delete( "number" ); } - return %params_ret; -} - -sub start { - my $params = shift; - - my $page = $params->{values}{page}{final} - || DEFAULT_PAGE; - my $res_per_page = $params->{values}{number}{final} - || DEFAULT_RES_PER_PAGE; - - return 1 if $res_per_page =~ /^all$/i; - return $res_per_page * ($page - 1) + 1; -} - -sub end { - my $params = shift; - - use Data::Dumper; - debug( "end: ".Dumper($params) ); - my $page = $params->{page} - || DEFAULT_PAGE; - my $res_per_page = $params->{number} - || DEFAULT_RES_PER_PAGE; - - return $page * $res_per_page; -} - -sub indexline { - my ($cgi, $params, $num_res) = @_; - - my $index_line = ""; - my $page = $params->{page} - || DEFAULT_PAGE; - my $res_per_page = $params->{number} - || DEFAULT_RES_PER_PAGE; - my $numpages = ceil($num_res / - $res_per_page); - for (my $i = 1; $i <= $numpages; $i++) { - if ($i == $page) { - $index_line .= $i; - } else { - $index_line .= "self_url). - "&page=$i&number=$res_per_page\">". - "$i"; - } - if ($i < $numpages) { - $index_line .= " | "; - } - } - return $index_line; -} - -sub nextlink { - my ($cgi, $params, $no_results ) = @_; - - my $page = $params->{page} - || DEFAULT_PAGE; - $page++; - my $res_per_page = $params->{number} - || DEFAULT_RES_PER_PAGE; - - if ((($page-1)*$res_per_page + 1) > $no_results) { - return ">>"; - } - - return "self_url). - "&page=$page&number=$res_per_page\">>>"; -} - -sub prevlink { - my ($cgi, $params ) = @_; - - my $page = $params->{page} - || DEFAULT_PAGE; - $page--; - if (!$page) { - return "<<"; - } - - my $res_per_page = $params->{number} - || DEFAULT_RES_PER_PAGE; - - return "self_url). - "&page=$page&number=$res_per_page\"><<"; -} - -sub resperpagelink { - my ($cgi, $params, $res_per_page ) = @_; - - my $page; - if ($res_per_page =~ /^all$/i) { - $page = 1; - } else { - $page = ceil(start( $params ) / $res_per_page); - } - - return "self_url). - "&page=$page&number=$res_per_page\">$res_per_page"; -} - -sub printindexline { - my ( $input, $no_results, $opts ) = @_; - - my $index_line; - if ($no_results > $opts->{number}) { - - $index_line = prevlink( $input, $opts)." | ". - indexline( $input, $opts, $no_results)." | ". - nextlink( $input, $opts, $no_results); - - print "

$index_line

"; - } -} - -#sub multipageheader { -# my ( $input, $no_results, $opts ) = @_; -# -# my ($start, $end); -# if ($opts->{number} =~ /^all$/i) { -# $start = 1; -# $end = $no_results; -# $opts->{number} = $no_results; -# $opts->{number_all}++; -# } else { -# $start = Packages::Search::start( $opts ); -# $end = Packages::Search::end( $opts ); -# if ($end > $no_results) { $end = $no_results; } -# } -# -# print "

Found $no_results matching packages,"; -# if ($end == $start) { -# print " displaying package $end.

"; -# } else { -# print " displaying packages $start to $end.

"; -# } -# -# printindexline( $input, $no_results, $opts ); -# -# if ($no_results > 100) { -# print "

Results per page: "; -# my @resperpagelinks; -# for (50, 100, 200) { -# if ($opts->{number} == $_) { -# push @resperpagelinks, $_; -# } else { -# push @resperpagelinks, resperpagelink($input,$opts,$_); -# } -# } -# if ($opts->{number_all}) { -# push @resperpagelinks, "all"; -# } else { -# push @resperpagelinks, resperpagelink($input, $opts, "all"); -# } -# print join( " | ", @resperpagelinks )."

"; -# } -# return ( $start, $end ); -#} - -sub read_entry_all { - my ($hash, $key, $results, $non_results, $opts) = @_; - my $result = $hash->{$key} || ''; foreach (split /\000/o, $result) { my @data = split ( /\s/o, $_, 8 ); - debug( "Considering entry ".join( ':', @data), 2); - if ($opts->{h_archives}{$data[0]} && $opts->{h_suites}{$data[1]} - && ($opts->{h_archs}{$data[2]} || $data[2] eq 'all' - || $data[2] eq 'virtual') - && ($opts->{h_sections}{$data[3]} || $data[3] eq 'v')) { - debug( "Using entry ".join( ':', @data), 2); + debug( "Considering entry ".join( ':', @data), 2) if DEBUG; + if ($opts->{h_suites}{$data[1]} + && ($opts->{h_archs}{$data[2]} || $data[2] eq 'all') + && $opts->{h_sections}{$data[3]}) { + debug( "Using entry ".join( ':', @data), 2) if DEBUG; push @$results, [ $key, @data ]; } else { push @$non_results, [ $key, @data ]; @@ -360,48 +97,51 @@ sub read_entry { my @non_results; read_entry_all( $hash, $key, $results, \@non_results, $opts ); } + +#FIXME: make configurable +my %fallback_suites = ( + 'stable-backports' => 'stable', + 'stable-volatile' => 'stable', + experimental => 'unstable' ); + sub read_entry_simple { my ($hash, $key, $archives, $suite) = @_; - my $result = $hash->{$key} || ''; + # FIXME: drop $archives + + my ($virt, $result) = split /\000/o, $hash->{$key} || "-\01-\0", 2; + my %virt = split /\01/o, $virt; debug( "read_entry_simple: key=$key, archives=". - join(" ",(keys %$archives)).", suite=$suite", 1); - my (@data_fuzzy, @data_virtual, @data_fuzzy_virtual); + join(" ",(keys %$archives)).", suite=$suite", 1) if DEBUG; + debug( "read_entry_simple: virt=".join(" ",(%virt)), 2) if DEBUG; + # FIXME: not all of the 2^4=16 combinations of empty(results), + # empty(virt{suite}), empty(fb_result), empty(virt{fb_suite}) are dealt + # with correctly, but it's adequate enough for now + return [ $virt{$suite} ] unless defined $result; foreach (split /\000/o, $result) { my @data = split ( /\s/o, $_, 8 ); - debug( "Considering entry ".join( ':', @data), 2); - if ($data[1] eq $suite) { - if ($archives->{$data[0]} - && ($data[2] ne 'virtual')) { - debug( "Using entry ".join( ':', @data), 2); - return \@data; - } elsif ($archives->{$data[0]}) { - debug( "Virtual entry ".join( ':', @data), 2); - @data_virtual = @data; - } elsif (($data[0] eq 'us') - && ($data[2] ne 'virtual')) { - debug( "Fuzzy entry ".join( ':', @data), 2); - @data_fuzzy = @data; - } elsif ($data[0] eq 'us') { - debug( "Virtual fuzzy entry ".join( ':', @data), 2); - @data_fuzzy_virtual = @data; - } - } + debug( "use entry: @data", 2 ) if DEBUG && $data[1] eq $suite; + return [ $virt{$suite}, @data ] if $data[1] eq $suite; } - return \@data_virtual if @data_virtual; - return \@data_fuzzy if @data_fuzzy; - return \@data_fuzzy_virtual; + if (my $fb_suite = $fallback_suites{$suite}) { + my $fb_result = read_entry_simple( $hash, $key, $archives, $fb_suite ); + my $fb_virt = shift(@$fb_result); + $virt{$suite} .= $virt{$suite} ? " $fb_virt" : $fb_virt if $fb_virt; + return [ $virt{$suite}, @$fb_result ] if @$fb_result; + } + return [ $virt{$suite} ]; } + sub read_src_entry_all { my ($hash, $key, $results, $non_results, $opts) = @_; my $result = $hash->{$key} || ''; - debug( "read_src_entry_all: key=$key", 1); + debug( "read_src_entry_all: key=$key", 1) if DEBUG; foreach (split /\000/o, $result) { my @data = split ( /\s/o, $_, 6 ); - debug( "Considering entry ".join( ':', @data), 2); + debug( "Considering entry ".join( ':', @data), 2) if DEBUG; if ($opts->{h_archives}{$data[0]} && $opts->{h_suites}{$data[1]} && $opts->{h_sections}{$data[2]}) { - debug( "Using entry ".join( ':', @data), 2); + debug( "Using entry ".join( ':', @data), 2) if DEBUG; push @$results, [ $key, @data ]; } else { push @$non_results, [ $key, @data ]; @@ -414,23 +154,29 @@ sub read_src_entry { read_src_entry_all( $hash, $key, $results, \@non_results, $opts ); } sub do_names_search { - my ($keyword, $packages, $postfixes, $read_entry, $opts, + my ($keywords, $packages, $postfixes, $read_entry, $opts, $results, $non_results) = @_; - $keyword = lc $keyword; + my $first_keyword = lc shift @$keywords; + @$keywords = map { lc $_ } @$keywords; - my ($key, $prefixes) = ($keyword, ''); + my ($key, $prefixes) = ($first_keyword, ''); my %pkgs; $postfixes->seq( $key, $prefixes, R_CURSOR ); - while (index($key, $keyword) >= 0) { + while (index($key, $first_keyword) >= 0) { if ($prefixes =~ /^\001(\d+)/o) { - debug( "$key has too many hits", 2 ); + debug( "$key has too many hits", 2 ) if DEBUG; $too_many_hits += $1; } else { + PREFIX: foreach (split /\000/o, $prefixes) { $_ = '' if $_ eq '^'; - debug( "add word $_$key", 2); - $pkgs{$_.$key}++; + my $word = "$_$key"; + foreach my $k (@$keywords) { + next PREFIX unless $word =~ /\Q$k\E/; + } + debug( "add word $word", 2) if DEBUG; + $pkgs{$word}++; } } last if $postfixes->seq( $key, $prefixes, R_NEXT ) != 0; @@ -440,39 +186,49 @@ sub do_names_search { my $no_results = keys %pkgs; if ($too_many_hits || ($no_results >= 100)) { $too_many_hits += $no_results; - %pkgs = ( $keyword => 1 ); + %pkgs = ( $first_keyword => 1 ) unless @$keywords; } foreach my $pkg (sort keys %pkgs) { &$read_entry( $packages, $pkg, $results, $non_results, $opts ); } } sub do_fulltext_search { - my ($keyword, $file, $did2pkg, $packages, $read_entry, $opts, + my ($keywords, $file, $did2pkg, $packages, $read_entry, $opts, $results, $non_results) = @_; # NOTE: this needs to correspond with parse-packages! - $keyword =~ tr [A-Z] [a-z]; - if ($opts->{exact}) { - $keyword = " $keyword "; + my @tmp; + foreach my $keyword (@$keywords) { + $keyword =~ tr [A-Z] [a-z]; + if ($opts->{exact}) { + $keyword = " $keyword "; + } + $keyword =~ s/[(),.-]+//og; + $keyword =~ s;[^a-z0-9_/+]+; ;og; + push @tmp, $keyword; } - $keyword =~ s/[(),.-]+//og; - $keyword =~ s#[^a-z0-9_/+]+# #og; + my $first_keyword = shift @tmp; + @$keywords = @tmp; my $numres = 0; my %tmp_results; # fgrep is seriously faster than using perl - open DESC, '-|', 'fgrep', '-n', '--', $keyword, $file + open DESC, '-|', 'fgrep', '-n', '--', $first_keyword, $file or die "couldn't open $file: $!"; + LINE: while () { + foreach my $k (@$keywords) { + next LINE unless /\Q$k\E/; + } /^(\d+)/; my $nr = $1; - debug( "Matched line $_", 2); + debug( "Matched line $_", 2) if DEBUG; my $result = $did2pkg->{$nr}; foreach (split /\000/o, $result) { my @data = split /\s/, $_, 3; -# debug ("Considering $data[0], arch = $data[2]", 3); +# debug ("Considering $data[0], arch = $data[2]", 3) if DEBUG; # next unless $data[2] eq 'all' || $opts->{h_archs}{$data[2]}; -# debug ("Ok", 3); +# debug ("Ok", 3) if DEBUG; $numres++ unless $tmp_results{$data[0]}++; } last if $numres > 100; @@ -494,11 +250,11 @@ sub find_binaries { foreach (split /\000/o, $bins) { my @data = split /\s/, $_, 5; - debug( "find_binaries: considering @data", 3 ); + debug( "find_binaries: considering @data", 3 ) if DEBUG; if (($data[0] eq $archive) && ($data[1] eq $suite)) { $bins{$data[2]}++; - debug( "find_binaries: using @data", 3 ); + debug( "find_binaries: using @data", 3 ) if DEBUG; } }