rpm-build/scripts/find-package.in
Alexey Tourbin 5909f93e30 find-package (FindByName): optimized awk script
It looks like that, unlike in perl, pattern matching in awk is very slow.
Perhaps they just don't have regexp engine hackers like Larry Wall or
Ilya Zakharevich (or, most recently, Yves Orton aka demerphq).

That's okay, since I can rewrite the script without pattern matching at all.
That is, I don't have to split each index line into dir+basename, because
I can prepare all valid absolute pathnames in advance.

Old speed:

$ time /usr/lib/rpm/shell.req -v /dev/stdin <<<`rpm -ql rpm-utils |sed -n 's|/usr/bin/||p'`
shell.req: add_changelog -> /usr/bin/add_changelog -> rpm-utils (via content index)
shell.req: buildreq -> /usr/bin/buildreq -> rpm-utils (via content index)
shell.req: cleanup_spec -> /usr/bin/cleanup_spec -> rpm-utils (via content index)
shell.req: compare_packages -> /usr/bin/compare_packages -> rpm-utils (via content index)
shell.req: filereq -> /usr/bin/filereq -> rpm-utils (via content index)
shell.req: packageof -> /usr/bin/packageof -> rpm-utils (via content index)
shell.req: packagereq -> /usr/bin/packagereq -> rpm-utils (via content index)
shell.req: rebuild_package -> /usr/bin/rebuild_package -> rpm-utils (via content index)
shell.req: rebuild_packages -> /usr/bin/rebuild_packages -> rpm-utils (via content index)
shell.req: rpmdups -> /usr/bin/rpmdups -> rpm-utils (via content index)
shell.req: rpmevrcmp -> /usr/bin/rpmevrcmp -> rpm-utils (via content index)
shell.req: rpmrdups -> /usr/bin/rpmrdups -> rpm-utils (via content index)
shell.req: rpmvercmp -> /usr/bin/rpmvercmp -> rpm-utils (via content index)
shell.req: stamp_spec -> /usr/bin/stamp_spec -> rpm-utils (via content index)
rpm-utils
/usr/lib/rpm/shell.req -v /dev/stdin <<<   5.37s user 0.11s system 96% cpu 5.683 total
$

New speed:

$ time /usr/lib/rpm/shell.req -v /dev/stdin <<<`rpm -ql rpm-utils |sed -n 's|/usr/bin/||p'`
shell.req: add_changelog -> /usr/bin/add_changelog -> rpm-utils (via content index)
shell.req: buildreq -> /usr/bin/buildreq -> rpm-utils (via content index)
shell.req: cleanup_spec -> /usr/bin/cleanup_spec -> rpm-utils (via content index)
shell.req: compare_packages -> /usr/bin/compare_packages -> rpm-utils (via content index)
shell.req: filereq -> /usr/bin/filereq -> rpm-utils (via content index)
shell.req: packageof -> /usr/bin/packageof -> rpm-utils (via content index)
shell.req: packagereq -> /usr/bin/packagereq -> rpm-utils (via content index)
shell.req: rebuild_package -> /usr/bin/rebuild_package -> rpm-utils (via content index)
shell.req: rebuild_packages -> /usr/bin/rebuild_packages -> rpm-utils (via content index)
shell.req: rpmdups -> /usr/bin/rpmdups -> rpm-utils (via content index)
shell.req: rpmevrcmp -> /usr/bin/rpmevrcmp -> rpm-utils (via content index)
shell.req: rpmrdups -> /usr/bin/rpmrdups -> rpm-utils (via content index)
shell.req: rpmvercmp -> /usr/bin/rpmvercmp -> rpm-utils (via content index)
shell.req: stamp_spec -> /usr/bin/stamp_spec -> rpm-utils (via content index)
rpm-utils
/usr/lib/rpm/shell.req -v /dev/stdin <<<   0.34s user 0.10s system 88% cpu 0.499 total
$

More than ten times faster, wow!
I didn't know regexp engine could be that slow, really.
2007-03-12 15:06:11 +03:00

186 lines
5.6 KiB
Bash
Executable File

