#!/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 }