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!

Reply via email to