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