pacsearch: rewrite in perl

This rewrite in perl blows the socks off the old shell script version for
large searches:

$ time ./pacsearch.perl ^.*$ >/dev/null
real    0m0.836s
user    0m0.593s
sys     0m0.217s

$ time pacsearch.sh ^.*$ >/dev/null
real    1m53.818s
user    1m16.818s
sys     0m33.694s

Functionality and output is identical to the old version with the exception
of the old version's missing EOL after all the output.  It should be a lot
easier to add new things like the --color flag that has been a TODO at the
top of the script for a long time.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2008-05-09 18:56:15 -05:00
parent b49fc504ac
commit 1ba0d84da2
1 changed files with 103 additions and 60 deletions

View File

@ -1,6 +1,9 @@
#!/bin/bash
#!/usr/bin/perl
# pacsearch - Adds color and install information to a 'pacman -Ss' search
#
# Copyright (C) 2008 Dan McGee <dpmcgee@gmail.com>
#
# Based off original shell script version:
# Copyright (C) 2006-2007 Dan McGee <dpmcgee@gmail.com>
#
# This program is free software; you can redistribute it and/or
@ -18,72 +21,112 @@
#TODO: colors flag on commandline
readonly progname="pacsearch"
readonly version="1.0"
use strict;
use warnings;
readonly CLR1='\\\e[0;34m'
readonly CLR2='\\\e[0;32m'
readonly CLR3='\\\e[0;35m'
readonly CLR4='\\\e[0;36m'
readonly CLR5='\\\e[0;31m'
readonly CLR6='\\\e[0;33m'
readonly CLR7='\\\e[1;36m'
readonly INST='\\\e[1;31m'
readonly BASE='\\\e[0m'
my $progname = "pacsearch";
my $version = "2.0";
if [ "$1" = "--help" -o "$1" = "-h" ]; then
echo "Usage: $progname <pattern>"
echo "Ex: $progname ^gnome"
exit 0
fi
if ($#ARGV lt 0 || $ARGV[0] eq "--help" || $ARGV[0] eq "-h") {
print "$progname - Add color and install information to a pacman -Ss search\n";
print "Usage: $progname <pattern>\n";
print "Example: $progname ^gnome\n";
if ($#ARGV lt 0) {
exit 1;
}
exit 0;
}
if [ "$1" = "--version" -o "$1" = "-v" ]; then
echo "$progname version $version"
echo "Copyright (C) 2006-2007 Dan McGee"
exit 0
fi
if ($ARGV[0] eq "--version" || $ARGV[0] eq "-v") {
print "$progname version $version\n";
print "Copyright (C) 2006-2008 Dan McGee\n";
exit 0;
}
if [ -z "$1" -o "${1:0:1}" = "-" ]; then
echo "Usage: $progname <pattern>"
echo "Ex: $progname ^gnome"
exit 1
fi
# define our colors to use when printing
my $CLR1 = "\e[0;34m";
my $CLR2 = "\e[0;32m";
my $CLR3 = "\e[0;35m";
my $CLR4 = "\e[0;36m";
my $CLR5 = "\e[0;31m";
my $CLR6 = "\e[0;33m";
my $CLR7 = "\e[1;36m";
my $INST = "\e[1;31m";
my $BASE = "\e[0m";
my $INSTMARK = $INST."***";
# Make two temp files and send output of commands to these files
querydump=$(mktemp)
pacman -Qs $1 > $querydump
syncdump=$(mktemp)
pacman -Ss $1 > $syncdump
# color a "repo/pkgname pkgver" line based on the respository name
sub to_color {
my $line = shift;
$line =~ s/(^core\/.*)/$CLR1$1$BASE/;
$line =~ s/(^extra\/.*)/$CLR2$1$BASE/;
$line =~ s/(^community\/.*)/$CLR3$1$BASE/;
$line =~ s/(^testing\/.*)/$CLR4$1$BASE/;
$line =~ s/(^unstable\/.*)/$CLR5$1$BASE/;
$line =~ s/(^custom\/.*)/$CLR6$1$BASE/;
$line =~ s/(^local\/.*)/$CLR7$1$BASE/;
# any other unknown repository
$line =~ s/(^[\w-]*\/.*)/$CLR6$1$BASE/;
return $line;
}
# Strip descriptions and 'local/' from -Qs query
instpkg=$(mktemp)
egrep '^[^ ]' $querydump | sed -e 's@^local/@@' > $instpkg
my %allpkgs = ();
# Add pkgs not in sync db, mark pkgs that are installed
cat $instpkg | while read -r pkg; do
if [ -z "$(grep "$pkg" $syncdump)" ]; then
# grep package name; pipe to another grep that prints at most one
# line starting with 'local/', allows for comments >1 line
grep -A10 "$pkg" $querydump | grep -A10 -m1 "local/" >> $syncdump
fi
sed -i "s@^\(.\+/$pkg\)@\***\1@" $syncdump
done
my $syncout = `pacman -Ss @ARGV`;
# split each sync search entry into its own array entry
my @syncpkgs = split(/\n^(?=\w)/m, $syncout);
# remove the extra \n from the last desc entry
if ($#syncpkgs >= 0) {
chomp($syncpkgs[$#syncpkgs]);
}
# Print colorized package list and descriptions to screen
echo -e "$(sed -r \
-e "s@core/.*@$CLR1&$BASE@" \
-e "s@extra/.*@$CLR2&$BASE@" \
-e "s@community/.*@$CLR3&$BASE@" \
-e "s@testing/.*@$CLR4&$BASE@" \
-e "s@unstable/.*@$CLR5&$BASE@" \
-e "s@custom/.*@$CLR6&$BASE@" \
-e "s@local/.*@$CLR7&$BASE@" \
-e "s@(^|\*\*\*)([[:alnum:]]*/.* .*)@\1$CLR6\2$BASE@" \
-e "s@\*\*\*@$INST&@" \
< $syncdump )"
echo -en "\e[0m"
# counter var for packages, used here and in the query loop too
my $cnt = 0;
foreach $_ (@syncpkgs) {
# we grab 3 fields here: repo, name/ver, and desc
my @pkgfields = /^(.*?)\/(.*?)\n(.*)$/s;
# add a fourth field that will indicate install status
push (@pkgfields, "");
# add a fifth field that indicates original order
push (@pkgfields, $cnt++);
# add each sync pkg by name/ver to a hash table for quick lookup
$allpkgs{$pkgfields[1]} = [ @pkgfields ];
}
rm $querydump
rm $syncdump
rm $instpkg
my $queryout = `pacman -Qs @ARGV`;
# split each querysearch entry into its own array entry
my @querypkgs = split(/\n^(?=\w)/m, $queryout);
# remove the extra \n from the last desc entry
if ($#querypkgs >= 0) {
chomp ($querypkgs[$#querypkgs]);
}
foreach $_ (@querypkgs) {
# we grab 3 fields here: repo, name/ver, and desc
my @pkgfields = /^(.*?)\/(.*?)\n(.*)$/s;
# check if the package was listed in the sync out
# if it is we want to mark it with a *** marker
if (exists $allpkgs{$pkgfields[1]}) {
# mark it in our fourth field as installed
@{ $allpkgs{$pkgfields[1]} }[3] = $INSTMARK;
} else {
# add a fourth field that will indicate install status
push (@pkgfields, $INSTMARK);
# add a fifth field that indicates original order (after sync)
push (@pkgfields, $cnt++);
# add our local-only package to the hash
$allpkgs{$pkgfields[1]} = [ @pkgfields ];
}
}
# sort by original order (the fifth field) and print
foreach $_ ( sort{ @{$allpkgs{$a}}[4] <=> @{$allpkgs{$b}}[4] } keys %allpkgs) {
my @v = @{$allpkgs{$_}};
my $line = "$v[0]/$v[1]";
$line = to_color($line);
# print install marker + colorized "repo/pkgname pkgver" string
print "$v[3]$line\n";
print "$v[2]\n";
}
#vim: set noet: