montana/Монтана-Протокол/Код/scripts/install-local-mac.sh

205 lines
9.0 KiB
Bash
Raw Normal View History

#!/bin/bash
# Montana node — локальная установка на macOS из текущей рабочей копии.
# БЕЗ клонирования с GitHub. Все процессы автоматически по очереди:
# build → install → identity → launchd → start → Finder.
#
# Использование (одна команда в Terminal.app):
# bash "/Users/kh./Python/Ничто/Монтана/Русский/Протокол/Код/scripts/install-local-mac.sh"
#
# Узел запускается через launchd (Mac-аналог systemd) — переживает logout
# и перезагрузку Mac, автоматически рестартует при падении.
set -euo pipefail
SCRIPT_PATH="${BASH_SOURCE[0]}"
if [ -L "$SCRIPT_PATH" ]; then
SCRIPT_PATH="$(readlink "$SCRIPT_PATH")"
fi
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
SOURCE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# Локация установки: задаётся env var INSTALL_DIR либо default ~/Applications/Montana.
# Пример с custom путём:
# INSTALL_DIR=/path/to/Montana_Node bash scripts/install-local-mac.sh
INSTALL_DIR="${INSTALL_DIR:-$HOME/Applications/Montana}"
DATA_DIR="$INSTALL_DIR/data"
LOGS_DIR="$DATA_DIR/logs"
LAUNCH_AGENTS_DIR="$HOME/Library/LaunchAgents"
PLIST_PATH="$LAUNCH_AGENTS_DIR/org.montana.node.plist"
SERVICE_LABEL="org.montana.node"
log() { printf '\033[1;32m[install-local-mac]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[install-local-mac]\033[0m %s\n' "$*" >&2; }
die() { printf '\033[1;31m[install-local-mac] ОШИБКА:\033[0m %s\n' "$*" >&2; exit 1; }
# --- Шаг 1: проверка платформы ---
[ "$(uname -s)" = "Darwin" ] || die "это installer для macOS"
log "macOS $(sw_vers -productVersion 2>/dev/null || echo unknown), arch $(uname -m)"
log "источник: $SOURCE_DIR"
# --- Шаг 2: проверка структуры репозитория ---
[ -f "$SOURCE_DIR/Cargo.toml" ] || die "не найден Cargo.toml в $SOURCE_DIR"
[ -d "$SOURCE_DIR/crates/montana-node" ] || die "не найден crates/montana-node"
[ -d "$SOURCE_DIR/dist/macOS/Montana" ] || die "не найден dist/macOS/Montana"
# --- Шаг 3: Xcode Command Line Tools ---
if ! xcode-select -p >/dev/null 2>&1; then
warn "Xcode Command Line Tools не установлены."
warn "Откроется системный диалог — нажмите «Установить» и дождитесь завершения."
xcode-select --install || true
die "после установки CLT повторите команду"
fi
# --- Шаг 4: Rust toolchain ---
if ! command -v cargo >/dev/null 2>&1; then
log "устанавливаю Rust toolchain (rustup minimal)..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
sh -s -- -y --default-toolchain stable --profile minimal --no-modify-path
fi
export PATH="$HOME/.cargo/bin:$PATH"
command -v cargo >/dev/null 2>&1 || die "cargo не доступен после rustup install"
log "Rust: $(cargo --version)"
# --- Шаг 5: остановить running узел (если есть) ---
if launchctl list "$SERVICE_LABEL" >/dev/null 2>&1; then
log "останавливаю текущий узел перед обновлением бинаря..."
launchctl unload "$PLIST_PATH" 2>/dev/null || true
fi
# --- Шаг 6: build ---
cd "$SOURCE_DIR"
log "собираю montana-node release..."
cargo build --release -p montana-node 2>&1 | tail -3
# --- Шаг 7: install в ~/Applications/Montana/ ---
mkdir -p "$INSTALL_DIR" "$DATA_DIR" "$LOGS_DIR" "$LAUNCH_AGENTS_DIR"
cp -f "$SOURCE_DIR/target/release/montana-node" "$INSTALL_DIR/montana-node"
chmod 0755 "$INSTALL_DIR/montana-node"
cp -f "$SOURCE_DIR/dist/macOS/Montana"/*.command "$INSTALL_DIR/" 2>/dev/null || true
cp -f "$SOURCE_DIR/dist/macOS/Montana/README.txt" "$INSTALL_DIR/"
chmod 0755 "$INSTALL_DIR"/*.command 2>/dev/null || true
xattr -dr com.apple.quarantine "$INSTALL_DIR" 2>/dev/null || true
# --- Шаг 8: identity (init если нет) ---
if [ ! -f "$DATA_DIR/identity.bin" ]; then
log ""
log "================================================================"
log " ГЕНЕРАЦИЯ IDENTITY"
log "================================================================"
log ""
log "Сейчас сгенерируются 24 слова мнемоники + ключи ML-DSA-65 +"
log "ML-KEM-768. ВНИМАНИЕ: запишите 24 слова в надёжное место."
log "Потеряете → потеряете доступ к узлу и всем заработанным Ɉ."
log ""
"$INSTALL_DIR/montana-node" init --data-dir "$DATA_DIR"
log ""
log "================================================================"
if [ -t 0 ] || [ -e /dev/tty ]; then
read -r -p "Нажмите Enter ПОСЛЕ того как записали 24 слова в надёжное место..." _ </dev/tty || true
fi
else
log "identity уже существует ($DATA_DIR/identity.bin) — пропускаю генерацию"
fi
# --- Шаг 9: установка LaunchAgent plist ---
log "устанавливаю LaunchAgent $PLIST_PATH..."
cat > "$PLIST_PATH" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>$SERVICE_LABEL</string>
<key>ProgramArguments</key>
<array>
<string>$INSTALL_DIR/montana-node</string>
<string>start</string>
<string>--data-dir</string>
<string>$DATA_DIR</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
<key>Crashed</key>
<true/>
</dict>
<key>ThrottleInterval</key>
<integer>10</integer>
<key>StandardOutPath</key>
<string>$LOGS_DIR/montana.log</string>
<key>StandardErrorPath</key>
<string>$LOGS_DIR/montana.err.log</string>
<key>WorkingDirectory</key>
<string>$DATA_DIR</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin</string>
</dict>
<key>ProcessType</key>
<string>Standard</string>
<key>LowPriorityIO</key>
<false/>
<key>Nice</key>
<integer>0</integer>
</dict>
</plist>
PLIST
chmod 0644 "$PLIST_PATH"
# --- Шаг 10: запуск через launchd ---
log "запускаю узел через launchctl load..."
launchctl load -w "$PLIST_PATH"
# Дать узлу секунду чтобы стартовать
sleep 2
# --- Шаг 11: проверка что запустилось ---
if launchctl list "$SERVICE_LABEL" 2>/dev/null | grep -q "$SERVICE_LABEL"; then
STATE=$(launchctl list "$SERVICE_LABEL" | awk '/PID/ {print $3}')
if [ -n "$STATE" ] && [ "$STATE" != "-" ]; then
log "узел запущен, PID=$STATE"
else
warn "узел загружен в launchd, но PID не получен. Проверьте логи: $LOGS_DIR/montana.err.log"
fi
else
die "не удалось загрузить службу $SERVICE_LABEL"
fi
# --- Шаг 12: финальный отчёт + Finder ---
log ""
log "================================================================"
log " УСТАНОВКА ЗАВЕРШЕНА. УЗЕЛ ЗАПУЩЕН."
log "================================================================"
log ""
log "Бинарь: $INSTALL_DIR/montana-node"
log "Данные: $DATA_DIR"
log "Логи: $LOGS_DIR/montana.log (stdout) + montana.err.log (stderr)"
log "Service: $SERVICE_LABEL (launchd, RunAtLoad=true, restart on crash)"
log ""
log "Узел работает в фоне через launchd:"
log " • переживает закрытие Terminal.app"
log " • переживает logout"
log " • переживает перезагрузку Mac (auto-start при логине)"
log " • перезапускается автоматически при падении"
log ""
log "Полезные команды:"
log " tail -f \"$LOGS_DIR/montana.log\" # логи realtime"
log " $INSTALL_DIR/montana-node status --data-dir \"$DATA_DIR\" # phase + balance"
log " launchctl unload \"$PLIST_PATH\" # остановить узел"
log " launchctl load -w \"$PLIST_PATH\" # запустить заново"
log ""
log "Жизненный цикл узла (canonical apply_proposal pipeline byte-exact spec):"
log " Phase 1: Bootstrap → CandidateVdf (~10 часов VDF до vdf_chain_length ≥ τ₂)"
log " Phase 2: CandidateVdf → Registered (apply_noderegistrations_batch)"
log " Phase 3: Registered → Active (apply_selection_event на W % 336 == 0)"
log " Phase 4: Active (13 Ɉ per окно через apply_proposal)"
log ""
log "Для повторной установки (после изменений в коде):"
log " bash \"$SCRIPT_PATH\""
log ""
open "$INSTALL_DIR" 2>/dev/null || warn "не удалось открыть Finder автоматически"