diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-25 12:35:12 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-25 12:35:12 +0300 |
| commit | 12b2733dab6da12a2a6cf1d27d69bc7d143f5dfc (patch) | |
| tree | 077adb3e5efc5e3a0bf9f1a5b24c38ebb264deb5 /src | |
| parent | 964901d672d8e12baf4ac0eb29821d670ae15eb8 (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')
| -rw-r--r-- | src/lib/compat.source.sh | 61 | ||||
| -rwxr-xr-x | src/shuriken.sh | 8 |
2 files changed, 69 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 +} diff --git a/src/shuriken.sh b/src/shuriken.sh index 16d846f..d9f7d1b 100755 --- a/src/shuriken.sh +++ b/src/shuriken.sh @@ -93,6 +93,8 @@ declare -r SHURIKEN_SOURCE_DIR # SHURIKEN_LIB_SOURCES_BEGIN # shellcheck source=src/lib/logging.source.sh source "$SHURIKEN_SOURCE_DIR/lib/logging.source.sh" +# shellcheck source=src/lib/compat.source.sh +source "$SHURIKEN_SOURCE_DIR/lib/compat.source.sh" # shellcheck source=src/lib/bootstrap.source.sh source "$SHURIKEN_SOURCE_DIR/lib/bootstrap.source.sh" # shellcheck source=src/lib/paths.source.sh @@ -167,6 +169,12 @@ main() { return "$status" fi + require_gnu_tools + status=$? + if (( status != 0 )); then + return "$status" + fi + run_action status=$? if (( status != 0 )); then |
