pkgsrc-wip/pkg_summary-utils/files/pkg_src_summary.in
Aleksey Cheusov 7f93979018 pkg_src_summary: final implementation for PSS_PRE_PATH and PSS_POST_PATH
manual page update
version -> 0.31.0
2009-08-09 18:13:38 +00:00

656 lines
16 KiB
Bash
Executable file

#!@SH@
#-*-mode: sh -*-
# Copyright (c) 2007-2008 Aleksey Cheusov <vle@gmx.net>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
set -e
export PATH=$PSS_PRE_PATH:$PATH:$PSS_POST_PATH
. pipestatus
export LC_ALL=C
############################################################
# user settable variables
if test -z "$PKGSRCDIR"; then
PKGSRCDIR=/usr/pkgsrc
fi
if test -z "$BMAKE"; then
BMAKE=make
fi
if test -z "$PSS_MKSCRIPTSDIR"; then
PSS_MKSCRIPTSDIR=@@mkscriptsdir@@
fi
############################################################
usage (){
cat 1>&2 <<EOF
pkg_src_summary - builds summary information
about source packages
usage:
pkg_src_summary [OPTIONS] [pkgpath1 pkgpath2 ...]
pkg_src_summary -s [OPTIONS]
pkg_src_summary -i [OPTIONS]
OPTIONS:
-h|--help display this help message
-p|--make-plist generate PLIST using 'bmake plist'
-i|--installed generate src_summary for the installed packages only,
do not read list of packages from stdin and
from pkgpathN arguments
-f|--fields <fields> list of fields (separated by space or comma)
to be included to summary,
by default FULL summary is generated
-s|--slave-mode ready for use as paexec slave/remote program
(used internally for generating summary in parallel
when PSS_SLAVES is set)
-a|--add-fields <fields> add the specified fields to the list
of default ones
-r|--rem-fields <fields> remove the specified fields from the list
of default ones
-d|--with-deps also generates summary for dependancies (DEPENDS)
-D|--with-bdeps also generates summary for dependancies (BUILD_DEPENDS)
-A|--with-alldeps implies -d and -D
-m|--multi generate ASSIGNMENTS field
for multi-variant packages
-M|--MULTI implies -m and move/add ASSIGNMENTS to PKGPATH field
-G|--debug for debugging
EOF
}
# list of fields for default pkg_src_summary
if test -z "$PSS_FIELDS"; then
PSS_FIELDS='PKGNAME PKGPATH DEPENDS BUILD_DEPENDS CONFLICTS HOMEPAGE COMMENT LICENSE ONLYFOR NOTFOR MAINTAINER CATEGORIES NO_BIN_ON_FTP NO_SRC_ON_FTP NO_BIN_ON_CDROM NO_SRC_ON_CDROM LICENSE ALLSRCFILES DESCRIPTION PLIST' # CVS_CHECKSUM'
fi
if test -z "$PSS_PPERS"; then
PSS_PPERS=10
fi
add_fields (){
rem_fields "$@"
for f in "$@"; do
PSS_FIELDS="$PSS_FIELDS $f"
done
}
rem_fields (){
for f in "$@"; do
PSS_FIELDS="$(echo $PSS_FIELDS | sed s,$f,,g)"
done
}
process_options (){
while test $# -ne 0; do
case "$1" in
-h|--help)
usage
exit 0;;
-f|--fields)
PSS_FIELDS="$(echo $2 | tr , ' ')"
shift;;
-f=*)
printf '%s\n' '-f= is not allowed' 1>&2
exit 1;;
-a=*)
printf '%s\n' '-a= is not allowed' 1>&2
exit 1;;
-r=*)
printf '%s\n' '-r= is not allowed' 1>&2
exit 1;;
--fields=*)
PSS_FIELDS="$(echo $1 | cut -f2 -d= | tr , ' ')";;
-f*)
PSS_FIELDS="$(echo $1 | cut -b 3- | tr , ' ')";;
-a|--add-fields)
add_fields $(echo $2 | tr , ' ')
shift;;
--add-fields=*)
add_fields $(echo $1 | cut -f2 -d= | tr , ' ');;
-a*)
add_fields $(echo $1 | cut -b 3- | tr , ' ');;
-r|--rem-fields)
rem_fields $(echo $2 | tr , ' ')
shift;;
--rem-fields=*)
rem_fields $(echo $1 | cut -f2 -d= | tr , ' ');;
-r*)
rem_fields $(echo $1 | cut -b 3- | tr , ' ');;
-s|--slave-mode)
slave=1;;
-p|--make-plist)
make_plist='-p';;
-d|--with-deps)
with_dep=1;;
-D|--with-bdeps)
with_bdep=1;;
-A|--with-alldeps)
add_fields DEPENDS BUILD_DEPENDS
with_dep=1
with_bdep=1;;
-m)
multi_var=1;;
-M)
multi_var=2;;
-i|--installed)
installed_pkgs=1;;
-G)
debug=1;;
--)
shift
break;;
-*)
echo "Unrecognized option " $1 ". Type --help to see usage" 1>&2
exit 1;;
*)
break;;
esac
shift
done
pkgpaths="$@"
}
process_options $PSS_OPTIONS "$@"
if test "$multi_var"; then
# VARIANTS - artificial field keeping all variable assignments
# for multi-variant packages.
add_fields '_VARIANTS'
fi
if test -n "$with_dep"; then
add_fields DEPENDS
fi
if test -n "$with_bdep"; then
add_fields BUILD_DEPENDS
fi
if echo "$PSS_FIELDS" | grep DESCRIPTION > /dev/null; then
field_descr=1
fi
if echo "$PSS_FIELDS" | grep PLIST > /dev/null; then
field_plist=1
fi
if echo "$PSS_FIELDS" | grep CVS_CHECKSUM > /dev/null; then
field_cvs_checksum=1
fi
varnames="`echo $PSS_FIELDS |
awk '{gsub(/PLIST/, \"\")
gsub(/CVS_CHECKSUM/, \"\")
gsub(/ONLYFOR/, \"ONLY_FOR_PLATFORM\")
gsub(/NOTFOR/, \"NOT_FOR_PLATFORM\")
gsub(/DESCRIPTION/, \"DESCR_SRC\")
print}'`"
############################################################
cd $PKGSRCDIR
tmp_dir="/tmp/pkg_src_summary.$$"
trap "rm -rf $tmp_dir" 0 1 2 15
mkdir -m 700 "$tmp_dir"
tmpfn=$tmp_dir/pkgdirs2info.txt
errsfn=$tmp_dir/errors.txt
summaryfn=$tmp_dir/summary.txt
real_plistfn=$tmp_dir/real_plist.txt
multi_pkgs_fn=$tmp_dir/multi_pkgs.txt
normal_pkgs_fn=$tmp_dir/normal_pkgs.txt
############################################################
enrich_summary (){
awk '
$0 ~ /^DESCR_SRC=/ {
$0 = substr($0, 11)
for (i=1; i <= NF; ++i){
while (0 < ret = (getline ln < $i)){
print "DESCRIPTION=" ln
}
if (ret < 0){
printf "reading from `" $i "` failed\n" > "/dev/stderr"
exit 1
}
close($i)
}
next
}
{
gsub(/ONLY_FOR_PLATFORM/, "ONLYFOR")
gsub(/NOT_FOR_PLATFORM/, "NOTFOR")
print
}' "$@"
}
prepand_PLIST () {
awk '/^[^@]/ {print "PLIST=" $0}' "$@"
}
pkgpath2multivar_opts (){
# textproc/dictem:EMACS_TYPE=xemacs215 -> EMACS_TYPE=xemacs215
# sysutils/mc:PKG_OPTIONS.mc=-x11~-slang -> PKG_OPTIONS.mc='-x11 -slang'
# sysutils/mc:A=a,B=b -> A=a B=b
sed -e 's|^[^:]*:||' -e 's|,| |g' -e "s|[^ ][^ ]*|'&'|g" -e 's|~| |g'
}
cd_and_print_summary (){
# $1 - pkgpath
real_pkgpath="`echo $1 | cut -d: -f1`"
if test "$real_pkgpath" = "$1"; then
var_assigns=''
else
var_assigns="$(echo $1 | pkgpath2multivar_opts)"
var_assignments="_ASSIGNMENTS='$(echo $1 | sed 's,^[^:]*:,,')'"
fi
extra_mk=''
if test -f mk/pbulk/pbulk-index.mk; then
extra_mk='-f ../../mk/pbulk/pbulk-index.mk'
fi
# INHER_ASSIGNS must be before DEPENDS and BUILD_DEPENDS, see below
( cd "$real_pkgpath" && eval ${BMAKE} -f ./Makefile $extra_mk \
-f "$PSS_MKSCRIPTSDIR"/pkg_src_summary.mk my-show-vars \
VARNAMES="'_INHER_ASSIGNS _INHER_ASSIGNS_REJ ASSIGNMENTS $varnames'" \
$var_assignments $var_assigns ) > "$tmpfn" || return 1
enrich_summary "$tmpfn" >"$summaryfn" || return 1
# CVS_CHECKSUM
if test "$field_cvs_checksum"; then
cvs_checksum "$real_pkgpath" > "$tmpfn" || return 1
read cksum < "$tmpfn" || return 1
printf "CVS_CHECKSUM=%s\n" "$cksum" >>"$summaryfn" || return 1
fi
# PLIST
if test "$field_plist"; then
if test -n "$make_plist" && \
rm -f "$real_plistfn" && \
( cd "$real_pkgpath" && \
eval ${BMAKE} PLIST="$real_plistfn" $var_assigns plist 2>/dev/null 1>&2)
then
prepand_PLIST "$real_plistfn" >> "$summaryfn" || return 1
else
plist_fns="$(cd $real_pkgpath && ${BMAKE} show-var VARNAME=PLIST_SRC)"
for plist_fn in $plist_fns; do
if test -f $plist_fn; then
prepand_PLIST $plist_fn >>"$summaryfn" || return 1
fi
done
fi
fi
}
summary2deps (){
awk '
match($0, /^(BUILD_)?DEPENDS=/) {
$0=substr($0, RLENGTH+1)
gsub(/[^ :]*:[.][.]\/[.][.]\//, "")
print
}' "$@"
}
generate_summary (){
# general information
if cd_and_print_summary $1 2>"$errsfn"
then
all_deps=$(summary2deps "$summaryfn")
bad_deps=''
for d in $all_deps; do
if ! test -d "$PKGSRCDIR/$d"; then
if test -z "$bad_deps"; then
printf ' ------------------\n' 1>&2
printf "Bad package %s, skipped\n" "$1" 1>&2
fi
bad_deps=1
printf " not existing dependancy: %s\n" "$d" 1>&2
fi
done
if test -z "$bad_deps"; then
cat "$summaryfn"
echo '' # empty line - separator
fi
else
printf ' ------------------\n' 1>&2
printf "Bad package %s, skipped\n" "$1" 1>&2
cat "$errsfn" 1>&2
fi
}
############################################################
installed_packages2stdout (){
pkg_info -X '*' | sed -n 's,^PKGPATH=,,p'
}
packages2stdout__1per_line (){
if test -n "$installed_pkgs"; then
installed_packages2stdout
elif test $# -eq 0; then
# processing stdin
cat
else
# processing arguments
for pkgpath in "$@"; do
echo "$pkgpath"
done
fi
}
packages2stdout (){
packages2stdout__1per_line "$@" |
awk -v pss_ppers=$PSS_PPERS '
{
printf " %s", $0
}
(NR % pss_ppers) == 0 {
printf "\n"
}
END {
if ((NR % pss_ppers) != 0){
printf "\n"
}
}'
}
process_one_by_one (){
if test "$slave"; then
prepand="awk '"'{print " " $0}'"'"
else
prepand=cat
fi
while read pkgpaths; do
for pkgpath in $pkgpaths; do
generate_summary "$pkgpath" | eval $prepand
done
if test "$slave"; then
printf 'success\n\n' # for paexec
fi
done
}
############################################################
# direct packages
partial_summary_fn=$tmp_dir/partial_summary.txt
if test "$PSS_SLAVES"; then
qfields="$(echo $PSS_FIELDS | sed 's| |,|g')"
environ="PSS_SLAVES= BMAKE=$BMAKE CKSUM=$CKSUM PKGSRCDIR=$PKGSRCDIR"
environ="$environ PSS_PRE_PATH=$PSS_PRE_PATH PSS_POST_PATH=$PSS_POST_PATH"
runpipe0 \
packages2stdout $pkgpaths '|' \
paexec -slez $PSS_PAEXEC_EXTRA_OPTS \
-n "$PSS_SLAVES" \
-t "$PSS_TRANSPORT" \
-c "env $environ $0 -s -f '$qfields'" '|' \
paexec_reorder -s > "$partial_summary_fn"
elif test "$slave"; then
process_one_by_one
exit 0
else
PSS_PPERS=1 # one package per line for local running
runpipe0 \
packages2stdout $pkgpaths '|' \
process_one_by_one > "$partial_summary_fn"
fi
############################################################
# multi-variant packages
export PSS_FIELDS
summary2all_variants (){
awk '
$1 ~ /PKGPATH=/ {
pkgpath = substr($0, 9)
next
}
$1 ~ /_VARIANTS=/ {
variants = substr($0, 11)
next
}
NF == 0 {
$0 = variants
count = 0
for (k=1; k <= NF; ++k){
values = varname = $k
sub(/=.*$/, "", varname)
sub(/^[^=]*=/, "", values)
cnt = split(values, vals, /,/)
if (count){
new_count = count
for (i=1; i <= count; ++i){
if (!(i in variant)) continue
for (j=1; j <= cnt; ++j){
++new_count
variant [new_count] = (variant [i] "," varname "=" vals [j])
}
delete variant [i]
}
count = new_count
}else{
for (j=1; j <= cnt; ++j){
variant [j] = (varname "=" vals [j])
}
count = cnt
}
}
for (i = 1; i <= count; ++i){
if (i in variant)
print pkgpath ":" variant [i]
}
pkgpath = variants = ""
delete variant
}
' "$@"
}
if test "_$multi_var" = _2; then
move_ASSIGNMENTS_to_PKGPATH (){
pkg_assignments2pkgpath "$@"
}
else
move_ASSIGNMENTS_to_PKGPATH (){
cat "$@"
}
fi
if test "$multi_var"; then
pkg_grep_summary _VARIANTS 'fvalue != ""' \
< $partial_summary_fn >$multi_pkgs_fn
if test -s $multi_pkgs_fn; then
pkg_grep_summary -e _VARIANTS \
< $partial_summary_fn >$normal_pkgs_fn
mv $normal_pkgs_fn $partial_summary_fn
runpipe0 \
summary2all_variants < $multi_pkgs_fn '|' \
pkg_src_summary $make_plist '|' \
move_ASSIGNMENTS_to_PKGPATH >> "$partial_summary_fn"
fi
fi
############################################################
# dependencies
extra_deps_fn=$tmp_dir/extra_deps.txt
processed_pkgs_fn=$tmp_dir/processed_pkgs.txt
get_processed_pkgs (){
awk '
NF == 0 {
if (assigns != "")
pkgpath = pkgpath ":" assigns
print pkgpath
if (assigns_rej != "")
print pkgpath (assigns != "" ? "," : ":") assigns_rej
pkgpath = assigns_rej = assigns = ""
next
}
/^PKGPATH=/ {
pkgpath = substr($0, 9)
next
}
/^ASSIGNMENTS=/ {
assigns = substr($0, 13)
next
}
/^_INHER_ASSIGNS_REJ=/ {
assigns_rej = substr($0, 20)
next
}
' "$@"
}
get_processed_pkgs < "$partial_summary_fn" > "$processed_pkgs_fn"
while test -n "${with_dep}${with_bdep}"; do
runawk -v with_dep=$with_dep -v with_bdep=$with_bdep \
-v processed_pkgs_fn=$processed_pkgs_fn -e '
#use "xgetline.awk"
BEGIN {
while (xgetline0(processed_pkgs_fn)){
processed_pkgs [$0] = 1
}
}
/^PKGPATH=/ {
pkgpaths [substr($0, 9)] = 1
next
}
NF == 0 {
inher_assigns = ""
next
}
/^_INHER_ASSIGNS=/ {
inher_assigns = ":" substr($0, 16)
next
}
(with_dep && /^DEPENDS=/) || (with_bdep && /^BUILD_DEPENDS=/) {
sub(/^[^=]*=/, "")
gsub(/[^ ]*:[.][.]\/[.][.]\//, "")
for (i=1; i <= NF; ++i){
sub(/\/+$/, "", $i)
depends [$i inher_assigns] = 1
}
next
}
END {
for (d in depends){
if (! (d in pkgpaths) && ! (d in processed_pkgs)){
print d
}
}
}
' "$partial_summary_fn" > "$extra_deps_fn"
if test -s "$extra_deps_fn"; then
if test -n "$debug"; then
echo ===== extra_deps: ========= 1>&2
sort "$extra_deps_fn" 1>&2
fi
runpipe0 \
env _PSS_RECURS=1 $0 $make_plist < "$extra_deps_fn" '|' \
tee -a "$partial_summary_fn" '|' \
get_processed_pkgs >> "$processed_pkgs_fn"
pkg_uniq_summary "$partial_summary_fn" > "$partial_summary_fn".tmp
mv "$partial_summary_fn".tmp "$partial_summary_fn"
cat "$extra_deps_fn" >> "$processed_pkgs_fn"
else
break
fi
done
remove_intrernal_fields (){
grep -v '^_.*=' "$@" || true
}
enrich_XDEPENDS (){
awk '
FILENAME == "-" {
if (/^PKGPATH=/){
pkgpath = substr($0, 9)
}else if (/^ASSIGNMENTS=/){
assigns = substr($0, 13)
}else if (NF == 0){
if (assigns != ""){
p2a [pkgpath, assigns] = 1
}
assigns = pkgpath = ""
}
next
}
assigns != "" && match($0, /^(BUILD_)?DEPENDS=/) {
field = substr($0, 1, RLENGTH)
$0 = substr($0, RLENGTH+1)
for (i=1; i <= NF; ++i){
idx = index($i, ":")
pkgpath = substr($i, idx+1)
sub(/^[.][.]\/[.][.]\//, "", pkgpath)
if ((pkgpath SUBSEP assigns ) in p2a){
$i = $i ":" assigns
}
}
print field $0
next
}
{
if (/^ASSIGNMENTS=/){
assigns = substr($0, 13)
}else if (/^PKGPATH=/){
pkgpath = substr($0, 9)
}
}
{
print $0
}
NF == 0 {
assigns = pkgpath = ""
}
' - "$1" < "$1"
}
if test -z "$_PSS_RECURS"; then
enrich_XDEPENDS "$partial_summary_fn" |
remove_intrernal_fields
else
remove_intrernal_fields "$partial_summary_fn"
fi