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