From: "Sam James" <sam@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/gentoo-functions:master commit in: functions/, /
Date: Sun, 11 Aug 2024 10:11:10 +0000 (UTC) [thread overview]
Message-ID: <1723371063.6cf0940b8d336eb35a970af2ffc819f55e3ab429.sam@gentoo> (raw)
commit: 6cf0940b8d336eb35a970af2ffc819f55e3ab429
Author: Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Sat Aug 10 05:12:15 2024 +0000
Commit: Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Aug 11 10:11:03 2024 +0000
URL: https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=6cf0940b
Use the -nt and -ot test primaries again rather than depend on GNU find
As regards the test(1) utility, the POSIX.1-2024 specification defines
the -nt and -ot primaries as standard features. Given that the
specification in question was only recently published, this would not
normally be an adequate reason for using them in gentoo-functions, in
and as of itself. However, I was already aware that the these primaries
are commonly implemented and have been so for years.
So, I decided to evaluate a number of shells and see how things stand
now. Here is a list of the ones that I tested:
- ash (busybox 1.36.1)
- dash 0.5.12
- bash 5.2.26
- ksh 93u+
- loksh 7.5
- mksh 59c
- oksh 7.5
- sh (FreeBSD 14.1)
- sh (NetBSD 10.0)
- sh (OpenBSD 7.5)
- yash 2.56.1
Of these, bash, ksh93, loksh, mksh, oksh, OpenBSD sh and yash appear to
conform with the POSIX-1.2024 specification. The remaining four fail to
conform in one particular respect, which is as follows.
$ touch existent
$ set -- existent nonexistent
$ [ "$1" -nt "$2" ]; echo "$?" # should be 0
1
$ [ "$2" -ot "$1" ]; echo "$?" # should be 0
1
To address this, I discerned a reasonably straightforward workaround
that involves testing both whether the file under consideration exists
and whether the variable keeping track of the newest/oldest file has yet
been assigned to.
As far as I am concerned, the coverage is more than adequate for both
primaries to be used by gentoo-functions. As such, this commit adjusts
the following three functions so as to do exactly that.
- is_older_than()
- newest()
- oldest()
It also removes the following functions, since they are no longer used.
- _find0()
- _select_by_mtime()
With this, GNU findutils is no longer a required runtime dependency. Of
course, should a newly introduced feature of gentoo-functions benefit
from the presence of findutils in the future, there is no reason that it
cannot be brought back in that capacity.
Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>
Signed-off-by: Sam James <sam <AT> gentoo.org>
functions.sh | 157 +++++++++++++++++++++++++++++++++-----------------------
functions/rc.sh | 25 +++++++--
2 files changed, 113 insertions(+), 69 deletions(-)
diff --git a/functions.sh b/functions.sh
index 641deb6..43ea385 100644
--- a/functions.sh
+++ b/functions.sh
@@ -1,6 +1,6 @@
# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
-# shellcheck shell=sh disable=2209,3043
+# shellcheck shell=sh disable=2209,3013,3043
# This file contains a series of function declarations followed by some
# initialisation code. Functions intended for internal use shall be prefixed
@@ -294,17 +294,55 @@ is_anyof()
#
# Considers one or more pathnames and prints the one having the newest
-# modification time. If at least one parameter is provided, all parameters shall
-# be considered as pathnames to be compared to one another. Otherwise, the
-# pathnames to be compared shall be read from the standard input as
-# NUL-delimited records. If no pathnames are given, or those specified do not
-# exist, the return value shall be greater than 0. In the case that two or more
-# pathnames are candidates, the one having the lexicographically greatest value
-# shall be selected. Pathnames containing newline characters shall be ignored.
+# modification time. If at least one parameter is provided, all parameters
+# shall be considered as pathnames to be compared to one another. Otherwise,
+# the pathnames to be compared shall be read from the standard input as
+# null-terminated records. In the case that two or more pathnames are
+# candidates, whichever was first specified shall take precedence over the
+# other. If no pathnames are given, or those specified do not exist, the return
+# value shall be greater than 0.
+#
+# Pathnames containing <newline> characters shall be handled correctly if
+# conveyed as positional parameters. Otherwise, the behaviour for such
+# pathnames is unspecified. Users of the function are duly expected to refrain
+# from conveying such pathnames for consumption from the standard input; for
+# example, by specifying a predicate of ! -path $'*\n*' to the find utility.
+# This constraint is expected to be eliminated by a future amendment to the
+# function, once support for read -d becomes sufficiently widespread.
+#
+# The test utility is required to support the -nt primary, per POSIX-1.2024.
+# However, measures are in place to to achieve compatibility with shells that
+# implement the primary without yet fully adhering to the specification.
#
newest()
{
- _select_by_mtime -r "$@"
+ local path newest
+
+ newest=
+ if [ "$#" -gt 0 ]; then
+ for path; do
+ # The tests within curly braces address a conformance
+ # issue whereby [ existent -nt nonexistent ] is
+ # incorrectly false. As of August 2024, busybox ash,
+ # dash, FreeBSD sh and NetBSD sh are known to be
+ # non-conforming in this respect.
+ if { [ ! "${newest}" ] && [ -e "${path}" ]; } || [ "${path}" -nt "${newest}" ]; then
+ newest=$path
+ fi
+ done
+ test "${newest}" && printf '%s\n' "${newest}"
+ else
+ # Support for read -d '' is not yet sufficiently widespread.
+ tr '\0' '\n' |
+ {
+ while IFS= read -r path; do
+ if { [ ! "${newest}" ] && [ -e "${path}" ]; } || [ "${path}" -nt "${newest}" ]; then
+ newest=$path
+ fi
+ done
+ test "${newest}" && printf '%s\n' "${newest}"
+ }
+ fi
}
#
@@ -330,17 +368,55 @@ get_nprocs()
#
# Considers one or more pathnames and prints the one having the oldest
-# modification time. If at least one parameter is provided, all parameters shall
-# be considered as pathnames to be compared to one another. Otherwise, the
-# pathnames to be compared shall be read from the standard input as
-# NUL-delimited records. If no pathnames are given, or those specified do not
-# exist, the return value shall be greater than 0. In the case that two or more
-# pathnames are candidates, the one having the lexicographically lesser value
-# shall be selected. Pathnames containing newline characters shall be ignored.
+# modification time. If at least one parameter is provided, all parameters
+# shall be considered as pathnames to be compared to one another. Otherwise,
+# the pathnames to be compared shall be read from the standard input as
+# null-terminated records. In the case that two or more pathnames are
+# candidates, whichever was first specified shall take precedence over the
+# other. If no pathnames are given, or those specified do not exist, the return
+# value shall be greater than 0.
+#
+# Pathnames containing <newline> characters shall be handled correctly if
+# conveyed as positional parameters. Otherwise, the behaviour for such
+# pathnames is unspecified. Users of the function are duly expected to refrain
+# from conveying such pathnames for consumption from the standard input; for
+# example, by specifying a predicate of ! -path $'*\n*' to the find utility.
+# This constraint is expected to be eliminated by a future amendment to the
+# function, once support for read -d becomes sufficiently widespread.
+#
+# The test utility is required to support the -ot primary, per POSIX-1.2024.
#
oldest()
{
- _select_by_mtime -- "$@"
+ local path oldest
+
+ oldest=
+ if [ "$#" -gt 0 ]; then
+ for path; do
+ # The specification has [ nonexistent -ot existent ] as
+ # being true. Such is a nuisance in this case but the
+ # preceding tests suffice as a workaround.
+ if [ ! -e "${path}" ]; then
+ continue
+ elif [ ! "${oldest}" ] || [ "${path}" -ot "${oldest}" ]; then
+ oldest=$path
+ fi
+ done
+ test "${oldest}" && printf '%s\n' "${oldest}"
+ else
+ # Support for read -d '' is not yet sufficiently widespread.
+ tr '\0' '\n' |
+ {
+ while IFS= read -r path; do
+ if [ ! -e "${path}" ]; then
+ continue
+ elif [ ! "${oldest}" ] || [ "${path}" -ot "${oldest}" ]; then
+ oldest=$path
+ fi
+ done
+ test "${oldest}" && printf '%s\n' "${oldest}"
+ }
+ fi
}
#
@@ -675,34 +751,6 @@ whenceforth()
#------------------------------------------------------------------------------#
-#
-# See the definitions of _select_by_mtime() and is_older_than(). This function
-# requires that GNU findutils >=4.9 be installed.
-#
-_find0()
-{
- # Store the name of the GNU find binary, which may be "gfind".
- hash gfind 2>/dev/null && genfun_bin_find=gfind || genfun_bin_find=find
-
- _find0()
- {
- local opt
-
- case $1 in
- -[HL])
- opt=$1
- shift
- set -- "${opt}" -files0-from - "$@"
- ;;
- *)
- set -- -files0-from - "$@"
- esac
- "${genfun_bin_find}" "$@"
- }
-
- _find0 "$@"
-}
-
#
# Determines whether the terminal is a dumb one.
#
@@ -734,25 +782,6 @@ if [ "${BASH_VERSINFO-0}" -ge 5 ]; then
'
fi
-#
-# See the definitions of oldest() and newest().
-#
-_select_by_mtime()
-{
- local sort_opt
-
- sort_opt=$1
- shift
- if [ "$#" -gt 0 ]; then
- printf '%s\0' "$@"
- else
- cat
- fi \
- | _find0 -maxdepth 0 ! -path "*${genfun_newline}*" -printf '%T+ %p\n' \
- | sort "${sort_opt}" \
- | { IFS= read -r line && printf '%s\n' "${line#* }"; }
-}
-
#
# Considers the first parameter as a number of centiseconds and determines
# whether fewer have elapsed since the last occasion on which the function was
diff --git a/functions/rc.sh b/functions/rc.sh
index 0c14035..4eff3c8 100644
--- a/functions/rc.sh
+++ b/functions/rc.sh
@@ -1,6 +1,6 @@
# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
-# shellcheck shell=sh disable=3043
+# shellcheck shell=sh disable=3013,3043
# This file contains alternative implementations for some of the functions and
# utilities provided by OpenRC. Please refer to ../functions.sh for coding
@@ -205,9 +205,13 @@ get_bootparam()
# Takes the first parameter as a reference file/directory then determines
# whether any of the following parameters refer to newer files/directories.
#
+# The test utility is required to support the -nt primary, per POSIX-1.2024.
+# However, measures are in place to to achieve compatibility with shells that
+# implement the primary without yet fully adhering to the specification.
+#
is_older_than()
{
- local ref
+ local path ref
if [ "$#" -eq 0 ]; then
warn "is_older_than: too few arguments (got $#, expected at least 1)"
@@ -218,9 +222,20 @@ is_older_than()
ref=
fi
shift
- { test "$#" -gt 0 && printf '%s\0' "$@"; } \
- | _find0 -L ${ref:+-newermm} ${ref:+"${ref}"} -printf '\n' -quit \
- | read -r _
+ for path; do
+ # The first branch addresses a conformance issue whereby
+ # [ existent -nt nonexistent ] is incorrectly false. As of
+ # August 2024, busybox ash, dash, FreeBSD sh and NetBSD sh are
+ # known to be non-conforming in this respect.
+ if [ ! "${ref}" ] && [ -e "${path}" ]; then
+ return
+ elif [ "${path}" -nt "${ref}" ]; then
+ return
+ elif [ -d "${path}" ] && is_older_than "${ref}" "${path}"/*; then
+ return
+ fi
+ done
+ false
}
#
next reply other threads:[~2024-08-11 10:11 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-11 10:11 Sam James [this message]
-- strict thread matches above, loose matches on Subject: below --
2025-10-14 12:59 [gentoo-commits] proj/gentoo-functions:master commit in: functions/, / Sam James
2024-08-11 10:11 Sam James
2024-08-02 23:14 Sam James
2024-06-25 4:06 Sam James
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1723371063.6cf0940b8d336eb35a970af2ffc819f55e3ab429.sam@gentoo \
--to=sam@gentoo.org \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox