summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKerin Millar <kfm@plushkava.net>2024-06-02 21:57:49 +0100
committerKerin Millar <kfm@plushkava.net>2024-06-12 08:06:42 +0100
commit6b1ea77cf5befc19999701a73c64eb39f0dafacd (patch)
treea8f592809c5ef1f52787e460149097af6e043b49
parentAdd the srandom() function (diff)
downloadgentoo-functions-6b1ea77cf5befc19999701a73c64eb39f0dafacd.tar.gz
gentoo-functions-6b1ea77cf5befc19999701a73c64eb39f0dafacd.tar.bz2
gentoo-functions-6b1ea77cf5befc19999701a73c64eb39f0dafacd.zip
Add the oldest() and newest() functions
It compares potentially existing pathnames, printing the oldest and newest among them by modification time, respectively. $ . /lib/gentoo/functions.sh $ newest /etc/* /etc/environment.d $ printf '%s\0' /etc/* | newest /etc/environment.d Support for pathnames containing <newline> characters may be added once read -d becomes broadly supported. https://austingroupbugs.net/view.php?id=245 Signed-off-by: Kerin Millar <kfm@plushkava.net>
-rw-r--r--functions.sh74
-rwxr-xr-xtest-functions39
2 files changed, 93 insertions, 20 deletions
diff --git a/functions.sh b/functions.sh
index 0c35b2d..1548bd0 100644
--- a/functions.sh
+++ b/functions.sh
@@ -1,6 +1,6 @@
# Copyright 1999-2023 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
-# shellcheck shell=sh disable=3043
+# shellcheck shell=sh disable=2209,3043
# This file contains a series of function declarations followed by some
# initialisation code. Functions intended for internal use shall be prefixed
@@ -401,7 +401,7 @@ is_int()
#
is_older_than()
{
- local ref has_gfind
+ local ref
if [ "$#" -eq 0 ]; then
warn "is_older_than: too few arguments (got $#, expected at least 1)"
@@ -412,26 +412,39 @@ is_older_than()
ref=
fi
shift
+ { test "$#" -gt 0 && printf '%s\0' "$@"; } \
+ | "${genfun_bin_find}" -L -files0-from - ${ref:+-newermm} ${ref:+"${ref}"} -printf '\n' -quit \
+ | read -r _
+}
- # Check whether GNU find is installed by the name of "gfind". So as to
- # avoid repeated PATH lookups, run the hash builtin in the present
- # shell, prior to forking.
- hash gfind 2>/dev/null; has_gfind=$(( $? == 0 ))
+#
+# 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.
+#
+newest()
+{
+ _select_by_mtime -r "$@"
+}
- 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 _
+#
+# 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.
+#
+oldest()
+{
+ _select_by_mtime -- "$@"
}
#
@@ -727,6 +740,24 @@ _print_args()
}
#
+# See the definitions of oldest() and newest().
+#
+_select_by_mtime() {
+ local sort_opt
+
+ sort_opt=$1
+ shift
+ if [ "$#" -ge 0 ]; then
+ printf '%s\0' "$@"
+ else
+ cat
+ fi \
+ | "${genfun_bin_find}" -files0-from - -maxdepth 0 ! -path "*${genfun_newline}*" -printf '%T+ %p\n' \
+ | sort "${sort_opt}" \
+ | { IFS= read -r line && printf '%s\n' "${line#* }"; }
+}
+
+#
# Determines whether the terminal on STDIN is able to report its dimensions.
# Upon success, the number of columns shall be stored in genfun_cols.
#
@@ -805,6 +836,9 @@ if [ "${BASH}" ]; then
genfun_bin_true=$(type -P true)
fi
+# Store the name of the GNU find binary. Some platforms may have it as "gfind".
+hash gfind 2>/dev/null && genfun_bin_find=gfind || genfun_bin_find=find
+
# Determine whether the use of color is to be wilfully avoided.
if [ -n "${NO_COLOR}" ]; then
# See https://no-color.org/.
diff --git a/test-functions b/test-functions
index 0c4a222..400ddb2 100755
--- a/test-functions
+++ b/test-functions
@@ -418,6 +418,44 @@ test_srandom() {
iterate_tests 2 "$@"
}
+test_newest() {
+ set -- \
+ ge 1 non-existent non-existent \
+ ge 1 N/A N/A \
+ \
+ eq 0 newer/file N/A \
+ eq 0 newer/file newer/file \
+ eq 0 newer/file non-existent \
+ eq 0 newer/file older/file \
+ eq 0 non-existent newer/file \
+ eq 0 older/file newer/file \
+ \
+ eq 0 older/file N/A \
+ eq 0 older/file older/file \
+ eq 0 older/file non-existent \
+ ge 1 newer/file older/file \
+ eq 0 non-existent older/file \
+ ge 1 older/file newer/file
+
+ row=0
+
+ callback() {
+ shift
+ test_description="newest $(_print_args "$@")"
+ row=$(( row + 1 ))
+ true |
+ if [ "${row}" -le 2 ]; then
+ newest "$@"
+ elif [ "${row}" -le 8 ]; then
+ test "$(newest "$@")" = "newer/file"
+ else
+ test "$(newest "$@")" = "older/file"
+ fi
+ }
+
+ iterate_tests 4 "$@"
+}
+
iterate_tests() {
slice_width=$1
shift
@@ -479,6 +517,7 @@ test_yesno || rc=1
test_die || rc=1
test_edo || rc=1
test_srandom || rc=1
+test_newest || rc=1
cleanup_tmpdir