- Add utils.sh with cross-platform timeout functions for macOS compatibility - Fix sf-logs-tail to use portable_timeout instead of GNU timeout command - Fix test-all-wrappers.sh to use portable_timeout_seconds for testing - Update README.md with macOS compatibility documentation The timeout command is not available by default on macOS, causing sf-logs-tail and test scripts to fail. The new utils.sh provides fallback timeout functionality that works on Linux, macOS with/without GNU coreutils, maintaining exit code 124 compatibility.
108 lines
2.9 KiB
Bash
Executable File
108 lines
2.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Shared utilities for SF CLI wrapper scripts
|
|
# Provides cross-platform compatibility helpers
|
|
|
|
# Portable timeout function for macOS and Linux compatibility
|
|
# Usage: portable_timeout MINUTES command [args...]
|
|
# Returns exit code 124 on timeout (matching GNU timeout behavior)
|
|
portable_timeout() {
|
|
local duration_minutes="$1"
|
|
shift
|
|
|
|
# Try GNU timeout first (available on Linux by default)
|
|
if command -v timeout >/dev/null 2>&1; then
|
|
timeout "${duration_minutes}m" "$@"
|
|
return $?
|
|
fi
|
|
|
|
# Try gtimeout (macOS with GNU coreutils installed)
|
|
if command -v gtimeout >/dev/null 2>&1; then
|
|
gtimeout "${duration_minutes}m" "$@"
|
|
return $?
|
|
fi
|
|
|
|
# Fallback implementation for macOS without GNU coreutils
|
|
# Start the command in background
|
|
"$@" &
|
|
local cmd_pid=$!
|
|
|
|
# Start timeout watcher in background
|
|
(
|
|
sleep "${duration_minutes}m"
|
|
kill "$cmd_pid" 2>/dev/null
|
|
) &
|
|
local watcher_pid=$!
|
|
|
|
# Wait for the command to finish
|
|
wait "$cmd_pid" 2>/dev/null
|
|
local cmd_exit_code=$?
|
|
|
|
# Clean up watcher if command finished normally
|
|
kill "$watcher_pid" 2>/dev/null
|
|
wait "$watcher_pid" 2>/dev/null
|
|
|
|
# Check if command was killed (timeout occurred)
|
|
if ! kill -0 "$cmd_pid" 2>/dev/null; then
|
|
# Command no longer exists, check if it was our timeout
|
|
if [[ $cmd_exit_code -ne 0 ]]; then
|
|
# Command may have been killed by timeout, return 124
|
|
return 124
|
|
fi
|
|
fi
|
|
|
|
return $cmd_exit_code
|
|
}
|
|
|
|
# Portable timeout function for seconds (for tests that need shorter timeouts)
|
|
# Usage: portable_timeout_seconds SECONDS command [args...]
|
|
portable_timeout_seconds() {
|
|
local duration_seconds="$1"
|
|
shift
|
|
|
|
# Try GNU timeout first
|
|
if command -v timeout >/dev/null 2>&1; then
|
|
timeout "${duration_seconds}s" "$@"
|
|
return $?
|
|
fi
|
|
|
|
# Try gtimeout
|
|
if command -v gtimeout >/dev/null 2>&1; then
|
|
gtimeout "${duration_seconds}s" "$@"
|
|
return $?
|
|
fi
|
|
|
|
# Fallback implementation
|
|
"$@" &
|
|
local cmd_pid=$!
|
|
|
|
# Start timeout watcher in background
|
|
(
|
|
sleep "$duration_seconds"
|
|
kill "$cmd_pid" 2>/dev/null
|
|
) &
|
|
local watcher_pid=$!
|
|
|
|
# Wait for the command to finish
|
|
wait "$cmd_pid" 2>/dev/null
|
|
local cmd_exit_code=$?
|
|
|
|
# Clean up watcher if command finished normally
|
|
kill "$watcher_pid" 2>/dev/null
|
|
wait "$watcher_pid" 2>/dev/null
|
|
|
|
# Check if command was killed (timeout occurred)
|
|
if ! kill -0 "$cmd_pid" 2>/dev/null; then
|
|
if [[ $cmd_exit_code -ne 0 ]]; then
|
|
return 124
|
|
fi
|
|
fi
|
|
|
|
return $cmd_exit_code
|
|
}
|
|
|
|
# Function to get the directory of the calling script
|
|
# Usage: SCRIPT_DIR=$(get_script_dir)
|
|
get_script_dir() {
|
|
cd "$(dirname "${BASH_SOURCE[1]}")" && pwd
|
|
}
|