← Files CrowdStrike Falcon FusionARCHIVED FILE
scripts/python-detect.sh
6.03 KB · Oct 2, 2026 · 00:31 UTC
#!/usr/bin/env bash
# python-detect.sh - Cross-platform Python discovery for the fusion-skills plugin.
# Source this file, then call find_compatible_python (echoes a python binary) or
# _pd_set_venv_bins <venv_dir> (sets VENV_PYTHON_BIN / VENV_PIP_BIN).
#
# Requires Python 3.13+ (fusion-skills' stated floor). 3.14+ is allowed.
# Supports: macOS (Homebrew, pyenv), Linux (apt, deadsnakes, pyenv, SCL), Windows (msys/cygwin).
# Version floor — fusion-skills requires Python 3.13+.
PYTHON_MIN_MAJOR=3
PYTHON_MIN_MINOR=13
PYTHON_MAX_MINOR=14 # 3.14+ should work
_PD_RED='\033[0;31m'
_PD_GREEN='\033[0;32m'
_PD_YELLOW='\033[1;33m'
_PD_NC='\033[0m'
_pd_detect_platform() {
case "$(uname -s)" in
Darwin) echo "macos" ;;
Linux)
if [[ -f /etc/redhat-release ]]; then echo "rhel"
elif [[ -f /etc/debian_version ]]; then echo "debian"
else echo "linux"; fi ;;
*) echo "unknown" ;;
esac
}
# Parse "major.minor" from a python binary, or empty on failure.
_pd_get_python_version() {
local python_bin="$1" version_output
if [[ ! -x "$python_bin" ]] && ! command -v "$python_bin" &>/dev/null; then
return 1
fi
version_output=$("$python_bin" --version 2>&1) || return 1
echo "$version_output" | sed -n 's/^Python \([0-9]*\.[0-9]*\).*/\1/p'
}
# True if version is within the supported range (>= 3.13, <= 3.14).
_pd_is_version_supported() {
local version="$1" major minor
major=$(echo "$version" | cut -d. -f1)
minor=$(echo "$version" | cut -d. -f2)
[[ "$major" -eq "$PYTHON_MIN_MAJOR" ]] || return 1
[[ "$minor" -ge "$PYTHON_MIN_MINOR" ]] && [[ "$minor" -le "$PYTHON_MAX_MINOR" ]]
}
_pd_get_search_paths() {
local platform="$1"
case "$platform" in
macos)
echo "/opt/homebrew/bin"
echo "/usr/local/bin"
echo "/opt/homebrew/opt/python@3.13/bin"
echo "/usr/local/opt/python@3.13/bin"
echo "$HOME/.pyenv/shims"
echo "/usr/bin"
;;
debian)
echo "/usr/bin"
echo "$HOME/.pyenv/shims"
echo "/usr/local/bin"
;;
rhel)
echo "/opt/rh/rh-python313/root/usr/bin"
echo "/usr/bin"
echo "$HOME/.pyenv/shims"
;;
*)
echo "/usr/bin"
echo "/usr/local/bin"
echo "$HOME/.pyenv/shims"
;;
esac
}
# Set VENV_PYTHON_BIN and VENV_PIP_BIN for the given venv directory (OS-aware).
_pd_set_venv_bins() {
local venv_dir="$1"
if [[ "$OSTYPE" == msys* || "$OSTYPE" == cygwin* ]]; then
# shellcheck disable=SC2034
VENV_PYTHON_BIN="${venv_dir}/Scripts/python.exe"
# shellcheck disable=SC2034
VENV_PIP_BIN="${venv_dir}/Scripts/pip.exe"
else
# shellcheck disable=SC2034
VENV_PYTHON_BIN="${venv_dir}/bin/python3"
# shellcheck disable=SC2034
VENV_PIP_BIN="${venv_dir}/bin/pip"
fi
}
# Echo a path to a compatible Python binary, or return 1 if none found.
find_compatible_python() {
local python_bin="" version="" platform
platform=$(_pd_detect_platform)
# 1. Explicit override.
if [[ -n "${PYTHON_BIN:-}" ]]; then
if [[ -x "$PYTHON_BIN" ]] || command -v "$PYTHON_BIN" &>/dev/null; then
version=$(_pd_get_python_version "$PYTHON_BIN")
if _pd_is_version_supported "$version"; then echo "$PYTHON_BIN"; return 0; fi
echo -e "${_PD_YELLOW}WARNING: PYTHON_BIN ($PYTHON_BIN) is Python $version, not 3.${PYTHON_MIN_MINOR}+${_PD_NC}" >&2
else
echo -e "${_PD_YELLOW}WARNING: PYTHON_BIN ($PYTHON_BIN) not found${_PD_NC}" >&2
fi
fi
# 2. System python3, if in range.
if command -v python3 &>/dev/null; then
version=$(_pd_get_python_version "python3")
if _pd_is_version_supported "$version"; then echo "python3"; return 0; fi
fi
# 3. Versioned binaries in PATH.
for bin in "python3.14" "python3.13"; do
if command -v "$bin" &>/dev/null; then
version=$(_pd_get_python_version "$bin")
if _pd_is_version_supported "$version"; then echo "$bin"; return 0; fi
fi
done
# 4. Platform-specific paths.
local search_path
while IFS= read -r search_path; do
[[ -d "$search_path" ]] || continue
for bin in "python3.14" "python3.13" "python3"; do
local full_path="$search_path/$bin"
if [[ -x "$full_path" ]]; then
version=$(_pd_get_python_version "$full_path")
if _pd_is_version_supported "$version"; then echo "$full_path"; return 0; fi
fi
done
done < <(_pd_get_search_paths "$platform")
return 1
}
# Platform-specific install instructions when no compatible Python is found.
print_install_instructions() {
local platform
platform=$(_pd_detect_platform)
echo ""
echo -e "${_PD_RED}ERROR: No compatible Python found (fusion-skills requires 3.${PYTHON_MIN_MINOR}+)${_PD_NC}"
echo ""
case "$platform" in
macos)
echo "Install Python 3.13 on macOS:"
echo " brew install python@3.13"
echo " # or: brew install uv && uv python install 3.13"
;;
debian)
echo "Install Python 3.13 on Ubuntu/Debian:"
echo " sudo add-apt-repository ppa:deadsnakes/ppa && sudo apt update"
echo " sudo apt install python3.13 python3.13-venv"
echo " # or: curl -LsSf https://astral.sh/uv/install.sh | sh && uv python install 3.13"
;;
rhel)
echo "Install Python 3.13 on RHEL/CentOS:"
echo " sudo dnf install python3.13"
echo " # or: curl -LsSf https://astral.sh/uv/install.sh | sh && uv python install 3.13"
;;
*)
echo "Install Python 3.13 (cross-platform):"
echo " curl -LsSf https://astral.sh/uv/install.sh | sh && uv python install 3.13"
;;
esac
echo ""
echo "Then restart your terminal, or set PYTHON_BIN=/path/to/python3.13 and retry."
echo ""
}
SHA-256: 76b6c605f012c4ad39b593e3d17457a934e6bb28709d00dafd8e0a97444506a3