On Wed, Aug 21, 2013 at 08:37:08PM +0400, Vadim Zhukov wrote:
> Next try, after more input from sthen@ and ajacoutot@. Main changes:
> 
>    * Check that every @lib has contemporary .a in PLIST before
>      suggesting merging PFRAG.share into PLIST.
> 
>    * More correct printing of FLAVOR when referencing a particular
>      FLAVOR/SUBPACKAGE combination.
> 
>    * Add a WANTLIB check for devel/gettext and converters/libiconv,
>      which already found some problems (sending patches one-by-one
>      to interested parties ATM).
> 
>    * Many manual page improvements, from sthen@.
> 
> okay?

Yes, just put it in. It doesn't make sense to keep sending these gigantic diffs.
If something needs to be fixed|enhanced, it can be done in-tree.



> #!/bin/ksh
> #
> # $OpenBSD$
> # Copyright (c) 2013 Vadim Zhukov
> # 
> # Permission to use, copy, modify, and distribute this software for any
> # purpose with or without fee is hereby granted, provided that the above
> # copyright notice and this permission notice appear in all copies.
> # 
> # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> 
> set -e
> set +X
> 
> usage() {
>       echo "usage: ${0##*/} [-CdPU] [-p portsdir] [-x glob]" >&2
>       echo "       ${0##*/} [-AdP] [-p portsdir] [-x glob] [subdir ...]" >&2
>       exit 1
> }
> 
> 
> ############################################################
> # Parsing command line options
> #
> 
> existing_port=false
> ignore_cvs=false
> plist_checks=true
> portsdir=
> rootrun=false
> unset ignore_list
> debugging=false
> 
> while getopts "ACdPp:Ux:" OPT; do
>       case $OPT in
>       A)
>               $rootrun || set -A ignore_list -- "${ignore_list[@]}" \
>                       .cvsignore \
>                       INDEX \
>                       README \
>                       bulk \
>                       distfiles \
>                       infrastructure \
>                       logs \
>                       lost+found \
>                       mystuff \
>                       openbsd-wip \
>                       packages \
>                       plist \
>                       pobj \
>                       update
>               rootrun=true
>               existing_port=true
>               ignore_cvs=true
>               ;;
> 
>       C)
>               ignore_cvs=true
>               ;;
> 
>       d)
>               debugging=true
>               ;;
> 
>       P)
>               plist_checks=false
>               ;;
> 
>       p)
>               if [[ ${PWD##"$OPTARG"} == "$PWD" ]]; then
>                       cat >&2 <<EOE
> ${0##*/}: current directory does not seem to be under the
> specified root directory: $OPTARG.
> EOE
>                       exit 3
>               fi
>               portsdir=$OPTARG
>               ;;
> 
>       U)
>               existing_port=true
>               ;;
> 
>       x)
>               set -A ignore_list -- "${ignore_list[@]}" "$OPTARG"
>               ;;
> 
>       *)
>               usage
>               ;;
>       esac
> done
> 
> shift $(($OPTIND - 1))
> (($# > 0)) && ! $rootrun && usage
> (($# == 0)) && set -- .
> 
> ############################################################
> # Detect path to root of directory tree of current port(-s) and put it
> # in $portsdir, unless it was set by user above. As a last resort, we
> # use some heuristics based on the commonly used names.
> #
> # We also have a $pkgpath variable, that represents subdirectory under
> # root ports directory where the port(-s) will be imported. In case we
> # use heuristics for determining $portsdir, we'll set up $pkgpath, too,
> # since we would get this info anyway.
> #
> # In make_args we write PORTSDIR_PATH override, that allows us to run
> # even in ports directory that is not on the PORTSDIR_PATH. This is
> # useful, for example, when you check your port on cvs.openbsd.org,
> # where you cannot just override mk.conf.
> #
> 
> pkgpath=
> 
> if [[ -z $portsdir ]]; then
>       # heuristics mode ON
>       pkgpath=${PWD##*/ports/*(mystuff/|openbsd-wip/)}
>       portsdir=${PWD%"/$pkgpath"}
>       [[ -n $portsdir ]] &&
>               echo "ports root directory detected: $portsdir" >&2
> fi
> 
> if [[ -z $portsdir ]]; then
>       cat >&2 <<EOE
> ${0##*/}: could not detect root ports directory. Please provide
> one with -p option.
> EOE
>       exit 2
> fi
> 
> # This way we can run all checks even on cvs.openbsd.org
> set -A make_args -- MASTER_SITE_OPENBSD= \
>       PORTSDIR_PATH="$portsdir:$(cd /usr/ports && make -V PORTSDIR_PATH || 
> true)"
> 
> $rootrun && cd -- "$portsdir"
> 
> ############################################################
> # Check and fail routines
> #
> 
> error=false
> 
> err() {
>       local prefix=
>       while (($# > 0)); do
>               printf "$prefix%s" "$1" >&2
>               prefix=" "
>               shift
>       done
>       echo >&2
>       error=true
> }
> 
> err_duplicated() {
>       err "both $2 and some of its parents has $1"
> }
> 
> err_core_found() {
>       err "file or directory \"$1\" found, CVS will ignore it"
> }
> 
> err_coredump_found() {
>       err "core dump file found: $1"
> }
> 
> is_vcs_item() {
>       [[ -d "$1" && ${1##*/} == @(CVS|.fslckout|.git|.hg|.svn) ]]
> }
> 
> ignoring() {
>       local iglob
>       for iglob in "${ignore_list[@]}"; do
>               [[ $1 == $iglob ]] && return 0
>       done
>       return 1
> }
> 
> check_trailing_whitespace() {
>       local check_what=$1; shift
>       local real_path
>       (($# > 0)) && real_path=$1
>       [[ -z $real_path ]] && real_path=$check_what
>       egrep -q '[[:space:]]+$' "$check_what" &&
>               err "trailing whitespace in $real_path"
> }
> 
> handle_extra_file() {
>       ignoring "$1" || return 0
> 
>       # avoid warning, e.g., about ".*"
>       test -e "$1" || return 0
> 
>       if is_vcs_item "$1"; then
>               if ! $ignore_cvs || [[ ${1##*/} != CVS ]]; then
>                       err "VCS item detected: $1"
>               fi
>       elif [[ ${1##*/} == core ]]; then
>               $rootrun || err_core_found "${1%/*}"
>       elif [[ -f $1 && $1 == *.core ]]; then
>               err_coredump_found "$1"
>       elif [[ -d $1 ]]; then
>               err "extra directory: $1"
>       else
>               err "extra file: $1"
>       fi
> }
> 
> # Print out a ref to the particular subport/subpackage, if needed.
> # Port FLAVORs could also be handled, if provided.
> # Usage: portref directory [subpackage [flavor all_flavors]]
> portref() {
>       local dir=$1; shift
>       local subpkg flavor all_flavors
>       if (($# > 0)); then
>               subpkg=$1
>               shift
>       fi
>       if (($# > 0)); then
>               flavor=$1
>               all_flavors=$2
>               shift 2
>       fi
> 
>       local ref=
>       if [[ $dir != . ]]; then
>               ref="${dir#./}"
>               [[ -n $subpkg && $subpkg != "-" ]] && ref="$ref,$subpkg"
>       else
>               [[ $subpkg != "-" ]] && ref="$subpkg"
>       fi
> 
>       if [[ -n $all_flavors ]]; then
>               [[ -n $ref ]] && ref="$ref, "
>               if [[ -z $flavor ]]; then
>                       ref="${ref}default FLAVOR"
>               else
>                       ref="${ref}FLAVOR \"$flavor\""
>               fi
>       fi
> 
>       [[ -n $ref ]] && echo "in $ref: "
> }
> 
> # Checks made:
> #   * Whitelist filter of what could be in this directory.
> check_port_hier() {
>       $debugging && echo "CALLED: check_port_hier($*)" >&2
> 
>       local dir=$1; shift
>       for opt; do
>               # looks unsafe but we do not pass anything except
>               # "foo=true" and "foo=false" here
>               eval "$opt"
>               shift
>       done
> 
>       local distinfo_lives_upper=${distinfo_lives_upper:-false}
>       local pkg_lives_upper=${pkg_lives_upper:-false}
>       local plist_lives_upper=${plist_lives_upper:-false}
> 
>       local distinfo_exists=false
>       [[ -f $dir/distinfo ]] && distinfo_exists=true
>       $distinfo_exists && $distinfo_lives_upper &&
>               err_duplicated distinfo "$dir"
> 
>       local pkg_exists=false
>       [[ -d $dir/pkg ]] && pkg_exists=true
> 
>       local plist_exists=false
>       ls $dir/pkg/PLIST* >/dev/null 2>&1 && plist_exists=true
>       $plist_lives_upper && $plist_exists &&
>               err_duplicated "packing list(-s)" "$dir"
> 
>       $distinfo_lives_upper && distinfo_exists=true
>       $pkg_lives_upper && pkg_exists=true
>       $plist_lives_upper && plist_exists=true
> 
>       local recursive_args
>       set -A recursive_args -- \
>               distinfo_lives_upper=$distinfo_exists \
>               pkg_lives_upper=$pkg_exists \
>               plist_lives_upper=$plist_exists
> 
>       local F
>       for F in "$dir"/* "$dir"/.*; do
>               F=${F#./}
>               ignoring "$F" && continue
> 
>               if is_vcs_item "$F"; then
>                       if ! $ignore_cvs || [[ ${F##*/} != CVS ]]; then
>                               err "VCS item detected: $F"
>                       fi
>               elif [[ -d $F ]]; then
>                       case "${F##*/}" in
>                       files|patches|pkg)
>                               check_${F##*/}_dir "$F"
>                               ;;
> 
>                       patches?(-*))
>                               check_patches_dir "$F"
>                               ;;
> 
>                       *)
>                               if ! $rootrun && [[ ${F##*/} == core ]]; then
>                                       err_core_found "$F"
>                               fi
> 
>                               if ! [[ -f $F/Makefile ]]; then
>                                       # Avoid extra spam
>                                       err "not a port directory: $F"
>                               else
>                                       local pkgpath_set=false
>                                       [[ -n $pkgpath ]] && pkgpath_set=true
>                                       check_port_dir "$F" 
> "${recursive_args[@]}"
>                                       $pkgpath_set || pkgpath=${pkgpath%/*}
>                               fi
>                               ;;
>                       esac
>               else
>                       case "${F##*/}" in
>                       Makefile?(.inc)|*.port.mk)
>                               check_makefile "$F"
>                               ;;
> 
>                       distinfo)
>                               ;;
> 
>                       *)
>                               handle_extra_file "$F"
>                               ;;
>                       esac
>               fi
>       done
>       egrep -q '^ *SUBDIR[[:space:]]*\+?=' Makefile ||
>               err missing subdir Makefile
> }
> 
> # Checks made:
> #   * Whitelist filter of what could be in this directory.
> check_port_dir() {
>       $debugging && echo "CALLED: check_port_dir($*)" >&2
> 
>       local dir=$1; shift
>       for opt; do
>               # looks unsafe but we do not pass anything except
>               # "foo=true" and "foo=false" here
>               eval "$opt"
>               shift
>       done
> 
>       local distinfo_lives_upper=${distinfo_lives_upper:-false}
>       local pkg_lives_upper=${pkg_lives_upper:-false}
>       local plist_lives_upper=${plist_lives_upper:-false}
>  
>       check_perms_in_dir "$dir"
> 
>       if [[ -f $dir/Makefile.inc ]] ||
>             egrep -sq '^ *SUBDIR[[:space:]]*\+?=' "$dir"/Makefile; then
>               check_port_hier "${dir#./}" "$@"
>               return
>       fi
> 
>       local F
>       local distinfo_exists=false
>       local mk_exists=false
>       local pkg_exists=false
>       local plist_exists=false
>       local portmk_exists=true
>       local non_portmk=0
> 
>       for F in "$dir"/* "$dir"/.*; do
>               F=${F#./}
>               ignoring "$F" && continue
>               case ${F##*/} in
>               Makefile)
>                       test -f "$F" || err "$F is not a file"
>                       check_makefile "$F"
>                       mk_exists=true
>                       ((non_portmk++)) || true
>                       ;;
> 
>               distinfo)
>                       $distinfo_lives_upper && err_duplicated distinfo "$dir"
>                       distinfo_exists=true
>                       test -f "$F" || err "$F is not a file"
>                       ((non_portmk++)) || true
>                       ;;
> 
>               *.port.mk)
>                       test -f "$F" || err "$F is not a file"
>                       check_makefile "$F"
>                       portmk_exists=true
>                       ;;
> 
>               systrace.filter)
>                       test -f "$F" || err "$F is not a file"
>                       ((non_portmk++)) || true
>                       ;;
> 
>               files|patches)
>                       if [[ -d $F ]]; then
>                               check_${F##*/}_dir "$F"
>                       else
>                               err "$F" is not a directory
>                       fi
>                       ((non_portmk++)) || true
>                       ;;
> 
>               pkg)
>                       if [[ -d $F ]]; then
>                               check_pkg_dir "$F"
>                               pkg_exists=true
>                               ls "$F"/PLIST* >/dev/null 2>&1 &&
>                                       plist_exists=true
>                               $plist_lives_upper && $plist_exists &&
>                                       err_duplicated "packing list(-s)" "$dir"
>                       else
>                               err "$F" is not a directory
>                       fi
>                       ((non_portmk++)) || true
>                       ;;
> 
>               *)
>                       handle_extra_file "$F"
>                       ;;
>               esac
>       done
> 
>       # examples: lang/clang, www/mozilla
>       $portmk_exists && ((non_portmk == 0)) && return
> 
>       $mk_exists || err no Makefile in "$dir"
>       $pkg_lives_upper && pkg_exists=true
>       $pkg_exists || err "no pkg/ in $dir"
>       $distinfo_lives_upper && distinfo_exists=true
>       $distinfo_exists || $existing_port || err "no distinfo in $dir"
> 
>       # Now gather and check some info via "make show=...".
>       # We request all info at once for speed.
> 
>       local dist_subdir distfiles flavor flavors master_sites modules
>       local multi_packages pseudo_flavors shared_libs
>       local show_items="DIST_SUBDIR DISTFILES FLAVOR FLAVORS FULLPKGNAME"
>       local show_items="$show_items MASTER_SITES MULTI_PACKAGES"
>       local show_items="$show_items PSEUDO_FLAVORS SHARED_LIBS"
> 
>         # Do not try to use co-processes, there is some bug related
>         # to redirection of error stream seen on big number of
>         # nested ports (100 or so). And we need to redirect stderr to
>         # avoid noise when accessing dead co-processes accidentially.
> 
>       (cd -- "$dir"; make "${make_args[@]}" show="$show_items") | {
>               read dist_subdir
>               read distfiles
>               read flavor
>               read flavors
>               read fullpkgname
>               read master_sites
>               read multi_packages
>               read pseudo_flavors
>               read shared_libs
> 
>               set -A check_flavors --
>               [[ -z $flavor ]] && set -A check_flavors -- ""
> 
>               local f pf
>               for f in $flavors; do
>                       for pf in $pseudo_flavors; do
>                               [[ $f == "$pf" ]] && continue 2
>                       done
>                       [[ $f == debug ]] && continue     # XXX
>                       set -A check_flavors -- "${check_flavors[@]}" $f
>               done
> 
>               check_distfiles "$dir" "$dist_subdir" $distfiles
>               check_master_sites "$dir" $master_sites
>               $existing_port || check_shlibs "$dir" $shared_libs
>               for _s in $multi_packages; do
>                       sub_checks "$dir" "$_s" \
>                           "$fullpkgname" "${check_flavors[@]}"
>               done
> 
>               ! $error
>       } || error=true
> 
>       if [ -z $pkgpath ] && ! $rootrun; then
>               pkgpath=$(cd -- "$dir"; make "${make_args[@]}" show=PKGPATH 
> 2>/dev/null) ||
>                       pkgpath=
>       fi
> }
> 
> # Checks made:
> #   * Every library in SHARED_LIBS has 0.0 version.
> check_shlibs() {
>       $debugging && echo "CALLED: check_shlibs($*)" >&2
> 
>       local dir=$1; shift
>       local lib
>       local libver
>       local portref=$(portref "$dir")
> 
>       while (($# > 1)); do
>               lib=$1
>               libver=$2
>               if [[ $libver != 0.0 ]]; then
>                       err "${portref}the $lib shared library has" \
>                           "version $libver instead of 0.0"
>               fi
>               shift 2
>       done
> }
> 
> # Checks made:
> #   * Distfiles with useless names go into DIST_SUBDIR or have {url} suffix.
> check_distfiles() {
>       $debugging && echo "CALLED: check_distfiles($*)" >&2
> 
>       local dir=$1; shift
>       local dist_subdir=$1; shift
>       local portref=$(portref "$dir")
> 
>       # do not care about absent distfiles, this is fine for meta ports
>       while (($# > 1)); do
>               # try to catch "version-only" names, but not anything more
>               if [[ $1 == ?(v)?(.)+([0-9])?(.+([0-9]))*(.+([a-z])) &&
>                     -z $dist_subdir && $1 != *\{*\} ]]; then
>                       err "${portref}badly named distfile $1 without" \
>                           "DIST_SUBDIR or {url} postfix"
>               fi
>               shift
>       done
> }
> 
> # Checks made:
> #   * No unreliable (without fixed distfiles) hosting listed in MASTER_SITES.
> check_master_sites() {
>       $debugging && echo "CALLED: check_master_sites($*)" >&2
> 
>       local dir=$1; shift
>       local portref=$(portref "$dir")
>       local name
> 
>       while (($# > 1)); do
>               case "$1" in
>               http?(s)://bitbucket.com/*)     name=BitBucket;;
>               http?(s)://gitorious.com/*)     name=Gitorious;;
>               *)                              name=;;
>               esac
>               [[ -n $name ]] && err "$portref$name does not hold real" \
>                       "releases, please host the distfiles somewhere" \
>                       "somewhere else or ask someone to do this for you"
>               shift
>       done
> }
> 
> # Run checks that are FLAVOR/SUBPACKAGE-dependent.
> sub_checks() {
>       $debugging && echo "CALLED: sub_checks($*)" >&2
> 
>       local dir=$1; shift
>       local subpkg=$1; shift
>       local fullpkgname=$1; shift
>       local flavor
>       for flavor in "$@"; do
>               # avoid extra noise
>               [[ ${flavor#no_} != ${flavor} &&
>                  ${subpkg#-} == ${flavor#no_} ]] &&
>                  continue
> 
>               (
>                       cd -- "$dir"
>                       portref=$(portref "$dir" "$subpkg" "$flavor" "$*")
>                       export SUBPACKAGE="$subpkg" FLAVOR="$flavor"
> 
>                       make "${make_args[@]}" show="MODULES WANTLIB$subpkg" | {
>                               local modules wantlib
>                               read modules
>                               read wantlib
>                               check_wantlib "$portref" "$modules" $wantlib
>                       } || error=true
> 
>                       if $plist_checks; then
>                               make "${make_args[@]}" print-plist-with-depends 
> |
>                                   check_plist "$portref" "$fullpkgname" ||
>                                   error=true
>                       fi
> 
>                       ! $error
>               ) || error=true
>       done
> }
> 
> # Checks made:
> #   * If package installs system-wide icons, it should have the
> #     x11/gtk+2,-guic dependency and @exec/@unexec-delete with
> #     %D/bin/gtk-update-icon-cache -q -t %D/share/icons/$theme
> #     for each icon theme used in package.
> #
> #   * If package adds a MIME type handler, it should have the
> #     devel/desktop-file-utils dependency and @exec/@unexec-delete with
> #     %D/bin/update-desktop-database . Unfortunately, it's hard to tell
> #     if there is a MIME type handler in .desktop file, so we just
> #     trigger if any .desktop files are added to
> #     ${PREFIX}/share/applications/ .
> #
> #   * If package adds a MIME types package, it should have the
> #     misc/shared-mime-info dependency and @exec/@unexec-delete with
> #     %D/bin/update-mime-database %D/share/mime
> #
> #   * If package installs .mo files under ${PREFIX}/share/locale/, then
> #     run-time dependency on devel/gettext should exists.
> check_plist() {
>       $debugging && echo "CALLED: check_plist($*)" >&2
> 
>       local portref=$1; shift
>       local fullpkgname=$1; shift
> 
>       local guic_dep=false
>       local guic_dep_needed=false
>       local guic_exec_cnt=0
>       local guic_unexec_cnt=0
> 
>       local mime_dep=false
>       local mime_dep_needed=false
>       local mime_exec_cnt=0
>       local mime_unexec_cnt=0
> 
>       local mimepkg_dep=false
>       local mimepkg_dep_needed=false
>       local mimepkg_exec_cnt=0
>       local mimepkg_unexec_cnt=0
> 
>       local icon_themes exec_themes unexec_themes
> 
>       local gettext_dep=false
>       local translation_found=false
> 
>       local app l theme varname
> 
>       while read l; do
>               case "$l" in
>               share/icons/*/@(+([0-9])x+([0-9])|scalable)/*)
>                       # We match directories by purpose, this helps to catch
>                       # update-plist fuckups, when directories go into one
>                       # package and actual icons go in another.
>                       guic_dep_needed=true
>                       theme=${l#share/icons/}
>                       theme=${theme%%/*}
>                       # wrap with the '/' characters to avoid erroneous 
> matching
>                       echo "$icon_themes" | fgrep -q "/$theme/" ||
>                               icon_themes="$icon_themes /$theme/"
>                       ;;
>               share/icons/*+(/*)?)
>                       app=${l#share/icons/}
>                       app=${app%%/*}
>                       err "${portref}installs icon ${l##*/} in ${l%/*}, it" \
>                           "should go in share/$app/icons/ or like instead"
>                       ;;
>               "@depend x11/gtk+2,-guic"*)
>                       guic_dep=true
>                       ;;
>               "@exec %D/bin/gtk-update-icon-cache -q -t %D/share/icons/"*)
>                       theme=${l##*/}
>                       varname=$(echo "$theme" | sed -e 's/[^a-zA-Z_]/_/g')
>                       ((guic_exec_cnt++)) || true
>                       eval "((guic_exec_cnt_$varname++)) || true"
>                       echo "$exec_icon_themes" | fgrep -q "/$theme/" ||
>                               exec_icon_themes="$exec_icon_themes /$theme/"
>                       ;;
>               "@unexec-delete %D/bin/gtk-update-icon-cache -q -t 
> %D/share/icons/"*)
>                       theme=${l##*/}
>                       varname=$(echo "$theme" | sed -e 's/[^a-zA-Z_]/_/g')
>                       ((guic_unexec_cnt++)) || true
>                       eval "((guic_unexec_cnt_$varname++)) || true"
>                       echo "$unexec_icon_themes" | fgrep -q "/$theme/" ||
>                               unexec_icon_themes="$unexec_icon_themes 
> /$theme/"
>                       ;;
>               "@unexec-delete rm -f "%D/share/icons/*/icon-theme.cache)
>                       # as an alternative, port could zap the theme entirely
>                       theme=${l#*/icons/}
>                       theme=${theme%/icon-theme.cache}
>                       varname=$(echo "$theme" | sed -e 's/[^a-zA-Z_]/_/g')
>                       ((guic_unexec_cnt++)) || true
>                       eval "((guic_unexec_cnt_$varname++)) || true"
>                       echo "$unexec_icon_themes" | fgrep -q "/$theme/" ||
>                               unexec_icon_themes="$unexec_icon_themes 
> /$theme/"
>                       ;;
>               @?(un)exec?(-delete|-update)" %D/bin/gtk-update-icon-cache"*)
>                       err "${portref}incorrect gtk-update-icon-cache" \
>                           "invocation: ${l#@* }"
>                       ;;
> 
>               share/applications/*(*/)*.desktop)
>                       mime_dep_needed=true
>                       ;;
>               "@depend devel/desktop-file-utils"*)
>                       mime_dep=true
>                       ;;
>               "@exec %D/bin/update-desktop-database")
>                       ((mime_exec_cnt++)) || true
>                       ;;
>               "@unexec-delete %D/bin/update-desktop-database")
>                       ((mime_unexec_cnt++)) || true
>                       ;;
>               @?(un)exec?(-delete|-update)" %D/bin/update-desktop-database"*)
>                       err "${portref}incorrect update-desktop-database" \
>                           "invocation: ${l#@* }"
>                       ;;
> 
>               share/mime/packages/*.xml)
>                       mimepkg_dep_needed=true
>                       ;;
>               "@depend misc/shared-mime-info"*)
>                       mimepkg_dep=true
>                       ;;
>               "@exec %D/bin/update-mime-database %D/share/mime")
>                       ((mimepkg_exec_cnt++)) || true
>                       ;;
>               "@unexec-delete %D/bin/update-mime-database %D/share/mime")
>                       ((mimepkg_unexec_cnt++)) || true
>                       ;;
>               @?(un)exec?(-delete|-update)" %D/bin/update-mime-database"*)
>                       err "${portref}incorrect update-mime-database" \
>                           "invocation: ${l#@* }"
>                       ;;
> 
>               "@depend devel/gettext"*)
>                       gettext_dep=true
>                       ;;
>               share/locale/*/*/*.mo)
>                       translation_found=true
>                       ;;
>               esac
>       done
> 
>       # gtk-update-icon-cache
>       $guic_dep_needed && ! $guic_dep &&
>           [[ $fullpkgname != gtk-update-icon-cache-* ]] &&
>               err "${portref}missing RDEP on x11/gtk+2,-guic"
>       local cnt
>       for theme in $icon_themes; do
>               theme=${theme#/}
>               theme=${theme%/}
> 
>               varname=$(echo "$theme" | sed -e 's/[^a-zA-Z_]/_/g')
> 
>               ((guic_exec_cnt--)) || true
>               ((guic_unexec_cnt--)) || true
>               eval "((guic_exec_cnt_$varname--)) || true"
>               eval "((guic_unexec_cnt_$varname--)) || true"
> 
>               eval "cnt=\$guic_exec_cnt_$varname"
>               if (($cnt > 0)); then
>                       err "${portref}extra @exec of gtk-update-icon-cache" \
>                           "for icon theme $theme"
>                       ((guic_exec_cnt--)) || true
>               elif (($cnt < 0)); then 
>                       err "${portref}missing @exec of gtk-update-icon-cache" \
>                           "for icon theme $theme"
>               fi
> 
>               eval "cnt=\$guic_unexec_cnt_$varname"
>               if (($cnt > 0)); then
>                       err "${portref}extra @unexec-delete of 
> gtk-update-icon-cache" \
>                           "for icon theme $theme"
>                       ((guic_unexec_cnt--)) || true
>               elif (($cnt < 0)); then 
>                       err "${portref}missing @unexec-delete of 
> gtk-update-icon-cache" \
>                           "for icon theme $theme"
>               fi
>       done
> 
>       for theme in $exec_icon_themes; do
>               theme=${theme#/}
>               theme=${theme%/}
>               echo "$icon_themes" | fgrep -q "/$theme/" ||
>                       err "doing @exec of gtk-update-icon-cache" \
>                           "for absent icon theme $theme"
>       done
> 
>       for theme in $unexec_icon_themes; do
>               theme=${theme#/}
>               theme=${theme%/}
>               echo "$icon_themes" | fgrep -q "/$theme/" ||
>                       err "doing @unexec-delete of gtk-update-icon-cache" \
>                           "for absent icon theme $theme"
>       done
> 
>       ((guic_exec_cnt > 0)) &&
>               err "${portref}extra @exec of gtk-update-icon-cache"
>       ((guic_unexec_cnt > 0)) &&
>               err "${portref}extra @unexec-delete of gtk-update-icon-cache"
> 
>       # desktop-file-utils (simplier than previous, isn't it?)
>       $mime_dep_needed && ! $mime_dep &&
>           [[ $fullpkgname != desktop-file-utils-* ]] &&
>               err "${portref}missing RDEP on devel/desktop-file-utils"
>       if $mime_dep_needed; then
>               ((mime_exec_cnt--)) || true
>               ((mime_unexec_cnt--)) || true
>       fi
>       if ((mime_exec_cnt > 0)) &&
>           [[ $fullpkgname != desktop-file-utils-* ]]; then
>               err "${portref}extra @exec of update-desktop-database"
>       elif ((mime_exec_cnt < 0)); then
>               err "${portref}missing @exec of update-desktop-database"
>       fi
>       if ((mime_unexec_cnt > 0)); then
>               err "${portref}extra @unexec-delete of update-desktop-database"
>       elif ((mime_unexec_cnt < 0)); then
>               err "${portref}missing @unexec-delete of 
> update-desktop-database"
>       fi
> 
>       # update-mime-database (same as previous)
>       $mimepkg_dep_needed && ! $mimepkg_dep &&
>           [[ $fullpkgname != shared-mime-info-* ]] &&
>               err "${portref}missing RDEP on misc/shared-mime-info"
>       if $mimepkg_dep_needed; then
>               ((mimepkg_exec_cnt--)) || true
>               ((mimepkg_unexec_cnt--)) || true
>       fi
>       if ((mimepkg_exec_cnt > 0)) &&
>           [[ $fullpkgname != shared-mime-info-* ]]; then
>               err "${portref}extra @exec of update-mime-database"
>       elif ((mimepkg_exec_cnt < 0)); then
>               err "${portref}missing @exec of update-mime-database"
>       fi
>       if ((mimepkg_unexec_cnt > 0)); then
>               err "${portref}extra @unexec-delete of update-mime-database"
>       elif ((mimepkg_unexec_cnt < 0)); then
>               err "${portref}missing @unexec-delete of update-mime-database"
>       fi
> 
>       # gettext
>       $translation_found && ! $gettext_dep &&
>               err "${portref}translation file(-s) found without" \
>                   "devel/gettext dependency"
> 
>       ! $error
> }
> 
> # Checks made:
> #   * devel/gettext and converters/libiconv MODULES are not forgotten.
> check_wantlib() {
>       local portref="$1"; shift
>       local modules="$1"; shift
> 
>       local iconv_wantlib=false
>       local intl_wantlib=false
>       local gettext_module=false
>       local iconv_module=false
>       local v
> 
>       for v in $modules; do case $v in
>               devel/gettext)          gettext_module=true;;
>               converters/libiconv)    iconv_module=true;;
>       esac; done
> 
>       for v; do case $v in
>               iconv?(?(">")=+([0-9])))        iconv_wantlib=true;;
>               intl?(?(">")=+([0-9])))         intl_wantlib=true;;
>       esac; done
> 
>       if $intl_wantlib && ! $gettext_module; then
>               err "${portref}missing devel/gettext in MODULES"
>       elif $iconv_wantlib && ! $gettext_module && ! $iconv_module; then
>               err "${portref}missing converters/libiconv in MODULES"
>       fi
> 
>       ! $error
> }
> 
> # Checks made:
> #   * Directory is not empty
> #   * No '*.core' files present
> check_files_dir() {
>       $debugging && echo "CALLED: check_files_dir($*)" >&2
> 
>       find -f "$1" -- -type f | {
>               local empty=true
>               while read F; do
>                       ignoring "$F" && continue
>                       empty=false
>                       [[ "$F" == *.core ]] && err_coredump_found "$F"
>               done
>               $empty && "there are no files, please remove the $1 directory"
>               ! $error
>       } || error=true
> }
> 
> # Checks made:
> #   * Each patch contains $OpenBSD$ RCS tag.
> #   * Directory is not empty and consists only of plain files starting
> #     with 'patch-' and not ending with '.orig'.
> check_patches_dir() {
>       $debugging && echo "CALLED: check_patches_dir($*)" >&2
> 
>       local empty=true
>       local F
> 
>       for F in "$1"/* "$1"/.*; do case "${F##*/}" in
>       patch-*.orig)
>               handle_extra_file "$F"
>               ;;
> 
>       patch-*)
>               empty=false
>               test -f "$F" ||
>                       err "$F is not a file"
>               $rootrun || head -n 1 -- "$F" | egrep -q '^\$OpenBSD.*\$$' ||
>                       err "$F does not have \$OpenBSD\$ RCS tag at the top"
>               ;;
> 
>       *)
>               handle_extra_file "$F"
>               ;;
>       esac; done
> 
>       $empty && err "there are no patches, please remove the $1 directory 
> instead"
> }
> 
> # Checks made:
> #   * Directory is not empty and consist only of plain files with fixed names.
> #   * PFRAG, PLIST, README, SECURITY and .rc files contain appropriate
> #     $OpenBSD$ RCS tags; other files should NOT contain $OpenBSD$ RCS tag.
> #   * PFRAG.shared should be merged in PLIST if it contains @lib items only.
> #   * No trailing whitespace for DESCR, MESSAGE, README, SECURITY, UNMESSAGE
> #     and .rc files (PLIST and PFRAG are better checked with "make package").
> check_pkg_dir() {
>       $debugging && echo "CALLED: check_pkg_dir($*)" >&2
> 
>       local empty=true
>       local F
> 
>       for F in "$1"/* "$1"/.*; do case "${F##*/}" in
>       DESCR?(-*))
>               empty=false
>               [[ -f $F ]] ||
>                       err "$F is not a file"
>               check_trailing_whitespace "$F"
>               fgrep -q '$OpenBSD$' "$F" &&
>                       err "$F should not contain \$OpenBSD\$ tag"
>               ;;
> 
>       PFRAG.shared?(-*))
>               empty=false
>               [[ -f $F ]] ||
>                       err "$F is not a file"
>               head -n 1 -- "$F" |
>                       egrep -q '^@comment \$OpenBSD[[:space:]]*(:.*)?\$$' ||
>                       err "$F does not have \$OpenBSD\$ RCS tag at the top"
> 
>               awk <"$F" '/^(@comment )?@lib /' | {
>                       local no_a_for_so=false plist=${F##*/} 
> shlibs_found=false
>                       plist=PLIST${plist##PFRAG.+([!-])}
>                       while read l; do
>                               shlibs_found=true
>                               l=${l##"@comment "}
>                               l=${l##"@lib "}
>                               l=${l%%.so.*}.a
>                               fgrep -q -- "$l" "${F%/*}/$plist" || 
> no_a_for_so=true
>                       done
>                       $shlibs_found && ! $no_a_for_so &&
>                               err "$F should be merged in $plist"
>               }
>               ;;
> 
>       PFRAG.*|PLIST?(-*))
>               empty=false
>               [[ -f $F ]] ||
>                       err "$F is not a file"
>               head -n 1 -- "$F" |
>                       egrep -q '^@comment \$OpenBSD[[:space:]]*(:.*)?\$$' ||
>                       err "$F does not have \$OpenBSD\$ RCS tag at the top"
>               ;;
> 
>       README?(-*)|SECURITY?(-*))
>               [[ -f $F ]] ||
>                       err "$F is not a file"
>               check_trailing_whitespace "$F"
>               head -n 1 -- "$F" |
>                       egrep -q 
> '^(#[[:space:]]*)?\$OpenBSD[[:space:]]*(:.*)?\$$' ||
>                       err "$F does not have \$OpenBSD\$ RCS tag at the top"
>               ;;
> 
>       *.rc)
>               [[ -f $F ]] ||
>                       err "$F is not a file"
>               check_trailing_whitespace "$F"
>               head -n 5 -- "$F" |
>                       egrep -q '^#[[:space:]]*\$OpenBSD[[:space:]]*(:.*)?\$$' 
> ||
>                       err "$F does not have \$OpenBSD\$ RCS tag at the top"
>               ;;
> 
>       MESSAGE?(-*)|UNMESSAGE?(-*))
>               [[ -f $F ]] ||
>                       err "$F is not a file"
>               check_trailing_whitespace "$F"
>               fgrep -q '$OpenBSD$' "$F" &&
>                       err "$F should not contain \$OpenBSD\$ tag"
>               ;;
> 
>       *)
>               handle_extra_file "$F"
>               ;;
>       esac; done
> 
>       $empty && err "$1 directory does not contain either DESCR, PFRAG or 
> PLIST files"
> }
> 
> # Checks made:
> #   * Contains $OpenBSD$ tag at the top line.
> #   * No REVISION marks present in given file (unless in update mode).
> #   * No trailing whitespace.
> check_makefile() {
>       $debugging && echo "CALLED: check_makefile($*)" >&2
> 
>       check_trailing_whitespace "$1"
>       head -n 1 -- "$1" |
>               egrep -q '^#[[:space:]]*\$OpenBSD[[:space:]]*(:.*)?\$' ||
>               err "$F does not have \$OpenBSD\$ RCS tag at the top"
> 
>       $existing_port && return 0
>       grep -q '^ *REVISION' "$1" 2>/dev/null &&
>               err "REVISION(-s) found in $1"
> }
> 
> # Checks made:
> #   * None of executable bits (111) are set on plain files.
> check_perms_in_dir() {
>       $debugging && echo "CALLED: check_perms_in_dir($*)" >&2
> 
>       find -f "$1" -- -maxdepth 1 -type f \
>           \( -perm -100 -or -perm -010 -or -perm 001 \) | {
>               while read F; do
>                       F=${F#./}
>                       ignoring "$F" && continue
>                       err "executable file: ${F#./}"
>               done
>               ! $error
>       } || error=true
> }
> 
> 
> ############################################################
> # Run checks. Also calculate and show pkgpath variable,
> # unless we're checking the ports tree root dir.
> #
> 
> for D; do
>       if [[ $D == /* ]]; then
>               err "absolute path $D ignored"
>               continue
>       fi
>       if [[ $D == *(*/)..*(/*) ]]; then
>               err "too many .. in $D, skipping"
>               continue
>       fi
>       check_port_dir "$D"
> done
> 
> if ! $rootrun; then
>       [[ -z $pkgpath ]] && pkgpath=${PWD##"$portsdir/"}
> 
>       if [[ $pkgpath == "$PWD" ]]; then
>               cat >&2 <<EOE
> ${0##*/}: could not determine PKGPATH. Please help me with the -p option.
> EOE
>               exit 2
>       fi
> 
>       echo "$pkgpath"
> fi
> 
> ! $error
> 
> <<<<< CUT HERE >>>>>
> 
> .\"     $OpenBSD$
> .\"
> .\" Copyright (c) 2013 Vadim Zhukov
> .\"
> .\" Permission to use, copy, modify, and distribute this software for any
> .\" purpose with or without fee is hereby granted, provided that the above
> .\" copyright notice and this permission notice appear in all copies.
> .\"
> .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> .\"
> .Dd $Mdocdate$
> .Dt PORTCHECK 1
> .Os
> .Sh NAME
> .Nm portcheck
> .Nd validate a port before submitting
> .Sh SYNOPSIS
> .Nm
> .Op Fl CdPU
> .Op Fl p Ar portsdir
> .Op Fl x Ar pattern
> .Pp
> .Nm
> .Op Fl AdP
> .Op Fl p Ar portsdir
> .Op Fl x Ar pattern
> .Op Ar subdir ...
> .Sh DESCRIPTION
> .Nm
> is used to validate the
> .Ox
> port or port hierarchy in current directory.
> It should be used before submitting ports for review to avoid making
> common mistakes.
> .Nm
> verifies that directory and file structure for a port is in place and
> that no bogus files exist.
> .Pp
> When it's done,
> .Nm
> will print detected value of port's
> .Ev PKGPATH
> to standard output, unless it fails in detection.
> In the latter case, the
> .Fl p
> option should be provided.
> All other (error) messages from
> .Nm
> end up on standard error output.
> .Pp
> By default,
> .Nm
> automatically picks up nearest parent directory named
> .Dq ports ,
> with an optional
> .Dq mystuff
> or
> .Dq openbsd-wip
> subdirectory component, as the ports root directory.
> For example: if the port being imported is located in
> .Pa /home/joe/cvs/ports/openbsd-wip/devel/p5-Foo ,
> then the root ports directory will be detected as being
> .Pa /home/joe/cvs/ports/openbsd-wip .
> To override this behaviour, see the
> .Fl p
> option.
> .Pp
> The following options are available:
> .Bl -tag -width Ds
> .It Fl A
> Intended for running
> .Nm
> on the whole ports tree, i.e., the one lying in
> .Ev PORTSDIR .
> This option adds several ignore patterns (see
> .Fl x
> option description), implies
> .Fl C
> and
> .Fl U
> options and disables some other checks (e.g., for missing distinfo).
> .Ev PKGPATH
> determining and printing won't be done.
> Implicit change of working directory to the ports tree root is done
> before starting any checks.
> Also, in this mode one or more
> .Ar subdir
> arguments could be specified, to narrow the check only for given
> subdirectories of ports tree root.
> .It Fl C
> Disables checks for the presence of CVS directories,
> for checking ports already committed to CVS tree.
> .It Fl d
> Show debugging information such as calling of check routines.
> .It Fl P
> Disable expensive checks that use 
> .Dq print-plist-with-depends
> target, e.g., proper usage of
> .Xr gtk-update-icon-cache 1 ,
> .Xr update-desktop-database 1
> and
> .Xr update-mime-database 1 .
> .It Fl p Ar portsdir
> Forces the given directory to be treated as ports root directory.
> Cancels autodetection of the root ports directory made by default.
> This option is useful, e.g., when you have a temporary ports tree in
> a non-standard location.
> .It Fl U
> Intended to be used when working on port updates.
> Disables the checks like the presence of REVISION markers and non-0.0
> .Ev SHARED_LIBS .
> .It Fl x
> Excludes files and subdirectories matching given shell globbing pattern
> from any checks.
> Note that matching is done against relative path, and not against
> absoulte path or base name either.
> I.e., to exclude the
> .Dq x11/kde4/libs/logs
> from checks, you must pass the whole line as argument, not just
> .Dq logs .
> Multiple -x options may be specified.
> .El
> .Sh EXAMPLES
> To validate a new port you've just prepared, go to port's directory and
> run:
> .Bd -literal -offset indent
> $ portcheck
> .Ed
> .Pp
> If you were working on updating of an existing port directly in CVS
> tree, you can avoid extra noise by using the
> .Fl C
> and
> .Fl U
> options:
> .Bd -literal -offset indent
> $ portcheck -CU
> .Ed
> .Pp
> To run a global check of the whole
> .Dq devel
> category in ports tree, use the
> .Fl A
> option instead:
> .Bd -literal -offset indent
> $ portcheck -Ap /usr/ports devel
> .Ed
> .Sh SEE ALSO
> .Xr portimport 1
> .Sh HISTORY
> This utility was split from
> .Xr portimport 1
> in 2013 and first appeared in
> .Ox 5.5 .
> 

-- 
Antoine

Reply via email to