[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

dpkg searcher



Fed up with dpkg -s/-S/-L/--print-avail being slow?

If so, try this little Perl script I wrote.  Comments and suggestions most
welcome. I'll probably package it properly a bit later on (I need to write a
manpage really).

I've been using Jim Picks "davail" and "dfind" for far too long :-)

fdpkg automatically uses regexps - normally with ".*" prepended and appended
to whatever you say, but you can ask for exact matches and "quit on the
first match". 

It might not be as quick as Jim's programs in some cases, but there's more
than one line to this program (unlike Jim's minimalist code <g>).

Some timings (96MB K6-200):

                     dpkg   fdpkg  fdpkg*  davail/dfind
available (exact):   3.3    1.9    0.16
          (normal):   -     2.0    0.16    1.7
status (exact):      3.4    0.65   0.12
       (normal):      -     0.65   0.12
list (exact):        3.4    0.15   0.11    0.05
     (normal):        -     0.16   0.11
search (exact):      4.5    1.6    0.43
       (normal):      -     1.8    0.47    0.29

fdpkg* = quit on first match
normal = using ".*regexp.*"

fdpkg is slower at list because it's doing more work in the normal case -
it's not bad anyway (unlike dpkg). The search speed could be vastly improved
- but that's for another day. I should get it down to about 0.3/0.4 by doing
"egrep" first and then fixing up what is returned.

Here's to you Jim!

Adrian

email: adrian.bridgett@zetnet.co.uk, http://www.poboxes.com/adrian.bridgett
Windows NT - Unix in beta-testing.   PGP key available on public key servers
Avoid tiresome goat sacrifices  -=-  use Debian Linux http://www.debian.org
#!/usr/bin/perl

# Fast dpkg - copyright Adrian Bridgett 1999

# Fed up with dpkg -l/L/s/S/-print-avail taking ages?
# You need fdpkg

# TODO:
# in $opt_L, remove known directories (look for the next entry have $_/ in it)
# should we print a sort conffiles/list for -LSF?
# for -SLF, how to pick if we print the contents of the *.list which matched?
# -l - needed?
# -i - case insensitive?
# -LSF should use egrep @list initially

# BUGS:
# -F matches directories too - how to check or is "-d ..." good enough?

use Getopt::Std;

sub usage()
{
  print <<'EOF';
  fdpkg v0.1 by Adrian Bridgett

  Usage:  fdpkg [-e] [-t] [-1] -[aLsSF] <regexp>
          -e exact matches only (regexp is unchanged)
          -t wildcard tail of package/filename (uses <regexp>.*)
          -1 exit after first match
          -a print from available list
          -L print list of files
	  -s print current status
	  -S find packages containing name
	  -F find packages containing filename - a stricter "-S"

  NB: Unless "-e" or "-t" are used, the regular expression is used as a
      partial match (it is changed to ".*<regexp>.*").

EOF
}

# grab the arguments
getopts("hHet1aLsSF") || do { usage(); exit 1};
if ($opt_H || $opt_h)
{
  usage();
  exit 0;
}

my $input = $ARGV[0];

# okay, lets use those regexps
$input .= ".*" unless $opt_e;
$input = ".*" . $input unless ($opt_e || $opt_t);
#$input .= "\w*" unless $opt_e;
#$input = "\w*" . $input unless ($opt_e || $opt_t);

# print $1 underlined by "-"
sub title($)
{
  $title = shift;
  print $title, "\n", "-" x length($title), "\n";
}

# print any entries in $2 (in RFC-822 format) which match "Package: $1"
sub search($$)
{
  my ($pattern, $file) = @_;
  open FH, $file || die;
  # lower case it
  $pattern_lc = $pattern;
  $pattern_lc =~ tr/[A-Z]/[a-z]/;
  print "$pattern\n$pattern_q\n";
  while (<FH>)
  {
    # lets try and optimize here ;-)
    if (/^Package: / && /^Package: $pattern_lc$/)
    {
      while (!/^$/)
      {
        print $_;
        $_ = <FH>;
      }
      print "\n";
      exit if ($opt_1);
    }
  }
  close FH;
}

# these two use the same subroutine
search ($input, "/var/lib/dpkg/available") if $opt_a;
search ($input, "/var/lib/dpkg/status") if $opt_s;

# we can't use glob() since regexps don't work on that.
if ($opt_L)
{
  opendir DIR, "/var/lib/dpkg/info" || die;
  # skip "." and ".."
  readdir DIR; readdir DIR;
  while ($_ = readdir DIR)
  {
    # faster having the | inside rather than a || outside
    if (/^$input\.(list|conffiles)$/)
    {
      title ($_);
      open FILE, "/var/lib/dpkg/info/$_" || die;
      print <FILE>;
      print "\n";
      close FILE;
      exit if ($opt_1);
    }
  }
  close DIR;
}

# we could use glob(), but lets keep things the same as above
# besides, man perlop says glob is slow anyway
if ($opt_S || $opt_F)
{
  my $file;
  opendir DIR, "/var/lib/dpkg/info" || die;
  # skip "." and ".."
  readdir DIR; readdir DIR;
  while ($file = readdir DIR)
  {
    if ($file =~ /\.(list|conffiles)$/)
    {
      open FILE, "/var/lib/dpkg/info/$file" || die;
      while (<FILE>)
      {
        if ($opt_F ? /([^\/]*)$/ && $1 =~ /$input/ : /$input/)
        {
          title ($file);
          print;
          while (<FILE>)
          {
            ($opt_F ? /([^\/]*)$/ && $1 =~ /$input/ : /$input/) && print;
          }
          print "\n";
          exit if ($opt_1);
        }
      }
      close FILE;
    }
  }
  close DIR;
}


Reply to: