#!/bin/ksh # # $OpenBSD: portcheck,v 1.15 2013/08/22 13:20:17 zhuk Exp $ # 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 < 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 < 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" } has_subdirs_only() { $debugging && echo "CALLED: has_subdirs_only($*)" >&2 local dir=$1; shift ls -A "$dir" | { local has_files=false has_dirs=false while read F; do $ignore_cvs && [[ $F == CVS ]] && continue if [[ -d $dir/$F ]]; then has_dirs=true else has_files=true fi done $has_dirs && ! $has_files } } 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: " } # Contains last SUBST_CMD. Filled by check_port_dir(), used # by check_port_hier() to lazily call the check_pkg_dir(). last_subst_cmd= # Checks made: # * Whitelist filter of what could be in this directory. check_port_hier() { $debugging && echo "CALLED: check_port_hier($*)" >&2 local distinfo_lives_upper pkg_lives_upper plist_lives_upper local dir=$1; shift for opt; do # looks unsafe but we do not pass anything except # "foo=true" and "foo=false" here eval "$opt" done distinfo_lives_upper=${distinfo_lives_upper:-false} pkg_lives_upper=${pkg_lives_upper:-false} 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 tell_pkg_exists=$pkg_lives_upper if [[ -d $dir/pkg ]]; then pkg_exists=true tell_pkg_exists=true fi 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 $plist_lives_upper && plist_exists=true local recursive_args set -A recursive_args -- \ distinfo_lives_upper=$distinfo_exists \ pkg_lives_upper=$tell_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) check_${F##*/}_dir "$F" ;; pkg) # Do nothing, pkg_exists is already set, # and we need to read SUBST_CMD first. ;; patches?(-*)) check_patches_dir "$F" ;; *) if ! $rootrun && [[ ${F##*/} == core ]]; then err_core_found "$F" fi if ! [[ -f $F/Makefile ]] && ! has_subdirs_only "$F"; 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 $pkg_exists && check_pkg_dir "$F" "$last_subst_cmd" 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 local distinfo_lives_upper pkg_lives_upper plist_lives_upper for opt; do # looks unsafe but we do not pass anything except # "foo=true" and "foo=false" here eval "$opt" done distinfo_lives_upper=${distinfo_lives_upper:-false} pkg_lives_upper=${pkg_lives_upper:-false} plist_lives_upper=${plist_lives_upper:-false} check_perms_in_dir "$dir" if [[ -f $dir/Makefile.inc ]] || egrep -sq '^ *SUBDIR[[:space:]]*\+?=' "$dir"/Makefile || has_subdirs_only "$dir"; 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 pkg_exists=true # Actual check to be done later, we need to gather # additional info through "make show=" call. 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_exists || $pkg_lives_upper || 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 local multi_packages this_pkg_path pseudo_flavors shared_libs subst_cmd local show_items="DIST_SUBDIR DISTFILES FLAVOR FLAVORS FULLPKGNAME" local show_items="$show_items MASTER_SITES MULTI_PACKAGES PKGPATH" local show_items="$show_items PSEUDO_FLAVORS SHARED_LIBS SUBST_CMD" local read_failed=false (cd -- "$dir"; make "${make_args[@]}" show="$show_items" || true) &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 -r modules read -r wantlib check_wantlib "$portref" "$modules" $wantlib } || error=true if $plist_checks; then (make "${make_args[@]}" print-plist-with-depends || true) &2 local portref=$1; shift local fullpkgname=$1; shift local flavor_list=$1; shift local flavor is_static=false for flavor in $flavor_list; do [[ $flavor == static ]] && is_static=true done 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 -pr l; do case "$l" in share/icons/*/*/*|share/icons/*/@(index.theme|iconrc?(-png))) # Themes have at least two levels in depth. # # 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/*(*/)) # Do not match intermediate directories to avoid false # positives. ;; 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 "${portref}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 "${portref}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 && ! $is_static && 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 qt3_module=false local qt4_module=false local kde3_module=false local kde4_module=false local v for v in $modules; do case $v in devel/gettext) gettext_module=true;; converters/libiconv) iconv_module=true;; x11/qt3) qt3_module=true;; x11/qt4) qt4_module=true;; x11/kde) kde3_module=true;; x11/kde4) kde4_module=true;; esac; done for v; do case $v in iconv?(?(">")=+([0-9]))) iconv_wantlib=true ;; intl?(?(">")=+([0-9]))) intl_wantlib=true ;; Qt+([A-Za-z0-9])?(?('>')=+([0-9]))) err "$portref$v instead of lib/qt4/$v" \ "in WANTLIB" ;; qt-mt?(?('>')=+([0-9]))) err "$portref$v instead of lib/qt3/$v" \ "in WANTLIB" ;; DCOP?(?('>')=+([0-9]))) err "$portref$v instead of \${KDE}/$v" \ "in WANTLIB (check other libs, too!)" ;; kdecore?(?('>')=+([0-9]))) if $kde4_module; then err "$portref$v instead of \${KDE4LIB}/$v" \ "in WANTLIB (check other libs, too!)" elif $kde3_module; then err "$portref$v instead of \${KDE}/$v" \ "in WANTLIB (check other libs, too!)" else err "$portref$v WANTLIB without x11/kde*" \ "in MODULES (check other libs, too!)" fi ;; 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"). # * See also check_plist_file(). check_pkg_dir() { $debugging && echo "CALLED: check_pkg_dir($*)" >&2 local dir=$1; shift local subst_cmd if (($# > 0)); then # XXX should find the way to always obtain SUBST_CMD subst_cmd=$1 shift fi local empty=true local F for F in "$dir"/* "$dir"/.*; do case "${F##*/}" in DESCR?(-*)) empty=false [[ -f $F ]] || err "$F is not a file" check_trailing_whitespace "$F" [[ -n $subst_cmd ]] && check_subst_vars "$F" "$subst_cmd" egrep -q '\$OpenBSD.*\$' "$F" && err "$F should not contain \$OpenBSD\$ tag" ;; PFRAG.shared?(-*)) empty=false [[ -n $subst_cmd ]] && check_subst_vars "$F" "$subst_cmd" check_plist_file "$F" 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" ! $error } || error=true ;; PFRAG.*|PLIST?(-*)) empty=false [[ -n $subst_cmd ]] && check_subst_vars "$F" "$subst_cmd" check_plist_file "$F" ;; README?(-*)|SECURITY?(-*)) [[ -f $F ]] || err "$F is not a file" [[ -n $subst_cmd ]] && check_subst_vars "$F" "$subst_cmd" check_trailing_whitespace "$F" head -n 1 -- "$F" | egrep -q '^(#[[:space:]]*)?\$OpenBSD(:.*)?\$$' || 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(:.*)?\$$' || err "$F does not have \$OpenBSD\$ RCS tag at the top" ;; MESSAGE?(-*)|UNMESSAGE?(-*)) [[ -f $F ]] || err "$F is not a file" [[ -n $subst_cmd ]] && check_subst_vars "$F" "$subst_cmd" check_trailing_whitespace "$F" egrep -q '\$OpenBSD.*\$' "$F" && err "$F should not contain \$OpenBSD\$ tag" ;; *) handle_extra_file "$F" ;; esac; done $empty && err "$dir directory does not contain either DESCR, PFRAG or PLIST files" } # Checks made: # * There is an OpenBSD RCS tag at the top. # * No items with ${FULLPKGNAME} are allowed, except readme. check_plist_file() { $debugging && echo "CALLED: check_plist_file($*)" >&2 [[ -f $1 ]] || err "$1 is not a file" head -n 1 -- "$1" | egrep -q '^@comment \$OpenBSD.*\$$' || err "$1 does not have \$OpenBSD\$ RCS tag at the top" # Do not match just '${FULLPKGNAME}' because many ports use the # following trick: # @cwd ${LOCALBASE}/share/doc/pkg-readmes # ${FULLPKGNAME} egrep -v '^(share/doc/pkg-readmes/\$\{FULLPKGNAME\}|@comment .*)$' "$1" | egrep '.\$\{FULLPKGNAME\}|\$\{FULLPKGNAME\}.' >&2 && err "$1 contains item(-s) with \${FULLPKGNAME} in it, see above" } # Checks made: # * Every variable referenced by ${[A-Z]+} should be in ${SUBST_VARS}. check_subst_vars() { $debugging && echo "CALLED: check_subst_vars($*)" >&2 local F=$1; shift local subst_cmd=$1; shift eval "$subst_cmd" <"$F" | egrep '\$\{[A-Z]+\}' >&2 && err "looks like misspelled variables in $F, see above" } # Checks made: # * Contains OpenBSD RCS tag at the top line. # * No REVISION marks present in given file (unless in update mode). # * BUILD_DEPENDS and MODULES are not defined in VAR-subpkg manner. # * No trailing whitespace. check_makefile() { $debugging && echo "CALLED: check_makefile($*)" >&2 check_trailing_whitespace "$1" head -n 1 -- "$1" | egrep -q '^#[[:space:]]*\$OpenBSD.*\$' || err "$F does not have \$OpenBSD\$ RCS tag at the top" local l lnum=0 while read -r l; do ((++lnum)); case $l in *(" ")REVISION*) $existing_port || err "REVISION mark found at $1:$lnum" ;; *(" ")@(BUILD_DEPENDS|MODULES)-*) err "${l%%-*} is not a subpackageble variable, see $1:$lnum" ;; esac; done <"$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 \) \ &2 <