Index: head/Mk/Scripts/actual-package-depends.sh =================================================================== --- head/Mk/Scripts/actual-package-depends.sh (revision 415572) +++ head/Mk/Scripts/actual-package-depends.sh (revision 415573) @@ -1,72 +1,74 @@ #!/bin/sh # MAINTAINER: portmgr@FeeeBSD.org # $FreeBSD$ +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_ACTUAL_PACKAGE_DEPENDS}" ] && set -x + if [ -z "${PKG_BIN}" ]; then echo "PKG_BIN required in environment." >&2 exit 1 fi resolv_symlink() { local file tgt file=${1} if [ ! -L ${file} ] ; then echo ${file} return fi tgt=`readlink ${file}` case $tgt in /*) echo $tgt return ;; esac file=${file%/*}/${tgt} absolute_path ${file} } absolute_path() { local file myifs target file=$1 myifs=${IFS} IFS='/' set -- ${file} IFS=${myifs} for el; do case $el in .) continue ;; '') continue ;; ..) target=${target%/*} ;; *) target="${target}/${el}" ;; esac done echo ${target} } find_dep() { pattern=$1 case ${pattern} in *\>*|*\<*|*=*) ${PKG_BIN} info -Eg "${pattern}" 2>/dev/null || echo "actual-package-depends: dependency on ${pattern} not registered" >&2 return ;; /*) searchfile=$pattern ;; *) searchfile=$(/usr/bin/which ${pattern} 2>/dev/null) ;; esac if [ -n "${searchfile}" ]; then ${PKG_BIN} which -q ${searchfile} || ${PKG_BIN} which -q "$(resolv_symlink ${searchfile} 2>/dev/null)" || echo "actual-package-depends: dependency on ${searchfile} not registered (normal if it belongs to base)" >&2 fi } for lookup; do ${PKG_BIN} query "\"%n\": {origin: \"%o\", version: \"%v\"}" "$(find_dep ${lookup})" || : done Index: head/Mk/Scripts/check-stagedir.sh =================================================================== --- head/Mk/Scripts/check-stagedir.sh (revision 415572) +++ head/Mk/Scripts/check-stagedir.sh (revision 415573) @@ -1,283 +1,285 @@ #!/bin/sh # ports/Mk/Scripts/check-stagedir.sh - called from ports/Mk/bsd.stage.mk # $FreeBSD$ # # MAINTAINER: portmgr@FreeBSD.org # # This script serves 2 purposes: # 1. Generate a plist # 2. Test a plist for issues: # a. Files in STAGEDIR that are missing from plist # b. Files in plist missing from STAGEDIR # c. Files in plist which are owned by dependencies/MTREEs set -e export LC_ALL=C . ${SCRIPTSDIR}/functions.sh # lists an mtree file's contents, prefixed to dir. listmtree() { # mtreefile prefix { echo '#mtree' sed 's/nochange$//;' $1 } | tar -tf- | sed "s,^,$2/,;s,^$2/\.$,$2,;s,^$,/," } ### PRODUCE MTREE FILE parse_mtree() { { listmtree /etc/mtree/BSD.root.dist "" listmtree /etc/mtree/BSD.usr.dist /usr listmtree /etc/mtree/BSD.var.dist /var # Use MTREE_FILE if specified and it doesn't already # match LOCALBASE if [ -n "${MTREE_FILE}" ]; then if [ "${PREFIX}" != "${LOCALBASE}" -o "${MTREE_FILE}" \ != "${PORTSDIR}/Templates/BSD.local.dist" ]; then listmtree "${MTREE_FILE}" "${PREFIX}" fi fi listmtree "${PORTSDIR}/Templates/BSD.local.dist" "${LOCALBASE}" unset MTREE_FILE # Add LOCALBASE a=${LOCALBASE} while :; do echo ${a} a=${a%/*} [ -z "${a}" ] && break done # Add in PREFIX if this port wants it if [ ${NO_PREFIX_RMDIR} -eq 0 ]; then a=${PREFIX} while :; do echo ${a} a=${a%/*} [ -z "${a}" ] && break done fi } >${WRKDIR}/.mtree } # Sort a directory list by the order of the dfs-sorted file (from find -ds) sort_dfs() { while read dir; do grep "^[0-9]* ${dir}$" ${WRKDIR}/.staged-dirs-dfs-sorted done | sort -n | cut -d ' ' -f2- } # Prepare sed(1) regex for PLIST_SUB_SED/PORTEXAMPLES/OPTIONS/... setup_plist_seds() { ### HANDLE PORTDOCS/PORTEXAMPLES sed_portdocsexamples="/%%DOCSDIR%%/s!^!%%PORTDOCS%%!g; /%%EXAMPLESDIR%%/s!^!%%PORTEXAMPLES%%!g;" if [ ${makeplist} -eq 0 ]; then # echo "=====> Using OPTIONS: ${PORT_OPTIONS}" | /usr/bin/fmt -w 79 | \ # sed -e '2,$s/^/ /' # Handle magical PORT* features for option in DOCS EXAMPLES; do want_option=0 case " ${PORT_OPTIONS} " in *\ ${option}\ *) want_option=1 ;; esac [ ${want_option} -eq 0 ] && \ sed_portdocsexamples="${sed_portdocsexamples} /^%%PORT${option}%%/d;" done unset PORT_OPTIONS fi sed_plist_sub=$(echo "${PLIST_SUB_SED}" | /bin/sh ${SCRIPTSDIR}/plist_sub_sed_sort.sh) unset PLIST_SUB_SED # Used for generate_plist sed_files_gen="s!^${PREFIX}/!!g; ${sed_plist_sub} \ ${sed_portdocsexamples} /^share\/licenses/d; \ \#${LOCALBASE}/lib/debug#d;" sed_dirs_gen="s!^${PREFIX}/!!g; ${sed_plist_sub} s,^,@dir ,; \ ${sed_portdocsexamples} \ /^@dir share\/licenses/d;" # These prevent ignoring DOCS/EXAMPLES dirs with sed_portdocsexamples sed_files="s!^${PREFIX}/!!g; ${sed_plist_sub} /^share\/licenses/d; \ \#${LOCALBASE}/lib/debug#d;" sed_dirs="s!^${PREFIX}/!!g; ${sed_plist_sub} s,^,@dir ,; \ /^@dir share\/licenses/d;" } # Generate plist from staged files generate_plist() { : >${WRKDIR}/.staged-plist ### HANDLE FILES find ${STAGEDIR} -type f -o -type l | sort | \ sed -e "s,${STAGEDIR},," >${WRKDIR}/.staged-files comm -13 ${WRKDIR}/.plist-files ${WRKDIR}/.staged-files | \ sed -e "${sed_files_gen}" \ >>${WRKDIR}/.staged-plist || : ### HANDLE DIRS cat ${WRKDIR}/.plist-dirs-unsorted ${WRKDIR}/.mtree \ | sort -u >${WRKDIR}/.traced-dirs find ${STAGEDIR} -type d | sed -e "s,^${STAGEDIR},,;/^$/d" | sort \ >${WRKDIR}/.staged-dirrms-sorted find -sd ${STAGEDIR}${PREFIX} -type d -empty | sed -e "s,^${STAGEDIR},,;\,^${PREFIX}$,d;/^$/d" \ >${WRKDIR}/.staged-dirs-dfs find -sd ${STAGEDIR} -type d ! -path "${STAGEDIR}${PREFIX}/*" | sed -e "s,^${STAGEDIR},,;\,^${PREFIX}$,d;/^$/d" \ >>${WRKDIR}/.staged-dirs-dfs sort ${WRKDIR}/.staged-dirs-dfs >${WRKDIR}/.staged-dirs-sorted awk '{print FNR, $0}' ${WRKDIR}/.staged-dirs-dfs \ >${WRKDIR}/.staged-dirs-dfs-sorted # Find all staged dirs and then sort them by depth-first (find -ds) comm -13 ${WRKDIR}/.traced-dirs ${WRKDIR}/.staged-dirs-sorted \ | sort_dfs | sed "${sed_dirs_gen}" \ >>${WRKDIR}/.staged-plist || : } # Check for files in STAGEDIR missing from plist check_orphans_from_plist() { local ret=0 echo "===> Checking for items in STAGEDIR missing from pkg-plist" # Handle whitelisting while read path; do case "${path}" in *.bak) ;; *.orig) ;; */.DS_Store) ;; */.cvsignore) ;; */.git/*|'@dir '*/.git) ;; */.gitattributes|*/.gitignore|*/.gitmodules) ;; */.svn/*|'@dir '*/.svn) ;; */.svnignore) ;; */CVS/*|'@dir '*/CVS) ;; */info/dir|info/dir) ;; share/fonts/*/fonts.dir) ;; share/fonts/*/fonts.scale) ;; share/applications/mimeinfo.cache) ;; share/mime/XMLnamespaces) ;; share/mime/aliases) ;; share/mime/generic-icons) ;; share/mime/globs) ;; share/mime/globs2) ;; share/mime/icons) ;; share/mime/magic) ;; share/mime/mime.cache) ;; share/mime/subclasses) ;; share/mime/treemagic) ;; share/mime/types) ;; share/mime/version) ;; '@dir etc/gconf/gconf.xml.defaults');; *) # An orphan was found, return non-zero status ret=1 echo "Error: Orphaned: ${path}" >&2 ;; esac done < ${WRKDIR}/.staged-plist return ${ret} } # Check for items in plist not in STAGEDIR (pkg lstat(2) errors) check_missing_plist_items() { local ret=0 echo "===> Checking for items in pkg-plist which are not in STAGEDIR" : >${WRKDIR}/.invalid-plist-missing comm -23 ${WRKDIR}/.plist-files-no-comments ${WRKDIR}/.staged-files | \ sed -e "${sed_files}" \ >>${WRKDIR}/.invalid-plist-missing || : # Look for directories, then sort them by DFS. Must create the dirs # so find -ds can be used to sort them. rm -rf ${WRKDIR}/.missing-dirs > /dev/null 2>&1 || : mkdir ${WRKDIR}/.missing-dirs comm -23 ${WRKDIR}/.plist-dirs-sorted-no-comments \ ${WRKDIR}/.staged-dirrms-sorted > ${WRKDIR}/.missing-plist-dirs # Creates the dirs in WRKDIR/.missing-dirs and ensure spaces are # quoted. sed -e "s,^,${WRKDIR}/.missing-dirs," \ -e 's,^\(.*\)$,"\1",' \ ${WRKDIR}/.missing-plist-dirs | xargs mkdir -p find -ds ${WRKDIR}/.missing-dirs | \ sed -e "s,^${WRKDIR}/.missing-dirs,," | \ while read dir; do \ grep -x "${dir}" ${WRKDIR}/.missing-plist-dirs || :; done | \ sed "${sed_dirs}" \ >>${WRKDIR}/.invalid-plist-missing || : rm -rf ${WRKDIR}/.missing-dirs if [ -s "${WRKDIR}/.invalid-plist-missing" ]; then ret=1 while read line; do echo "Error: Missing: ${line}" >&2 done < ${WRKDIR}/.invalid-plist-missing fi return ${ret} } # obtain operating mode from command line ret=0 makeplist=0 case "$1" in checkplist) ;; makeplist) makeplist=1 ;; *) echo >&2 "Usage: $0 {checkplist|makeplist}" ; exit 1 ;; esac # validate environment validate_env STAGEDIR PREFIX LOCALBASE WRKDIR WRKSRC MTREE_FILE \ TMPPLIST PLIST_SUB_SED SCRIPTSDIR PORT_OPTIONS NO_PREFIX_RMDIR +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_CHECK_STAGEDIR}" ] && set -x + set -u if [ $makeplist = 0 ] ; then echo "===> Parsing plist" parse_plist "${PREFIX}" 1 < ${TMPPLIST} \ 3>${WRKDIR}/.plist-dirs-unsorted \ >${WRKDIR}/.plist-files-unsorted unset TMPPLIST # Create the -no-comments files and trim out @comment from the plists. # This is used for various tests later. sed -e '/^@comment/d' ${WRKDIR}/.plist-dirs-unsorted \ >${WRKDIR}/.plist-dirs-unsorted-no-comments sed -i '' -e 's/^@comment //' ${WRKDIR}/.plist-dirs-unsorted sed -e '/^@comment/d' ${WRKDIR}/.plist-files-unsorted | sort \ >${WRKDIR}/.plist-files-no-comments sed -e 's/^@comment //' ${WRKDIR}/.plist-files-unsorted | sort \ >${WRKDIR}/.plist-files else # generate plist - pretend the plist had been empty : >${WRKDIR}/.plist-dirs-unsorted : >${WRKDIR}/.plist-files echo '/you/have/to/check/what/makeplist/gives/you' fi parse_mtree setup_plist_seds generate_plist # If just making plist, show results and exit successfully. if [ ${makeplist} -eq 1 ]; then cat ${WRKDIR}/.staged-plist exit 0 fi check_orphans_from_plist || ret=1 # Prepare plist-dirs for directory checks sort -u ${WRKDIR}/.plist-dirs-unsorted-no-comments \ >${WRKDIR}/.plist-dirs-sorted-no-comments check_missing_plist_items || ret=1 if [ ${ret} -ne 0 ]; then echo "===> Error: Plist issues found." >&2 if [ "${PREFIX}" != "${LOCALBASE}" ]; then echo "===> Warning: Test was done with PREFIX != LOCALBASE" echo "===> Warning: The port may not be properly installing into PREFIX" fi fi exit ${ret} Index: head/Mk/Scripts/check_leftovers.sh =================================================================== --- head/Mk/Scripts/check_leftovers.sh (revision 415572) +++ head/Mk/Scripts/check_leftovers.sh (revision 415573) @@ -1,165 +1,167 @@ #! /bin/sh # $FreeBSD$ # # MAINTAINER: portmgr@FreeBSD.org # # This script is used by poudriere and tinderbox(soon) as the source-of-truth for # what should be considered a leftover and what is whitelisted. # # !!!! This script's input/output format must remain backwards-compatible. # !!!! If you want to change it, create a new script and have the calling # !!!! scripts use the new one if available. # # Usage: env PORTSDIR=... check_leftovers.sh category/port # stdin: # - missing-file # + new-file # M modified-file reason... # # stdout: # same -/+/M format, but with files substituted, without approved # whitelisted files, and hides any directories already in plist. # # The PLIST_SUB feature can be disabled by setting PLIST_SUB_SED= # in environment. +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_CHECK_LEFTOVERS}" ] && set -x + origin="$1" [ $# -eq 1 ] || { echo "Must supply ORIGIN as parameter" >&2; exit 1; } [ -n "${PORTSDIR}" ] || { echo "PORTSDIR must be set" >&2; exit 1; } portdir="${PORTSDIR}/${origin}" # PREFIX/LOCALBASE may be set in env or want default from port. if [ -n "${PREFIX}" ]; then PORT_FLAGS="${PORT_FLAGS} PREFIX=${PREFIX}" else PREFIX=$(make -C ${portdir} -VPREFIX) fi if [ -n "${LOCALBASE}" ]; then PORT_FLAGS="${PORT_FLAGS} LOCALBASE=${LOCALBASE}" else LOCALBASE=$(make -C ${portdir} -VLOCALBASE) fi if [ -z "${CCACHE_DIR}" ]; then CCACHE_DIR=$(make -C ${portdir} -VCCACHE_DIR) fi homedirs=$(awk -F: -v users=$(make -C ${portdir} -V USERS|sed -e 's, ,|,g;/^$/d;s,^,^(,;s,$,)$,') 'users && $1 ~ users {print $9}' ${PORTSDIR}/UIDs|sort -u|sed -e "s|/usr/local|${PREFIX}|"|tr "\n" " ") plistsub_sed=$(make -C ${portdir} -VPLIST_SUB_SED | /bin/sh ${PORTSDIR}/Mk/Scripts/plist_sub_sed_sort.sh) tmpplist=$(make -C ${portdir} -VTMPPLIST) while read modtype path extra; do # Ignore everything from these files/directories case "${path}" in ${CCACHE_DIR}/*|\ /compat/linux/proc/*|\ /dev/*|\ /etc/make.conf.bak|\ /proc/*|\ /tmp/*|\ /var/db/pkg/*|\ /var/db/ports/*|\ /var/log/*|\ /var/mail/*|\ /var/run/*|\ /var/tmp/*) continue ;; # fc-cache - skip for now /var/db/fontconfig/*) continue ;; esac ignore_path=0 sub_path=$(echo "$path" | sed -e "s|^${PREFIX}/||" -e "${plistsub_sed}") orig_sub_path="${sub_path}" # If this is a directory, use @dir in output is_dir=0 if [ -d "${path}" ]; then is_dir=1 sub_path="@dir ${sub_path}" fi # Handle PORTDOCS/PORTEXAMPLES/etc case "${orig_sub_path}" in %%DOCSDIR%%*) sub_path="%%PORTDOCS%%${sub_path}" ;; %%EXAMPLESDIR%%*) sub_path="%%PORTEXAMPLES%%${sub_path}" ;; esac case $modtype in +) if [ ${is_dir} -eq 1 ]; then # home directory of users created case " ${homedirs} " in *\ ${path}\ *) continue ;; *\ ${path}/*\ *) continue ;; esac # Don't show dirs already in plist (due to parents) grep -qE \ "^@(unexec rmdir \"?(%D/|${PREFIX})?${path#${PREFIX}/}[ \"]|dir(rm|rmtry)? ${path#${PREFIX}/}\$)" \ ${tmpplist} && continue fi # Check absolute paths case "${path}" in # Leave qmail's queue dir alone to not cause lost mail # during upgrades, just as /var/mail is left alone. /var/qmail/queue/*|/var/qmail/queue) continue ;; esac # Check relative/plist paths case "${sub_path}" in # gconftool-2 --makefile-uninstall-rule is unpredictable etc/gconf/gconf.xml.defaults/%gconf-tree*.xml) ;; *) echo "+ ${sub_path}" ;; esac ;; -) # Skip removal of PREFIX and PREFIX/info from # bsd.port.mk for now. # Skip if it is PREFIX and non-LOCALBASE. See misc/kdehier4 # or mail/qmail for examples [ "${path}" = "${PREFIX}" -a "${LOCALBASE}" != "${PREFIX}" ] && ignore_path=1 # The removal of info may be a bug; it's part of BSD.local.dist. # See ports/74691 [ "${sub_path}" = "info" -a "${LOCALBASE}" != "${PREFIX}" ] && ignore_path=1 [ $ignore_path -eq 0 ] && echo "- ${sub_path}" ;; M) # Check relative/plist paths case "${sub_path}" in # gconftool-2 --makefile-uninstall-rule is unpredictable etc/gconf/gconf.xml.defaults/%gconf-tree*.xml) ;; # This is a cache file for gio modules could be modified # for any gio modules lib/gio/modules/giomodule.cache) ;; # removal of info files leaves entry uneasy to cleanup # in info/dir info/dir) ;; */info/dir) ;; # The is pear database cache %%PEARDIR%%/.depdb|%%PEARDIR%%/.filemap) ;; #ls-R files from texmf are often regenerated */ls-R) ;; # Octave packages database, blank lines can be inserted # between pre-install and post-deinstall share/octave/octave_packages) ;; # xmlcatmgr is constantly updating catalog.ports ignore # modification to that file share/xml/catalog.ports) ;; # Ignore common system config files /etc/group|\ /etc/make.conf|\ /etc/master.passwd|\ /etc/passwd|\ /etc/pwd.db|\ /etc/shells|\ /etc/spwd.db) ;; *) echo "M ${sub_path#@dir } ${extra}" ;; esac ;; esac done exit 0 Index: head/Mk/Scripts/depends-list.sh =================================================================== --- head/Mk/Scripts/depends-list.sh (revision 415572) +++ head/Mk/Scripts/depends-list.sh (revision 415573) @@ -1,89 +1,91 @@ #!/bin/sh # MAINTAINER: portmgr@FreeBSD.org # $FreeBSD$ set -e . ${dp_SCRIPTSDIR}/functions.sh recursive=0 requires_wrkdir=0 while getopts "rw" FLAG; do case "${FLAG}" in r) recursive=1 ;; w) # Only list dependencies that have a WRKDIR. Used for # 'make clean-depends'. requires_wrkdir=1 ;; *) echo "Unknown flag" >&2 exit 1 ;; esac done shift $((OPTIND-1)) validate_env PORTSDIR dp_PKGNAME if [ ${recursive} -eq 1 -o ${requires_wrkdir} -eq 1 ]; then validate_env dp_MAKE # Cache command executions to avoid looking them up again in every # sub-make. MAKE="${dp_MAKE}" export_ports_env >/dev/null fi +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_DEPENDS_LIST}" ] && set -x + set -u check_dep() { local _dep wrkdir show_dep for _dep ; do myifs=${IFS} IFS=: set -- ${_dep} IFS=${myifs} case "${2}" in /*) d=${2} ;; *) d=${PORTSDIR}/${2} ;; esac case " ${checked} " in *\ ${d}\ *) continue ;; # Already checked esac checked="${checked} ${d}" # Check if the dependency actually exists or skip otherwise. if [ ! -d ${d} ]; then echo "${dp_PKGNAME}: \"${d}\" non-existent -- dependency list incomplete" >&2 continue fi # Grab any needed vars from the port. if [ ${requires_wrkdir} -eq 1 -a ${recursive} -eq 1 ]; then set -- $(${dp_MAKE} -C ${d} -VWRKDIR -V_UNIFIED_DEPENDS) wrkdir="$1" shift elif [ ${requires_wrkdir} -eq 1 -a ${recursive} -eq 0 ]; then set -- "$(${dp_MAKE} -C ${d} -VWRKDIR)" wrkdir="$1" elif [ ${recursive} -eq 1 ]; then set -- $(${dp_MAKE} -C ${d} -V_UNIFIED_DEPENDS) fi # If a WRKDIR is required to show the dependency, check for it. show_dep=1 if [ ${requires_wrkdir} -eq 1 ] && ! [ -d "${wrkdir}" ]; then show_dep=0 fi [ ${show_dep} -eq 1 ] && echo ${d} if [ ${recursive} -eq 1 ]; then check_dep $@ fi done } checked= check_dep $@ Index: head/Mk/Scripts/dialog4ports.sh =================================================================== --- head/Mk/Scripts/dialog4ports.sh (revision 415572) +++ head/Mk/Scripts/dialog4ports.sh (revision 415573) @@ -1,48 +1,50 @@ #! /bin/sh # $FreeBSD$ # Maintainer: portmgr@FreeBSD.org set -e +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_DIALOG4PORTS}" ] && set -x + if [ -z "${DIALOG4PORTS}" -o -z "${PORTSDIR}" -o -z "${MAKE}" ]; then echo "DIALOG4PORTS, MAKE and PORTSDIR required in environment." >&2 exit 1 fi : ${DIALOGPORT:=ports-mgmt/dialog4ports} : ${DIALOGNAME:=dialog4ports} OPTIONSFILE="$1" if ! [ -e $DIALOG4PORTS ]; then # If INSTALL_AS_USER is set then just build and use the WRKDIR version # Also do this if PREFIX!=LOCALBASE to avoid missing file or double # installs if [ -n "${INSTALL_AS_USER}" -o "${PREFIX}" != "${LOCALBASE}" ]; then if ! [ -d "${PORTSDIR}/${DIALOGPORT}" ]; then echo "===> Skipping 'config' as ${DIALOGPORT} is not checked out" >&2 exit 1 fi DIALOG4PORTS=$(${MAKE} -C ${PORTSDIR}/${DIALOGPORT} -V DIALOG4PORTS) if ! [ -e "${DIALOG4PORTS}" ]; then echo "===> Building ${DIALOGNAME} as it is required for the config dialog" ${MAKE} -C ${PORTSDIR}/${DIALOGPORT} -D NO_DIALOG clean build fi else # Build+install through su-install as normal echo "===> Building/installing ${DIALOGNAME} as it is required for the config dialog" ${MAKE} -C ${PORTSDIR}/${DIALOGPORT} -D NO_DIALOG clean install # Need to clean again as it can't run twice in 1 call above ${MAKE} -C ${PORTSDIR}/${DIALOGPORT} -D NO_DIALOG clean fi fi # Backwards compat with older version which used stdout [<= 0.1.1] (or stderr [0.1.2]). # Clear environment of PKGNAME or the dialog will show on older versions # that do not understand -v. if ! env -u PKGNAME ${DIALOG4PORTS} -v > /dev/null 2>&1; then exec $DIALOG4PORTS > $OPTIONSFILE 2>&1 fi # Newer versions use stderr to work around a jail issue # http://lists.freebsd.org/pipermail/freebsd-ports/2013-March/082383.html exec $DIALOG4PORTS 2> $OPTIONSFILE Index: head/Mk/Scripts/do-depends.sh =================================================================== --- head/Mk/Scripts/do-depends.sh (revision 415572) +++ head/Mk/Scripts/do-depends.sh (revision 415573) @@ -1,188 +1,190 @@ #!/bin/sh # $FreeBSD$ # # MAINTAINER: portmgr@FreeBSD.org set -e . ${dp_SCRIPTSDIR}/functions.sh validate_env dp_RAWDEPENDS dp_DEPTYPE dp_DEPENDS_TARGET dp_DEPENDS_PRECLEAN \ dp_DEPENDS_CLEAN dp_DEPENDS_ARGS dp_USE_PACKAGE_DEPENDS \ dp_USE_PACKAGE_DEPENDS_ONLY dp_PKG_ADD dp_PKG_INFO dp_WRKDIR \ dp_PKGNAME dp_STRICT_DEPENDS dp_LOCALBASE dp_LIB_DIRS dp_SH \ dp_SCRIPTSDIR PORTSDIR dp_MAKE +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_DO_DEPENDS}" ] && set -x + set -u install_depends() { origin=$1 target=$2 depends_args=$3 if [ -z "${dp_USE_PACKAGE_DEPENDS}" -a -z "${dp_USE_PACKAGE_DEPENDS_ONLY}" ]; then ${dp_MAKE} -C ${origin} -DINSTALLS_DEPENDS ${target} ${depends_args} return 0 fi read pkgfile <<- EOF $(${dp_MAKE} -C ${origin} -VPKGFILE) EOF read pkgbase <<- EOF $(${dp_MAKE} -C ${origin} -VPKGBASE) EOF if [ -r "${pkgfile}" -a "${target}" = "${dp_DEPENDS_TARGET}" ]; then echo "===> Installing existing package ${pkgfile}" if [ "${pkgbase}" = "pkg" ]; then [ -d ${dp_WRKDIR} ] || mkdir -p ${dp_WRKDIR} tar xf ${pkgfile} -C ${dp_WRKDIR} -s ",/.*/,,g" "*/pkg-static" ${dp_WRKDIR}/pkg-static add ${pkgfile} rm -f ${dp_WRKDIR}/pkg-static else ${dp_PKG_ADD} -A ${pkgfile} fi elif [ -n "${dp_USE_PACKAGE_DEPENDS_ONLY}" -a "${target}" = "${dp_DEPENDS_TARGET}" ]; then echo "===> ${dp_PKGNAME} depends on package: ${pkgfile} - not found" >&2 echo "===> dp_USE_PACKAGE_DEPENDS_ONLY set - not building missing dependency from source" >&2 exit 1 else ${dp_MAKE} -C ${origin} -DINSTALLS_DEPENDS ${target} ${depends_args} fi } find_package() { if ${dp_PKG_INFO} "$1" >/dev/null 2>&1; then echo "===> ${dp_PKGNAME} depends on package: $1 - found" return 0 fi echo "===> ${dp_PKGNAME} depends on package: $1 - not found" return 1 } find_file() { if [ -e "$1" ]; then echo "===> ${dp_PKGNAME} depends on file: $1 - found" return 0 fi echo "===> ${dp_PKGNAME} depends on file: $1 - not found" return 1 } find_file_path() { if which -s $1 ; then echo "===> ${dp_PKGNAME} depends on executable: $1 - found" return 0 fi echo "===> ${dp_PKGNAME} depends on executable: $1 - not found" return 1 } find_lib() { echo -n "===> ${dp_PKGNAME} depends on shared library: $1" libfile=$(env -i PATH="${PATH}" LIB_DIRS="${dp_LIB_DIRS}" LOCALBASE="${dp_LOCALBASE}" ${dp_SH} ${dp_SCRIPTSDIR}/find-lib.sh $1) if [ -z "${libfile}" ]; then echo " - not found" return 1 fi echo " - found (${libfile})" } anynotfound=0 err=0 for _line in ${dp_RAWDEPENDS} ; do myifs=${IFS} IFS=: set -- ${_line} IFS=${myifs} if [ $# -lt 2 -o $# -gt 3 ]; then echo "Error: bad dependency syntax in ${dp_DEPTYPE}" >&2 echo "expecting: pattern:origin[:target]" >&2 echo "got: ${_line}" >&2 err=1 continue fi pattern=$1 origin=$2 last=${3:-} if [ -z "${pattern}" ]; then echo "Error: there is an empty port dependency in ${dp_DEPTYPE}" >&2 err=1 continue fi if [ -z "${origin}" ]; then echo "Error: a dependency has an empty origin in ${dp_DEPTYPE}" >&2 err=1 continue fi case "${origin}" in /*) ;; *) origin="${PORTSDIR}/${origin}" ;; esac depends_args="${dp_DEPENDS_ARGS}" target=${dp_DEPENDS_TARGET} if [ -n "${last}" ]; then target=${last} if [ -n "${dp_DEPENDS_PRECLEAN}" ]; then target="clean ${target}" depends_args="NOCLEANDEPENDS=yes" fi if [ -n "${dp_DEPENDS_CLEAN}" ]; then target="${target} clean" depends_args="NOCLEANDEPENDS=yes" fi fi case ${dp_DEPTYPE} in LIB_DEPENDS) case ${pattern} in lib*.so*) fct=find_lib ;; *) echo "Error: pattern ${pattern} in LIB_DEPENDS is not valid" err=1 continue ;; esac ;; *) case ${pattern} in *\>*|*\<*|*=*) fct=find_package ;; /nonexistent) fct=false ;; /*) fct=find_file ;; *) fct=find_file_path ;; esac ;; esac if ${fct} "${pattern}" ; then continue fi [ ${pattern} = "/nonexistent" ] || anynotfound=1 if [ ! -f "${origin}/Makefile" ]; then echo "Error a dependency refers to a non existing origin: ${origin} in ${dp_DEPTYPE}" >&2 err=1 continue fi # Now actually install the dependencies install_depends "${origin}" "${target}" "${depends_args}" # Recheck if the installed dependency validates the pattern except for /nonexistent [ "${fct}" = "false" ] || ${fct} "${pattern}" echo "===> Returning to build of ${dp_PKGNAME}" done if [ $err -eq 1 ]; then echo "Errors with dependencies." exit 1 fi if [ -n "${dp_STRICT_DEPENDS}" -a ${anynotfound} -eq 1 ]; then \ echo "===> dp_STRICT_DEPENDS set - Not installing missing dependencies." echo " This means a dependency is wrong since it was not satisfied in the ${dp_DEPTYPE} phase." exit 1 fi Index: head/Mk/Scripts/do-users-groups.sh =================================================================== --- head/Mk/Scripts/do-users-groups.sh (revision 415572) +++ head/Mk/Scripts/do-users-groups.sh (revision 415573) @@ -1,179 +1,181 @@ #!/bin/sh # $FreeBSD$ # # MAINTAINER: portmgr@FreeBSD.org set -e . "${dp_SCRIPTSDIR}/functions.sh" validate_env dp_ECHO_MSG dp_GID_FILES dp_GID_OFFSET dp_GROUPS_BLACKLIST \ dp_INSTALL dp_OPSYS dp_OSVERSION dp_PREFIX dp_PW dp_SCRIPTSDIR \ dp_UG_DEINSTALL dp_UG_INSTALL dp_UID_FILES dp_UID_OFFSET \ dp_USERS_BLACKLIST +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_DO_USERS_GROUPS}" ] && set -x + set -u USERS=$1 GROUPS=$2 error() { ${dp_ECHO_MSG} "${1}" exit 1 } rm -f "${dp_UG_INSTALL}" "${dp_UG_DEINSTALL}" || : # Before FreeBSD 10.2, PW did not have -R support. if [ "${dp_OPSYS}" = FreeBSD ] && [ "${dp_OSVERSION}" -ge 1002000 ]; then cat >> "${dp_UG_INSTALL}" <<-eot if [ -n "\${PKG_ROOTDIR}" ] && [ "\${PKG_ROOTDIR}" != "/" ]; then PW="${dp_PW} -R \${PKG_ROOTDIR}" else PW=${dp_PW} fi eot else echo "PW=${dp_PW}" >> "${dp_UG_INSTALL}" fi # Both scripts need to start the same, so cp -f "${dp_UG_INSTALL}" "${dp_UG_DEINSTALL}" if [ -n "${GROUPS}" ]; then for file in ${dp_GID_FILES}; do if [ ! -f "${file}" ]; then error "** ${file} doesn't exist. Exiting." fi done ${dp_ECHO_MSG} "===> Creating groups." echo "echo \"===> Creating groups.\"" >> "${dp_UG_INSTALL}" for group in ${GROUPS}; do # _bgpd:*:130: if ! grep -q "^${group}:" ${dp_GID_FILES}; then \ error "** Cannot find any information about group \`${group}' in ${dp_GID_FILES}." fi o_IFS=${IFS} IFS=":" while read -r group _ gid _; do if [ -z "${gid}" ]; then error "Group line for group ${group} has no gid" fi gid=$((gid+dp_GID_OFFSET)) cat >> "${dp_UG_INSTALL}" <<-eot2 if ! \${PW} groupshow $group >/dev/null 2>&1; then echo "Creating group '$group' with gid '$gid'." \${PW} groupadd $group -g $gid else echo "Using existing group '$group'." fi eot2 done <<-eot $(grep -h "^${group}:" ${dp_GID_FILES} | head -n 1) eot IFS=${o_IFS} done fi if [ -n "${USERS}" ]; then for file in ${dp_UID_FILES}; do if [ ! -f "${file}" ]; then error "** ${file} doesn't exist. Exiting." fi done ${dp_ECHO_MSG} "===> Creating users" echo "echo \"===> Creating users\"" >> "${dp_UG_INSTALL}" for user in ${USERS}; do # _bgpd:*:130:130:BGP Daemon:/var/empty:/sbin/nologin if ! grep -q "^${user}:" ${dp_UID_FILES} ; then error "** Cannot find any information about user \`${user}' in ${dp_UID_FILES}." fi o_IFS=${IFS} IFS=":" while read -r login _ uid gid class _ _ gecos homedir shell; do if [ -z "$uid" ] || [ -z "$gid" ] || [ -z "$homedir" ] || [ -z "$shell" ]; then error "User line for ${user} is invalid" fi uid=$((uid+dp_UID_OFFSET)) gid=$((gid+dp_GID_OFFSET)) if [ -n "$class" ]; then class="-L $class" fi homedir=$(echo "$homedir" | sed "s|^/usr/local|${dp_PREFIX}|") cat >> "${dp_UG_INSTALL}" <<-eot2 if ! \${PW} usershow $login >/dev/null 2>&1; then echo "Creating user '$login' with uid '$uid'." \${PW} useradd $login -u $uid -g $gid $class -c "$gecos" -d $homedir -s $shell else echo "Using existing user '$login'." fi eot2 case $homedir in /|/nonexistent|/var/empty) ;; *) echo "${dp_INSTALL} -d -g $gid -o $uid $homedir" >> "${dp_UG_INSTALL}" ;; esac done <<-eot $(grep -h "^${user}:" ${dp_UID_FILES} | head -n 1) eot IFS=${o_IFS} done fi if [ -n "${GROUPS}" ]; then for group in ${GROUPS}; do # mail:*:6:postfix,clamav o_IFS=${IFS} IFS=":" while read -r group _ gid members; do gid=$((gid+dp_GID_OFFSET)) oo_IFS=${IFS} IFS="," for login in $members; do for user in ${USERS}; do if [ -n "${user}" ] && [ "${user}" = "${login}" ]; then cat >> "${dp_UG_INSTALL}" <<-eot2 if ! \${PW} groupshow ${group} | grep -qw ${login}; then echo "Adding user '${login}' to group '${group}'." \${PW} groupmod ${group} -m ${login} fi eot2 fi done done IFS=${oo_IFS} done <<-eot $(grep -h "^${group}:" ${dp_GID_FILES} | head -n 1) eot IFS=${o_IFS} done fi if [ -n "${USERS}" ]; then for user in ${USERS}; do if ! echo "${dp_USERS_BLACKLIST}" | grep -qw "${user}"; then cat >> "${dp_UG_DEINSTALL}" <<-eot if \${PW} usershow ${user} >/dev/null 2>&1; then echo "==> You should manually remove the \"${user}\" user. " fi eot fi done fi if [ -n "${GROUPS}" ]; then for group in ${GROUPS}; do if ! echo "${dp_GROUPS_BLACKLIST}" | grep -qw "${group}"; then cat >> "${dp_UG_DEINSTALL}" <<-eot if \${PW} groupshow ${group} >/dev/null 2>&1; then echo "==> You should manually remove the \"${group}\" group " fi eot fi done fi Index: head/Mk/Scripts/find-lib.sh =================================================================== --- head/Mk/Scripts/find-lib.sh (revision 415572) +++ head/Mk/Scripts/find-lib.sh (revision 415573) @@ -1,31 +1,33 @@ #!/bin/sh # MAINTAINER: portmgr@FreeBSD.org # $FreeBSD$ +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_FIND_LIB}" ] && set -x + if [ -z "${LIB_DIRS}" -o -z "${LOCALBASE}" ]; then echo "LIB_DIRS, LOCALBASE required in environment." >&2 exit 1 fi if [ -f /usr/share/misc/magic.mime -o -f /usr/share/misc/magic.mime.mgc ]; then echo >&2 echo "Either /usr/share/misc/magic.mime or /usr/share/misc/magic.mime.mgc exist and must be removed." >&2 echo "These are legacy files from an older release and may safely be deleted." >&2 echo "Please see UPDATING 20150213 for more details." >&2 exit 1 fi if [ $# -ne 1 ]; then echo "$0: no argument provided." >&2 fi lib=$1 dirs="${LIB_DIRS} `cat ${LOCALBASE}/libdata/ldconfig/* 2>/dev/null || :`" for libdir in ${dirs} ; do test -f ${libdir}/${lib} || continue libfile=${libdir}/${lib} [ `file -b -L --mime-type ${libfile}` = "application/x-sharedlib" ] || continue echo $libfile break done Index: head/Mk/Scripts/qa.sh =================================================================== --- head/Mk/Scripts/qa.sh (revision 415572) +++ head/Mk/Scripts/qa.sh (revision 415573) @@ -1,322 +1,324 @@ #!/bin/sh # MAINTAINER: portmgr@FreeBSD.org # $FreeBSD$ if [ -z "${STAGEDIR}" -o -z "${PREFIX}" -o -z "${LOCALBASE}" ]; then echo "STAGEDIR, PREFIX, LOCALBASE required in environment." >&2 exit 1 fi +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_QA}" ] && set -x + LF=$(printf '\nX') LF=${LF%X} warn() { echo "Warning: $@" >&2 } err() { echo "Error: $@" >&2 } shebangonefile() { local f interp rc f="$@" rc=0 # blacklist of files which are not intended to be runnable case "${f##*/}" in *.pm|*.pod|*.txt) return 0 ;; esac interp=$(sed -n -e '1s/^#![[:space:]]*\([^[:space:]]*\).*/\1/p;2q' "${f}") case "${interp}" in "") ;; ${LINUXBASE}/*) ;; ${LOCALBASE}/*) ;; ${PREFIX}/*) ;; /bin/csh) ;; /bin/sh) ;; /bin/tcsh) ;; /usr/bin/awk) ;; /usr/bin/env) ;; /usr/bin/nawk) ;; /usr/bin/sed) ;; /usr/sbin/dtrace) ;; *) err "'${interp}' is an invalid shebang you need USES=shebangfix for '${f#${STAGEDIR}${PREFIX}/}'" rc=1 ;; esac return ${rc} } shebang() { local f l link rc rc=0 while read f; do # No results presents a blank line from heredoc. [ -z "${f}" ] && continue shebangonefile "${f}" || rc=1 # Use heredoc to avoid losing rc from find|while subshell done <<-EOF $(find ${STAGEDIR}${PREFIX}/bin ${STAGEDIR}${PREFIX}/sbin \ ${STAGEDIR}${PREFIX}/libexec ${STAGEDIR}${PREFIX}/www \ -type f -perm +111 2>/dev/null) EOF # Split stat(1) result into 2 lines and read each line separately to # retain spaces in filenames. while read l; do # No results presents a blank line [ -z "${l}" ] && continue read link case "${link}" in /*) f="${STAGEDIR}${link}" ;; *) f="${l%/*}/${link}" ;; esac if [ -f "${f}" ]; then shebangonefile "${f}" || rc=1 fi # Use heredoc to avoid losing rc from find|while subshell done <<-EOF $(find ${STAGEDIR}${PREFIX}/bin ${STAGEDIR}${PREFIX}/sbin \ ${STAGEDIR}${PREFIX}/libexec ${STAGEDIR}${PREFIX}/www \ -type l -exec stat -f "%N${LF}%Y" {} + 2>/dev/null) EOF return ${rc} } baselibs() { local rc [ "${PKGBASE}" = "pkg" -o "${PKGBASE}" = "pkg-devel" ] && return while read f; do case ${f} in *NEEDED*\[libarchive.so.[56]]) err "Bad linking on ${f##* } please add USES=libarchive" rc=1 ;; *NEEDED*\[libedit.so.7]) err "Bad linking on ${f##* } please add USES=libedit" rc=1 ;; esac done <<-EOF $(find ${STAGEDIR}${PREFIX}/bin ${STAGEDIR}${PREFIX}/sbin \ ${STAGEDIR}${PREFIX}/lib ${STAGEDIR}${PREFIX}/libexec \ -type f -exec readelf -d {} + 2>/dev/null) EOF return ${rc} } symlinks() { local rc rc=0 # Split stat(1) result into 2 lines and read each line separately to # retain spaces in filenames. while read l; do # No results presents a blank line from heredoc. [ -z "${l}" ] && continue read link case "${link}" in ${STAGEDIR}*) err "Bad symlink '${l#${STAGEDIR}${PREFIX}/}' pointing inside the stage directory" rc=1 ;; esac # Use heredoc to avoid losing rc from find|while subshell. done <<-EOF $(find ${STAGEDIR} -type l -exec stat -f "%N${LF}%Y" {} +) EOF return ${rc} } paths() { local rc rc=0 while read f; do # No results presents a blank line from heredoc. [ -z "${f}" ] && continue # Ignore false-positive/harmless files case "${f}" in */lib/ruby/gems/*) continue ;; */share/texmf-var/web2c/*/*.fmt) continue ;; */share/texmf-var/web2c/*/*.log) continue ;; esac err "'${f#${STAGEDIR}${PREFIX}/}' is referring to ${STAGEDIR}" rc=1 # Use heredoc to avoid losing rc from find|while subshell done <<-EOF $(find ${TMPPLIST} ${STAGEDIR} -type f -exec grep -l "${STAGEDIR}" {} +) EOF return ${rc} } # For now do not raise an error, just warnings stripped() { [ -x /usr/bin/file ] || return # this is fatal [ -n "${STRIP}" ] || return 0 # Split file and result into 2 lines and read separately to ensure # files with spaces are kept intact. # Using readelf -h ... /ELF Header:/ will match on all ELF files. find ${STAGEDIR} -type f ! -name '*.a' ! -name '*.o' \ -exec readelf -S {} + 2>/dev/null | awk '\ /File:/ {sub(/File: /, "", $0); file=$0} \ /SYMTAB/ {print file}' | while read f; do warn "'${f#${STAGEDIR}${PREFIX}/}' is not stripped consider trying INSTALL_TARGET=install-strip or using \${STRIP_CMD}" done } desktopfileutils() { if [ -z "${USESDESKTOPFILEUTILS}" ]; then grep -q MimeType= ${STAGEDIR}${PREFIX}/share/applications/*.desktop 2>/dev/null && warn "you need USES=desktop-file-utils" else grep -q MimeType= ${STAGEDIR}${PREFIX}/share/applications/*.desktop 2>/dev/null || warn "you may not need USES=desktop-file-utils" fi return 0 } sharedmimeinfo() { local f found found=0 for f in ${STAGEDIR}${PREFIX}/share/mime/packages/*.xml; do [ "${f}" = "${STAGEDIR}${PREFIX}/share/mime/packages/*.xml" ] && break #no matches [ "${f}" = "${STAGEDIR}${PREFIX}/share/mime/packages/freedesktop.org.xml" ] && continue found=1 break done if [ -z "${USESSHAREDMIMEINFO}" -a ${found} -eq 1 ]; then warn "you need USES=shared-mime-info" elif [ -n "${USESSHAREDMIMEINFO}" -a ${found} -eq 0 ]; then warn "you may not need USES=shared-mime-info" fi return 0 } suidfiles() { local filelist filelist=`find ${STAGEDIR} -type f \ \( -perm -u+x -or -perm -g+x -or -perm -o+x \) \ \( -perm -u+s -or -perm -g+s \)` if [ -n "${filelist}" ]; then warn "setuid files in the stage directory (are these necessary?):" ls -liTd ${filelist} fi return 0 } libtool() { if [ -z "${USESLIBTOOL}" ]; then find ${STAGEDIR} -name '*.la' | while read f; do grep -q 'libtool library' "${f}" && err ".la libraries found, port needs USES=libtool" && return 1 || true done # The return above continues here. fi } libperl() { local has_some_libperl_so files found if [ -n "${SITE_ARCH_REL}" -a -d "${STAGEDIR}${PREFIX}/${SITE_ARCH_REL}" ]; then has_some_libperl_so=0 files=0 while read f; do # No results presents a blank line from heredoc. [ -z "${f}" ] && continue files=$((files+1)) found=`readelf -d ${f} | awk "BEGIN {libperl=1; rpath=10; runpath=100} /NEEDED.*${LIBPERL}/ { libperl = 0 } /RPATH.*perl.*CORE/ { rpath = 0 } /RUNPATH.*perl.*CORE/ { runpath = 0 } END {print libperl+rpath+runpath} "` case "${found}" in *1) warn "${f} is not linked with ${LIBPERL}, not respecting lddlflags?" ;; *0) has_some_libperl_so=1 # Older Perl did not USE_LDCONFIG. if [ ! -f ${LOCALBASE}/${LDCONFIG_DIR}/perl5 ]; then case "${found}" in *1?) warn "${f} does not have a rpath to ${LIBPERL}, not respecting lddlflags?" ;; esac case "${found}" in 1??) warn "${f} does not have a runpath to ${LIBPERL}, not respecting lddlflags?" ;; esac fi ;; esac # Use heredoc to avoid losing rc from find|while subshell done <<-EOT $(find ${STAGEDIR}${PREFIX}/${SITE_ARCH_REL} -name '*.so') EOT if [ ${files} -gt 0 -a ${has_some_libperl_so} -eq 0 ]; then err "None of the .so in ${STAGEDIR}${PREFIX}/${SITE_ARCH_REL} are linked with ${LIBPERL}, see above for the full list." return 1 else return 0 fi fi } prefixvar() { if test -d ${STAGEDIR}${PREFIX}/var; then warn "port uses ${PREFIX}/var instead of /var" fi } terminfo() { local f found for f in ${STAGEDIR}${PREFIX}/share/misc/*.terminfo; do [ "${f}" = "${STAGEDIR}${PREFIX}/share/misc/*.terminfo" ] && break #no matches found=1 break done for f in ${STAGEDIR}${PREFIX}/share/misc/terminfo.db*; do [ "${f}" = "${STAGEDIR}${PREFIX}/share/misc/terminfo.db*" ] && break #no matches found=1 break done if [ -z "${USESTERMINFO}" -a -n "${found}" ]; then warn "you need USES=terminfo" elif [ -n "${USESTERMINFO}" -a -z "${found}" ]; then warn "you may not need USES=terminfo" fi return 0 } checks="shebang symlinks paths stripped desktopfileutils sharedmimeinfo suidfiles libtool libperl prefixvar baselibs terminfo" ret=0 cd ${STAGEDIR} for check in ${checks}; do ${check} || ret=1 done exit ${ret} Index: head/Mk/Scripts/smart_makepatch.sh =================================================================== --- head/Mk/Scripts/smart_makepatch.sh (revision 415572) +++ head/Mk/Scripts/smart_makepatch.sh (revision 415573) @@ -1,260 +1,261 @@ #!/bin/sh # MAINTAINER: portmgr@FreeBSD.org # $FreeBSD$ # This script regenerates patches. It conserves existing comments and # file names, even if the file name does not meet any current or # previous convention. It will keep multiple patches in the same file # rather than splitting them into individual files. # # If a generated patch was not present before, it will create a file # name where forward slashes are replaced with an underscore and # underscores are appended by another underscore. # # Limitations: # 1) If a file is modified by multiple patches, it will be regenerated # as a single patch. That means if two multi-patch files modified # the same source file, when regenerated, the source file's patch # will only appear in one of patch file. # 2) It's possible that trailing garbage at the end of a patch in a # multipatch file might corrupt the comment (or be interpreted as # a comment) of the following patch. (garbage in, garbage out) # # Reminder # Don't forget to disable post-patch targets before regenerating patches # if those targets modify source files (e.g. with sed). You may also # want to disable EXTRA_PATCHES as well if that is being used. +[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_SMART_MAKEPATCH}" ] && set -x if [ -z "${PATCHDIR}" -o -z "${PATCH_WRKSRC}" -o -z "${WRKDIR}" ]; then echo "WRKDIR, PATCHDIR, and PATCH_WRKSRC required in environment." >&2 exit 1 fi WORKAREA=${WRKDIR}/.makepatch-tmp PATCHMAP=${WORKAREA}/pregen.map COMMENTS=${WORKAREA}/comments REGENNED=${WORKAREA}/regenerated DESTDIR=${WORKAREA}/staged SAVEDIR=${WORKAREA}/archived-patches case "${STRIP_COMPONENTS}" in [123456789]) ;; 1[0123456789]) ;; *) STRIP_COMPONENTS=0 esac strip_path() { local raw_name=$1 if [ "${STRIP_COMPONENTS}" = "0" ]; then echo ${raw_name} else echo ${raw_name} | awk -v sc=${STRIP_COMPONENTS} -F "/" \ '{ for (x = sc + 1; x <= NF; x++) { \ slash = (x>sc+1) ? "/" : ""; \ printf ("%s%s", slash, $x); \ }}' fi } std_patch_filename() { local sans_cwd local raw_name sans_cwd=$(echo $1 | sed 's|^\.\/||') raw_name=$(strip_path ${sans_cwd}) echo patch-$(echo ${raw_name} | sed -e 's|_|&&|g; s|/|_|g') } patchdir_files_list() { if [ -d "${PATCHDIR}" ]; then (cd ${PATCHDIR} && \ find * -type f -name "patch-*" -maxdepth 0 \ 2>/dev/null | sed -e '/\.orig$/d' ) fi; } valid_name() { local current_patch_name=$1 local result=$3 local first_target local testres local lps first_target=$(echo $2 | sed 's|^\.\/||') for lps in __ - + ; do testres=patch-$(echo ${first_target} | sed -e "s|/|${lps}|g") if [ "${testres}" = "${current_patch_name}" ]; then result=${testres} break fi done echo ${result} } map_existing_patches() { mkdir -p ${WORKAREA} : > ${PATCHMAP} local target local future_name local std_target local P local t for P in ${old_patch_list}; do target=$(cd ${PATCHDIR} && \ grep "^+++ " ${P} | awk '{print $2}' ) # For single patches, we honor previous separators, but use # a standard patch name if the current patch name does not # conform. However, if two or more patches are contained in # single file, then we do *NOT* rename the file future_name= for t in ${target}; do if [ -n "${future_name}" ]; then future_name=${P} break; fi std_target=$(std_patch_filename ${t}) future_name=$(valid_name ${P} ${t} ${std_target}) done for t in ${target}; do std_target=$(std_patch_filename ${t}) echo "${future_name} ${std_target}" >> ${PATCHMAP} done done } extract_comment_from_patch() { local existing_patch=${PATCHDIR}/$1 local contains local rawname local fname local num contains=$(grep "^+++ " ${existing_patch} | awk '{x++; print x}') for num in ${contains}; do rawname=$(grep "^+++ " ${existing_patch} | \ awk -v num=${num} '{x++; if (x==num) print $2}') fname=$(std_patch_filename $rawname) awk -v num=${num} '\ BEGIN { done=0; x=0; hunk=0; looking=(num==1) } \ { \ if (!done) { \ if ($1 == "@@") { \ split ($2,a,","); \ split ($3,b,","); \ hca = a[2]; hcb = a[3]; hunk = 1; } else if (hunk) { \ first=substr($1,1,1); \ if (first == "-") { hca-- } \ else if (first == "+") { hcb-- } \ else {hca--; hcb--} \ if (hca == 0 && hcb == 0) {hunk = 0} \ } \ if ($1 == "---") { \ x++; \ if (x == num) { done = 1 } \ if (x + 1 == num) { looking = 1 } \ } else if (!hunk && looking) { \ if ($1!="diff" && $1!="index" && $1!="+++") {\ print $0 \ } \ } \ } \ }' ${existing_patch} > ${COMMENTS}/${fname} done } extract_comments() { mkdir -p ${COMMENTS} rm -f ${COMMENTS}/* local P for P in ${old_patch_list}; do extract_comment_from_patch ${P} done } regenerate_patches() { mkdir -p ${REGENNED} rm -f ${REGENNED}/* [ ! -d "${PATCH_WRKSRC}" ] && return local F local NEW local OUT local ORIG local new_list new_list=$(cd "${PATCH_WRKSRC}" && \ find -s * -type f -name '*.orig' 2>/dev/null) (cd "${PATCH_WRKSRC}" && for F in ${new_list}; do ORIG=${F#./} NEW=${ORIG%.orig} cmp -s ${ORIG} ${NEW} && continue OUT=${REGENNED}/$(std_patch_filename ${NEW}) TZ=UTC diff -udp ${ORIG} ${NEW} | sed \ -e '/^---/s|\.[0-9]* +0000$| UTC|' \ -e '/^+++/s|\([[:blank:]][-0-9:.+]*\)*$||' \ > ${OUT} || true done) } get_patch_name() { awk -v name=$1 '\ { if ($2 == name) \ { \ if (!done) { print $1 }; \ done = 1; \ } \ } \ END { if (!done) print name }' ${PATCHMAP} } stage_patches() { mkdir -p ${DESTDIR} rm -f ${DESTDIR}/* local P local name local patch_list patch_list=$(cd ${REGENNED} && find * -name "patch-*" 2>/dev/null) for P in ${patch_list}; do name=$(get_patch_name ${P}) [ -e ${COMMENTS}/${P} ] && cat ${COMMENTS}/${P} \ >> ${DESTDIR}/${name} if [ "${P}" = "${name}" ]; then echo "Generated ${P}" else echo "Generated ${P} >> ${name} (legacy)" fi cat ${REGENNED}/${P} >> ${DESTDIR}/${name} done } conserve_old_patches() { mkdir -p ${SAVEDIR} rm -f ${SAVEDIR}/* [ -z "${old_patch_list}" ] && return local P for P in ${old_patch_list}; do mv ${PATCHDIR}/${P} ${SAVEDIR}/${P} done echo "The previous patches have been placed here:" echo ${SAVEDIR} } install_regenerated_patches() { local testdir=$(find ${DESTDIR} -empty) if [ -z "${testdir}" ]; then mkdir -p ${PATCHDIR} find ${DESTDIR} -type f -exec mv {} ${PATCHDIR}/ \; fi } old_patch_list=$(patchdir_files_list) map_existing_patches extract_comments regenerate_patches stage_patches conserve_old_patches install_regenerated_patches