feat: add macOS support to installer and docs
- install.sh: detect Darwin, use Homebrew for packages/Node, Docker Desktop hint - install.sh: portable realpath and bash 3-compatible confirm() for macOS - docs/installer-support.md: add macOS (Darwin) / Homebrew to support matrix - README.md: document supported platforms (Linux and macOS), Docker Desktop/Homebrew - ci.yml: add installer-macos job (macos-latest, bash -n install.sh) Made-with: Cursor
This commit is contained in:
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@@ -184,6 +184,17 @@ jobs:
|
|||||||
if [ -f .install-logs/frontend.pid ]; then kill "$(cat .install-logs/frontend.pid)" || true; fi
|
if [ -f .install-logs/frontend.pid ]; then kill "$(cat .install-logs/frontend.pid)" || true; fi
|
||||||
docker compose -f compose.yml --env-file .env down -v --remove-orphans || true
|
docker compose -f compose.yml --env-file .env down -v --remove-orphans || true
|
||||||
|
|
||||||
|
installer-macos:
|
||||||
|
runs-on: macos-latest
|
||||||
|
needs: [check]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Validate installer shell syntax (macOS)
|
||||||
|
run: bash -n install.sh
|
||||||
|
|
||||||
e2e:
|
e2e:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [check]
|
needs: [check]
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ Installer support matrix: [`docs/installer-support.md`](./docs/installer-support
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
|
- **Supported platforms**: Linux and macOS. On macOS, Docker mode requires [Docker Desktop](https://www.docker.com/products/docker-desktop/); local mode requires [Homebrew](https://brew.sh) and Node.js 22+.
|
||||||
- Docker Engine
|
- Docker Engine
|
||||||
- Docker Compose v2 (`docker compose`)
|
- Docker Compose v2 (`docker compose`)
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ This document defines current support status for `./install.sh`.
|
|||||||
| openSUSE | `zypper` | **Scaffolded** | Detection + actionable commands present; auto-install path is TODO. |
|
| openSUSE | `zypper` | **Scaffolded** | Detection + actionable commands present; auto-install path is TODO. |
|
||||||
| Arch Linux | `pacman` | **Scaffolded** | Detection + actionable commands present; auto-install path is TODO. |
|
| Arch Linux | `pacman` | **Scaffolded** | Detection + actionable commands present; auto-install path is TODO. |
|
||||||
| Other Linux distros | unknown | **Unsupported** | Installer exits with package-manager guidance requirement. |
|
| Other Linux distros | unknown | **Unsupported** | Installer exits with package-manager guidance requirement. |
|
||||||
|
| macOS (Darwin) | Homebrew | **Stable** | Docker mode requires Docker Desktop. Local mode uses Homebrew for curl, git, make, openssl, Node.js. |
|
||||||
|
|
||||||
## Guard rails
|
## Guard rails
|
||||||
|
|
||||||
|
|||||||
80
install.sh
80
install.sh
@@ -7,6 +7,7 @@ REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
|||||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}"
|
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||||
LOG_DIR="$STATE_DIR/openclaw-mission-control-install"
|
LOG_DIR="$STATE_DIR/openclaw-mission-control-install"
|
||||||
|
|
||||||
|
PLATFORM=""
|
||||||
LINUX_DISTRO=""
|
LINUX_DISTRO=""
|
||||||
PKG_MANAGER=""
|
PKG_MANAGER=""
|
||||||
PKG_UPDATED=0
|
PKG_UPDATED=0
|
||||||
@@ -209,6 +210,9 @@ install_command_hint() {
|
|||||||
pacman)
|
pacman)
|
||||||
printf 'sudo pacman -Sy --noconfirm %s' "${packages[*]}"
|
printf 'sudo pacman -Sy --noconfirm %s' "${packages[*]}"
|
||||||
;;
|
;;
|
||||||
|
brew)
|
||||||
|
printf 'brew install %s' "${packages[*]}"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
printf 'install packages manually: %s' "${packages[*]}"
|
printf 'install packages manually: %s' "${packages[*]}"
|
||||||
;;
|
;;
|
||||||
@@ -218,10 +222,21 @@ install_command_hint() {
|
|||||||
detect_platform() {
|
detect_platform() {
|
||||||
local uname_s
|
local uname_s
|
||||||
uname_s="$(uname -s)"
|
uname_s="$(uname -s)"
|
||||||
if [[ "$uname_s" != "Linux" ]]; then
|
if [[ "$uname_s" == "Darwin" ]]; then
|
||||||
die "Unsupported platform: $uname_s. Linux is required."
|
PLATFORM="darwin"
|
||||||
|
PKG_MANAGER="brew"
|
||||||
|
if ! command_exists brew; then
|
||||||
|
die "Homebrew is required on macOS. Install from https://brew.sh, then re-run this script."
|
||||||
|
fi
|
||||||
|
info "Detected platform: darwin (macOS), package manager: Homebrew"
|
||||||
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "$uname_s" != "Linux" ]]; then
|
||||||
|
die "Unsupported platform: $uname_s. Linux and macOS (Darwin) are supported."
|
||||||
|
fi
|
||||||
|
|
||||||
|
PLATFORM="linux"
|
||||||
if [[ ! -r /etc/os-release ]]; then
|
if [[ ! -r /etc/os-release ]]; then
|
||||||
die "Cannot detect Linux distribution (/etc/os-release missing)."
|
die "Cannot detect Linux distribution (/etc/os-release missing)."
|
||||||
fi
|
fi
|
||||||
@@ -268,6 +283,9 @@ install_packages() {
|
|||||||
fi
|
fi
|
||||||
as_root apt-get install -y "${packages[@]}"
|
as_root apt-get install -y "${packages[@]}"
|
||||||
;;
|
;;
|
||||||
|
brew)
|
||||||
|
brew install "${packages[@]}"
|
||||||
|
;;
|
||||||
dnf|yum|zypper|pacman)
|
dnf|yum|zypper|pacman)
|
||||||
die "Automatic package install is not implemented yet for '$PKG_MANAGER'. Run: $(install_command_hint "$PKG_MANAGER" "${packages[@]}")"
|
die "Automatic package install is not implemented yet for '$PKG_MANAGER'. Run: $(install_command_hint "$PKG_MANAGER" "${packages[@]}")"
|
||||||
;;
|
;;
|
||||||
@@ -351,7 +369,7 @@ confirm() {
|
|||||||
input="${input:-n}"
|
input="${input:-n}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "${input,,}" in
|
case "$(printf '%s' "$input" | tr '[:upper:]' '[:lower:]')" in
|
||||||
y|yes)
|
y|yes)
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
@@ -376,9 +394,33 @@ generate_token() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Portable relative path: print path of $1 relative to $2 (both absolute).
|
||||||
|
relative_to() {
|
||||||
|
local target="$1"
|
||||||
|
local base="$2"
|
||||||
|
local rel
|
||||||
|
if [[ -z "$base" || -z "$target" ]]; then
|
||||||
|
printf '%s' "$target"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
base="${base%/}"
|
||||||
|
target="${target%/}"
|
||||||
|
if [[ "$target" == "$base" ]]; then
|
||||||
|
printf ''
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
rel="${target#$base/}"
|
||||||
|
if [[ "$rel" != "$target" ]]; then
|
||||||
|
printf '%s' "$rel"
|
||||||
|
else
|
||||||
|
printf '%s' "$target"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
ensure_file_from_example() {
|
ensure_file_from_example() {
|
||||||
local target_file="$1"
|
local target_file="$1"
|
||||||
local example_file="$2"
|
local example_file="$2"
|
||||||
|
local display_path
|
||||||
|
|
||||||
if [[ -f "$target_file" ]]; then
|
if [[ -f "$target_file" ]]; then
|
||||||
return
|
return
|
||||||
@@ -389,7 +431,12 @@ ensure_file_from_example() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cp "$example_file" "$target_file"
|
cp "$example_file" "$target_file"
|
||||||
info "Created $(realpath --relative-to="$REPO_ROOT" "$target_file" 2>/dev/null || printf '%s' "$target_file")"
|
if command_exists realpath && realpath --relative-to="$REPO_ROOT" "$target_file" >/dev/null 2>&1; then
|
||||||
|
display_path="$(realpath --relative-to="$REPO_ROOT" "$target_file" 2>/dev/null)"
|
||||||
|
else
|
||||||
|
display_path="$(relative_to "$(cd -- "$(dirname -- "$target_file")" && pwd -P)/$(basename "$target_file")" "$REPO_ROOT")"
|
||||||
|
fi
|
||||||
|
info "Created $display_path"
|
||||||
}
|
}
|
||||||
|
|
||||||
upsert_env_value() {
|
upsert_env_value() {
|
||||||
@@ -474,8 +521,23 @@ ensure_nodejs() {
|
|||||||
die "Cannot continue without Node.js >= 22."
|
die "Cannot continue without Node.js >= 22."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "$PLATFORM" == "darwin" ]]; then
|
||||||
|
brew install node
|
||||||
|
if ! command_exists node || ! command_exists npm; then
|
||||||
|
die 'Node.js/npm installation failed. Ensure Homebrew bin is in PATH (e.g. eval "$(brew shellenv)").'
|
||||||
|
fi
|
||||||
|
hash -r || true
|
||||||
|
node_version="$(node -v || true)"
|
||||||
|
node_major="${node_version#v}"
|
||||||
|
node_major="${node_major%%.*}"
|
||||||
|
if [[ ! "$node_major" =~ ^[0-9]+$ ]] || ((node_major < 22)); then
|
||||||
|
die "Detected Node.js $node_version. Node.js >= 22 is required. Install with: brew install node@22 and link or adjust PATH."
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$PKG_MANAGER" != "apt" ]]; then
|
if [[ "$PKG_MANAGER" != "apt" ]]; then
|
||||||
die "Node.js auto-install is currently implemented for apt-based distros only. Install Node.js >= 22 manually, then rerun installer. Suggested command: $(install_command_hint "$PKG_MANAGER" nodejs npm)"
|
die "Node.js auto-install is currently implemented for apt-based distros and macOS only. Install Node.js >= 22 manually, then rerun installer. Suggested command: $(install_command_hint "$PKG_MANAGER" nodejs npm)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install_packages ca-certificates curl gnupg
|
install_packages ca-certificates curl gnupg
|
||||||
@@ -505,6 +567,10 @@ ensure_docker() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "$PLATFORM" == "darwin" ]]; then
|
||||||
|
die "Docker and Docker Compose v2 are required on macOS. Install Docker Desktop from https://www.docker.com/products/docker-desktop/, start it, then re-run this script."
|
||||||
|
fi
|
||||||
|
|
||||||
info "Docker and Docker Compose v2 are required."
|
info "Docker and Docker Compose v2 are required."
|
||||||
if ! confirm "Install Docker tooling now?" "y"; then
|
if ! confirm "Install Docker tooling now?" "y"; then
|
||||||
die "Cannot continue without Docker."
|
die "Cannot continue without Docker."
|
||||||
@@ -620,7 +686,11 @@ main() {
|
|||||||
parse_args "$@"
|
parse_args "$@"
|
||||||
|
|
||||||
detect_platform
|
detect_platform
|
||||||
|
if [[ "$PLATFORM" == "darwin" ]]; then
|
||||||
|
info "Platform detected: darwin (macOS)"
|
||||||
|
else
|
||||||
info "Platform detected: linux ($LINUX_DISTRO)"
|
info "Platform detected: linux ($LINUX_DISTRO)"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -n "$FORCE_MODE" ]]; then
|
if [[ -n "$FORCE_MODE" ]]; then
|
||||||
deployment_mode="$FORCE_MODE"
|
deployment_mode="$FORCE_MODE"
|
||||||
|
|||||||
Reference in New Issue
Block a user