#!@SH@ #-*-mode: sh -*- # Copyright (c) 2007-2008 Aleksey Cheusov # # 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 PKGSRCDIR=${PKGSRCDIR:=@PKGSRCDIR@} BMAKE=${BMAKE:=@BMAKE@} PSS_MKSCRIPTSDIR=${PSS_MKSCRIPTSDIR:=@@mkscriptsdir@@} ############################################################ usage (){ cat 1>&2 < 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 add the specified fields to the list of default ones -r|--rem-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 -Xa | 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" deps1_all_fn=$tmp_dir/level1_all_deps.txt deps1_needed_fn=$tmp_dir/level1_needed_deps.txt filter_needed_deps (){ runawk -v partial_summary_fn="$partial_summary_fn" -e ' #use "xgetline.awk" #use "pkg_grep_summary.awk" #use "braceexpand.awk" BEGIN { oldFS = FS FS = " " while (xgetline0(partial_summary_fn)){ if (match($0, /^(BUILD_)?DEPENDS=/)) { $0=substr($0, RLENGTH+1) for (i=1; i <= NF; i += 2){ if ($i ~ /[{]/){ $i = braceexpand($i) sub(/ .*$/, "", $i) } gsub(/:[.][.]\/[.][.]\//, " ") sub(/-\[[^\[\]]*\].$|(>|>=|<|<=|=|-)[^><=-]*$/, "", $i) needed [$i, $(i+1)] = 1 } } } FS = oldFS grep_summary__field = "" # all lines will be analysed } function grep_summary__condition ( _res){ if (fname == "PKGNAME"){ pkgname = fvalue sub(/-[^-]+$/, "", pkgname) }else if (fname == "PKGPATH"){ pkgpath = fvalue } if (pkgpath && pkgname){ _res = (pkgname SUBSEP pkgpath) in needed pkgname = pkgpath = "" return _res }else{ return -1 } } ' "$@" } 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" #use "braceexpand.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(/^[^=]*=/, "") for (i=1; i <= NF; ++i){ if ($i ~ /[{]/){ $i = braceexpand($i) sub(/ .*$/, "", $i) } gsub(/[^ ]*:[.][.]\/[.][.]\//, "", $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 -n "$debug"; then echo '===== extra_deps: =========' 1>&2 sort "$extra_deps_fn" 1>&2 fi if ! test -s "$extra_deps_fn"; then break fi env _PSS_RECURS=1 $0 -m $make_plist \ < "$extra_deps_fn" > "$deps1_all_fn" if test -n "$debug"; then echo '===== level-1 deps summaries (multivariant) =========' 1>&2 cat "$deps1_all_fn" 1>&2 fi filter_needed_deps "$deps1_all_fn" > "$deps1_needed_fn" if test -n "$debug"; then echo '===== level-1 deps summaries (needed) =========' 1>&2 cat "$deps1_needed_fn" 1>&2 fi if ! test -s "$deps1_needed_fn"; then break fi cat "$deps1_needed_fn" >> "$partial_summary_fn" pkg_uniq_summary "$partial_summary_fn" > "$partial_summary_fn".tmp mv "$partial_summary_fn".tmp "$partial_summary_fn" get_processed_pkgs "$deps1_needed_fn" >> "$processed_pkgs_fn" done remove_internal_fields (){ grep -v '^_.*=' "$@" || true } enrich_XDEPENDS (){ awk ' FILENAME == "-" { if (/^PKGPATH=/){ pkgpath = substr($0, 9) }else if (/^PKGNAME=/){ pkgbase = substr($0, 9) sub(/-[^-]+$/, "", pkgbase) }else if (/^ASSIGNMENTS=/){ assigns = substr($0, 13) }else if (NF == 0){ if (assigns != ""){ p2a [pkgpath, pkgbase] = assigns } assigns = pkgpath = pkgbase = "" } next } 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) pkgbase = substr($i, 1, idx-1) sub(/-[^-]+$/, "", pkgbase) if ((pkgpath SUBSEP pkgbase) in p2a){ $i = $i ":" p2a [pkgpath, pkgbase] } } print field $0 next } { print $0 } ' - "$1" < "$1" } if test -z "$_PSS_RECURS"; then enrich_XDEPENDS "$partial_summary_fn" | remove_internal_fields else remove_internal_fields "$partial_summary_fn" fi