summaryrefslogtreecommitdiff
path: root/src/lib/compat.source.sh
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-25 12:35:12 +0300
committerPaul Buetow <paul@buetow.org>2026-06-25 12:35:12 +0300
commit12b2733dab6da12a2a6cf1d27d69bc7d143f5dfc (patch)
tree077adb3e5efc5e3a0bf9f1a5b24c38ebb264deb5 /src/lib/compat.source.sh
parent964901d672d8e12baf4ac0eb29821d670ae15eb8 (diff)
Add runtime GNU-tool guard; document Linux-only platform support
shuriken shells out to GNU-only features of the standard Unix tools (find -printf, stat -c, cp -a, sort -R). Add require_gnu_tools in a new src/lib/compat.source.sh, sourced early and invoked from main() before any action runs. On invocation it feature-probes each tool in a throwaway temp dir; if any probe fails it prints a clear error naming the offending tool and exits 1, so non-GNU (macOS/BSD) environments fail fast instead of producing broken output. README gains a Platform compatibility section and the requirements line now mentions GNU coreutils/findutils. Tests cover the find and stat rejection paths; the shared test helper that builds a coreutils-without-imagemagick PATH now includes cp and stat (which the guard probes).
Diffstat (limited to 'src/lib/compat.source.sh')
-rw-r--r--src/lib/compat.source.sh61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/lib/compat.source.sh b/src/lib/compat.source.sh
new file mode 100644
index 0000000..718c7ed
--- /dev/null
+++ b/src/lib/compat.source.sh
@@ -0,0 +1,61 @@
+# Runtime compatibility guard: verify the standard Unix tools shuriken shells
+# out to are the GNU variants. shuriken relies on GNU-only extensions -- find
+# -printf, stat -c, cp -a, and sort -R -- that the BSD tools shipped with macOS
+# and BSD systems do not provide (see the "Platform compatibility" section of
+# README.md). require_gnu_tools probes each feature in a throwaway temp dir and
+# exits with a clear error naming the offending tool if any probe fails, so the
+# check runs before any real work begins (it is called from main, after CLI
+# parsing and before run_action).
+#
+# The probes intentionally exercise the exact GNU-only behavior the codebase
+# depends on rather than parsing --help text (which is unstable across
+# implementations), so a tool that lacks the feature fails the probe regardless
+# of its version string.
+
+require_gnu_tools() {
+ local probe_dir
+ local probe_out
+ local failed=''
+
+ probe_dir=$(mktemp -d 2>/dev/null) || return 1
+ # shellcheck disable=SC2064 # expand probe_dir now, clean up on any return
+ trap "rm -rf '$probe_dir'" RETURN
+
+ # GNU find supports the -printf action; BSD/macOS find does not.
+ probe_out=$(find "$probe_dir" -maxdepth 0 -printf '%f\n' 2>/dev/null) \
+ && [ -n "$probe_out" ] || failed='find (missing the -printf action)'
+
+ # GNU stat uses -c FORMAT; BSD/macOS stat uses -f and rejects -c.
+ if [ -z "$failed" ]; then
+ printf 'probe\n' > "$probe_dir/file"
+ probe_out=$(stat -c '%s' "$probe_dir/file" 2>/dev/null) \
+ && [[ "$probe_out" =~ ^[0-9]+$ ]] \
+ || failed='stat (missing the -c option)'
+ fi
+
+ # GNU cp supports the -a archive flag; minimal/older BSD cp variants lack it.
+ if [ -z "$failed" ]; then
+ mkdir "$probe_dir/src"
+ printf 'x\n' > "$probe_dir/src/inner"
+ if ! cp -a "$probe_dir/src" "$probe_dir/dest" 2>/dev/null \
+ || [ ! -f "$probe_dir/dest/inner" ]; then
+ failed='cp (missing the -a option)'
+ fi
+ fi
+
+ # GNU sort supports -R (random shuffle); BSD sort lacks it.
+ if [ -z "$failed" ]; then
+ probe_out=$(printf 'a\nb\nc\n' | sort -R 2>/dev/null) \
+ && [ -n "$probe_out" ] || failed='sort (missing the -R option)'
+ fi
+
+ if [ -n "$failed" ]; then
+ printf 'ERROR: shuriken requires the GNU versions of the standard Unix\n' >&2
+ printf 'ERROR: tools (GNU coreutils/findutils). Non-GNU or unsupported: %s\n' \
+ "$failed" >&2
+ printf 'ERROR: shuriken is Linux-only and will not run on macOS or BSD.\n' >&2
+ return 1
+ fi
+
+ return 0
+}