#!/bin/sh -efu
#
# Copyright (C) 2002-2003 Dmitry V. Levin <ldv@altlinux.org>
# Copyright (C) 2007 Alexey Tourbin <at@altlinux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
. @RPMCONFIGDIR@/functions
RPM_FINDPACKAGE_PATH="${RPM_FINDPACKAGE_PATH-}:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin"
RPM_FINDPACKAGE_PATH="$(IFS="$IFS:"; set -f; echo '' $RPM_FINDPACKAGE_PATH |sed -e 's/ */:/g; s/^://')"
Debug "RPM_FINDPACKAGE_PATH=$RPM_FINDPACKAGE_PATH"
FindByPath()
{
# Dependence name starts with `/'.
local f="$1" rep="$2" package; shift 2 || return
# Does it start with buildroot?
if [ -n "${RPM_BUILD_ROOT-}" ] && [ -z "${rep##$RPM_BUILD_ROOT*}" ]; then
Info "$f: invalid dependence: $rep"
return 1
fi
# Does it belong to buildroot?
if [ -n "${RPM_BUILD_ROOT-}" ] && [ -e "$RPM_BUILD_ROOT$rep" ]; then
Verbose "$f: $rep -> \$RPM_BUILD_ROOT$rep (skip)"
return
fi
# Is it an alternative?
if readlink "$rep" |grep -qs '^/etc/alternatives/'; then
Verbose "$f: $rep -> $rep (alternative)"
printf %s\\n "$rep"
return
fi
# Check for pkg contents complete index and pkg binary index.
local idx
for idx in "${RPM_PKG_CONTENTS_INDEX_ALL-}" "${RPM_PKG_CONTENTS_INDEX_BIN-}"; do
[ -n "$idx" ] && [ -s "$idx" ] && [ -r "$idx" ] || continue
package="$(awk -v "f=$rep" '($1 == f) {print $2}' "$idx" |sort -u)"
local n="$(IFS=$'\n'; set -- $package; echo $#)"
if [ "$n" = 1 ]; then
Verbose "$f: $rep -> $package (via content index)"
printf %s\\n "$package"
return
elif [ "$n" -gt 1 ]; then
Info "$f: $rep indexed by:$(echo '' $package)"
Verbose "$f: $rep -> $rep (raw, ambiguous, via content index)"
printf %s\\n "$rep"
return
fi
done
# Check package database.
if package="$(rpmquery --whatprovides --queryformat='%{NAME}\n' -- "$rep")"; then
package="$(printf %s "$package" |LC_COLLATE=C sort -u)"
local n="$(IFS=$'\n'; set -- $package; echo $#)"
if [ "$n" = 1 ]; then
Verbose "$f: $rep -> $package (via rpmdb)"
printf %s\\n "$package"
return
elif [ "$n" -gt 1 ]; then
Info "$f: $rep provided by:$(echo '' $package)"
Verbose "$f: $rep -> $rep (raw, ambiguous, via rpmdb)"
printf %s\\n "$rep"
return
fi
fi
# Not found; output raw dependence.
Verbose "$f: $rep -> $rep (raw, not found)"
printf %s\\n "$rep"
}
FindByName()
{
local f="$1" r="$2" rep package; shift 2 || return
# Check buildroot first.
if [ -n "${RPM_BUILD_ROOT-}" ]; then
local RPATH
RPATH="$(printf %s "$RPM_FINDPACKAGE_PATH" |sed -e "s|[^:]\+|$RPM_BUILD_ROOT&|g")"
if rep="$(PATH="$RPATH" /usr/bin/which -- "$r" 2>/dev/null)"; then
Verbose "$f: $r -> \$RPM_BUILD_ROOT${rep#$RPM_BUILD_ROOT} (skip)"
return
fi
fi
# Check for pkg contents binary index.
rep= package=
if [ -n "${RPM_PKG_CONTENTS_INDEX_BIN-}" ] && [ -s "$RPM_PKG_CONTENTS_INDEX_BIN" ] && [ -r "$RPM_PKG_CONTENTS_INDEX_BIN" ]; then
local out="$(awk -v r="$r" -v RPM_FINDPACKAGE_PATH="$RPM_FINDPACKAGE_PATH" '
BEGIN {
n = split(RPM_FINDPACKAGE_PATH, ary, ":")
for (i = 1; i <= n; i++) {
dir = ary[i]
sub("/+$", "", dir)
file = dir "/" r
if (dir && !(file in FILES))
FILES[file] = i
}
}
NF==2 && ($1 in FILES) {
print FILES[$1] "\t" $1 "\t" $2
}
' "$RPM_PKG_CONTENTS_INDEX_BIN" |
sort -n |sort -u -k3 |sort -n |cut -f2-)"
local n="$(IFS=$'\n'; set -- $out; echo $#)"
if [ "$n" = 1 ]; then
rep="$(IFS=$'\t\n'; set -- $out; printf %s "$1")"
package="$(IFS=$'\t\n'; set -- $out; printf %s "$2")"
Verbose "$r -> $rep -> $package (via content index)"
printf %s\\n "$package"
return
elif [ "$n" -gt 1 ]; then
Info "$f: $r indexed by:$(printf %s "$out" |sed -e 's/\t/ -> /; s/$/,/; $s/,$//' |xargs echo '')"
rep="$(IFS=$'\t\n'; set -- $out; printf %s "$1")"
package="$(IFS=$'\t\n'; set -- $out; printf %s "$2")"
local rep2="$(IFS=$'\t\n'; set -- $out; printf %s "$3")"
if [ "$rep" = "$rep2" ]; then
Verbose "$f: $r -> $rep -> $rep (raw, ambiguous, via content index)"
printf %s\\n "$rep"
return
fi
fi
fi
# Lookup in the host system.
local irep="$rep"
if rep="$(PATH="$RPM_FINDPACKAGE_PATH" /usr/bin/which --all -- "$r" 2>/dev/null)"; then
local n="$(IFS=$'\n'; set -- $rep; echo $#)"
if [ "$n" -gt 1 ]; then
n="$(IFS=$'\n'; for f in $rep; do readlink -vm "$f"; done |sort -u |wc -l)"
[ "$n" = 1 ] || Info "$f: which $r:$(echo '' $rep)"
rep="$(IFS=$'\n'; set -- $rep; printf %s "$1")"
fi
if [ -n "$rep" ]; then
Verbose "$f: $r -> $rep -> ... (via which)"
FindByPath "$f" "$rep"
return
fi
fi
# Reconsult pkg contents binary index.
if [ -n "$irep" ] && [ -n "$package" ]; then
rep="$irep"
Verbose "$f: $r -> $rep -> $package (via content index)"
printf %s\\n "$package"
return
fi
# Not found.
Verbose "$f: $r not found (skip)"
}
FindPackage()
{
local f="$1" r; shift || return
for r; do
[ -n "$r" ] || continue
if [ -z "${r##/*}" ]; then
FindByPath "$f" "$r"
elif [ -n "${r##*/*}" ]; then
FindByName "$f" "$r"
else
Verbose "$f: invalid pathname $r"
fi
done
}