Fix macOS compatibility: Add portable timeout helper
- 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.
This commit is contained in:
10
README.md
10
README.md
@@ -508,6 +508,16 @@ sf-deploy -to DEMO-ORG \
|
||||
- **Flexible Input**: Supports absolute and repository-relative paths
|
||||
- **Command Echo**: Shows the actual `sf` command being executed for transparency
|
||||
- **Focused Workflows**: Deploy, validate, retrieve, test, run Apex, manage orgs, data import/export, and tail logs
|
||||
- **macOS Compatibility**: Full compatibility with macOS using portable timeout implementation
|
||||
|
||||
## macOS Compatibility
|
||||
|
||||
The wrapper scripts include a `utils.sh` helper that provides cross-platform timeout functionality. This ensures that scripts requiring timed execution (like `sf-logs-tail`) work correctly on macOS without requiring GNU coreutils.
|
||||
|
||||
The timeout helper automatically detects and uses:
|
||||
1. `timeout` command (Linux/GNU systems)
|
||||
2. `gtimeout` command (macOS with GNU coreutils)
|
||||
3. Built-in fallback implementation (pure Bash for macOS)
|
||||
|
||||
## Tips
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
# Debug logs tail wrapper for Salesforce CLI
|
||||
# Provides real-time debug log monitoring with filtering and formatting
|
||||
|
||||
# Source utilities for cross-platform compatibility
|
||||
source "$(dirname "$0")/utils.sh"
|
||||
|
||||
# Color codes for output formatting
|
||||
readonly RED='\033[0;31m'
|
||||
readonly GREEN='\033[0;32m'
|
||||
@@ -291,7 +294,7 @@ if [[ "$VERBOSE" == true ]]; then
|
||||
fi
|
||||
|
||||
# Start the log tailing with timeout
|
||||
timeout "${DURATION}m" sf "${SF_ARGS[@]}" 2>/dev/null | while IFS= read -r line; do
|
||||
portable_timeout "$DURATION" sf "${SF_ARGS[@]}" 2>/dev/null | while IFS= read -r line; do
|
||||
if should_show_log_entry "$line" "$FILTER_PATTERN" "$APEX_ONLY"; then
|
||||
format_log_entry "$line" "$SHOW_COLORS" "$VERBOSE"
|
||||
fi
|
||||
|
||||
@@ -4,6 +4,9 @@ set -euo pipefail
|
||||
# Comprehensive Test Suite for SF CLI Wrapper Scripts
|
||||
# Tests all scenarios with 100% coverage using PWC-TEAM-DEV org
|
||||
|
||||
# Source utilities for cross-platform compatibility
|
||||
source "$(dirname "$0")/utils.sh"
|
||||
|
||||
readonly TEST_ORG="PWC-TEAM-DEV"
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly RED='\033[0;31m'
|
||||
@@ -182,7 +185,7 @@ echo ""
|
||||
echo -e "${BLUE}=== Testing sf-logs-tail (quick test) ===${NC}"
|
||||
|
||||
# Test logs tail for a very short duration
|
||||
run_test "sf-logs-tail short duration" "timeout 5s ./sf-logs-tail -to $TEST_ORG --duration 1 || true"
|
||||
run_test "sf-logs-tail short duration" "portable_timeout_seconds 5 ./sf-logs-tail -to $TEST_ORG --duration 1 || true"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}=== Test Results Summary ===${NC}"
|
||||
|
||||
107
utils.sh
Executable file
107
utils.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/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
|
||||
}
|
||||
Reference in New Issue
Block a user