commit: b6c180b9851ba94f68016836cbce2dde46e07165 Author: Kerin Millar <kfm <AT> plushkava <DOT> net> AuthorDate: Mon Feb 6 00:59:11 2023 +0000 Commit: Sam James <sam <AT> gentoo <DOT> org> CommitDate: Mon Feb 6 03:08:33 2023 +0000 URL: https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=b6c180b9
Eliminate the bashism that is the -nt test operator Presently, the is_older_than() function uses the -nt operator as part of a test command. As was reported by bug 579688, it is not supported by POSIX. In fact, there is no way to perform this kind of check with sh(1) and the standard utilities alone. After some deliberation, I concluded that relying on GNU findutils would be the best course of action. Not only does it provide the -newerXY predicate, but it is also required by PMS to begin with. The revised function works by using the -newermm predicate to compare any of the pathnames that it encounters against the specified reference path. In the event that it encounters any other path that is newer than the reference path, it shall immediately quit, rendering it fairly efficient. In fact, there is no circumstance under which more than one line of output needs to be read from find(1). The prior implementation would aggressively follow directories, even for symlinks. This seems unwise to me. Nevertheless, find(1) is given the -L option so as to preserve this behaviour. Considerable care has been taken to ensure that the revised function remains exit status compatible. I performed 50 individual tests to that end. One obvious difference is that directories whose names begin with a dot will now be recursed. I determined that there was no obviously apparent reason that this should be an issue. Regardless, it would be trivial to alter this behaviour in the future, if so neeed. Please note that it requires findutils >=4.9 as a runtime dependency, owing to its use of -files0-from, which is far too useful an option to wish to forgo. It will prefer "gfind" over "find", if the former is found to exist. Incidentally, the revised function is resilient to the case in which the sh(1) implementation does not support local. The anti-pattern of using local (which is undefined behaviour) to define a variable, while simultaneously assigning it, is becoming a most tiresome one. Signed-off-by: Kerin Millar <kfm <AT> plushkava.net> Bug: https://bugs.gentoo.org/579688 Signed-off-by: Sam James <sam <AT> gentoo.org> functions.sh | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/functions.sh b/functions.sh index acce989..0391c90 100644 --- a/functions.sh +++ b/functions.sh @@ -376,16 +376,32 @@ get_bootparam() # EXAMPLE: if is_older_than a.out *.o ; then ... is_older_than() { - local x= - local ref="$1" - [ $# -eq 0 ] || shift + local ref has_gfind - for x in "$@" ; do - [ "${x}" -nt "${ref}" ] && return 0 - [ -d "${x}" ] && is_older_than "${ref}" "${x}"/* && return 0 - done + if [ -e "$1" ]; then + ref=$1 + else + ref= + fi + shift - return 1 + # Consult the hash table in the present shell, prior to forking. + hash gfind 2>/dev/null; has_gfind=$(( $? == 0 )) + + for path; do + if [ -e "${path}" ]; then + printf '%s\0' "${path}" + fi + done | + { + set -- -L -files0-from - ${ref:+-newermm} ${ref:+"${ref}"} -printf '\n' -quit + if [ "${has_gfind}" -eq 1 ]; then + gfind "$@" + else + find "$@" + fi + } | + read -r line } # This is the main script, please add all functions above this point!
