# Deploy Operations 平台抽象架構

## 概述

deploy_operations 模組實作平台無關的部署編排層，支援多種部署類型：

- Network Deployment（SSH-based）：適用 Linux SBC
- Direct Flashing（JTAG/USB-based）：適用 MCU 平台

## 架構圖

```mermaid
flowchart TD
    DN["deploy_node"]
    DF["deploy_firmware()<br/>(路由函數)"]

    subgraph "Network Deployment"
        DPN["_deploy_network()"]
        CNC["_check_network_connectivity()"]
        DPS_SSH["deploy.py (SSH)"]
    end

    subgraph "Direct Flashing"
        DPF["_deploy_direct_flashing()"]
        DPS_STM32["deploy.py (ST-LINK)"]
    end

    DN --> DF
    DF -->|"sdk_type: am62x"| DPN
    DF -->|"sdk_type: stm32"| DPF

    DPN --> CNC --> DPS_SSH
    DPF --> DPS_STM32
```

## 平台支援

### 已實作（v0.5.0 - Network Deployment）

| SDK Type | Deploy Type        | 工具    | 實作狀態    | 版本   | 說明                    |
| -------- | ------------------ | ------- | ----------- | ------ | ----------------------- |
| am62x    | Network Deployment | SSH/SCP | ✅ 完整實作 | v0.5.0 | 透過 \_deploy_network() |

**功能特性**：

- ✅ 網路連接性檢查（SSH port 檢測）
- ✅ SCP 二進制檔案傳輸
- ✅ SSH 遠端執行（foreground/background 模式）
- ✅ 遠端日誌路徑配置與自動記憶

## 設計原則

1. **工具無關**：deploy_operations 不知道 SSH、ST-LINK、esptool 的存在
2. **平台特定邏輯在 deploy.py**：所有工具調用都在 deploy.py 中
3. **環境檢測共用**：SSH 檢測可跨 Linux 平台共用
4. **KISS**：不提前設計未使用的功能

---

## 詳細設計

### Data Classes

#### NetworkDeployConfig

SSH-based 網路部署配置（適用 Linux SBC）：

```python
@dataclass
class NetworkDeployConfig:
    board_ip: str                    # 開發板 IP 位址
    board_user: str = "root"         # SSH 登入使用者
    deploy_path: str = "/home/root"  # 部署路徑
    ssh_options: str = "..."         # SSH 連線選項
    binary_args: str = ""            # 執行參數
    execution_mode: Literal["foreground", "background"] = "foreground"
    remote_log_enabled: bool = False
    remote_log_path: str = "/dev/null"
```

#### DeployResult

部署結果：

```python
@dataclass
class DeployResult:
    success: bool       # 是否成功
    message: str        # 結果訊息
    binary_name: str    # 二進制檔案名稱
    pid: int | None     # 進程 PID (background mode)
```

### 核心函數

| 函數                                 | 說明                                        |
| ------------------------------------ | ------------------------------------------- |
| `deploy_firmware()`                  | 主入口點：路由函數，根據 SDK type 分流      |
| `_get_deploy_type()`                 | SDK type → Deploy type 映射                 |
| `_deploy_network()`                  | Network Deployment 實作（SSH-based）        |
| `_deploy_direct_flashing()`          | Direct Flashing 骨架（NotImplementedError） |
| `_check_network_connectivity()`      | SSH port 連接性檢查                         |
| `find_binary()`                      | 在 build 目錄找到可執行檔                   |
| `_extract_binary_name_from_output()` | 從 stderr 提取 binary name                  |
| `_extract_pid_from_output()`         | 從 stderr 提取 PID（background mode）       |

### 部署流程

#### Network Deployment 完整流程

```
1. deploy_firmware() 接收 ProjectConfig
   └─ _get_deploy_type(sdk_type) → "network"
       └─ _deploy_network(build_dir, config, binary_args)
           ├─ 建立 NetworkDeployConfig
           ├─ _check_network_connectivity() 檢查 SSH port
           ├─ 定位 .fwauto/deploy/deploy.py
           ├─ 組裝 CLI 參數
           ├─ subprocess.run() 執行 deploy.py
           └─ 解析結果（binary_name, PID）
```

#### deploy.py 內部流程（平台相關）

```
1. 檢查網路連接性（Ping + SSH port 檢測）
2. 尋找二進制檔案
3. 部署到開發板（SCP 上傳）
4. 遠端執行
   ├─ foreground mode: 同步執行
   └─ background mode: nohup 背景執行
```

### 執行模式

**Foreground Mode**：

- 同步執行，阻塞等待程式結束
- 適用於短生命週期程式
- 可直接取得 exit code

**Background Mode**：

- 使用 nohup 背景執行
- 適用於長時間運行的服務
- 返回進程 PID 供追蹤

### 遠端日誌功能

**remote_log_path 參數**：

- 支援透過 CLI 或環境變數配置
- 預設格式：`{{ app_name }}_{{ date }}.log`
- 例如：`led_2025-11-24.log`
- Deploy 成功後自動儲存日誌路徑到 `.fwauto/config.toml`
- Log 命令自動檢測上次的日誌路徑，無需重複輸入
- 使用者可透過 `--log-path` 參數覆蓋

**與 UART log 的區別**：

- App log：應用程式層級日誌（stdout/stderr）
- UART log：硬體串口輸出（kernel, bootloader）

### 錯誤處理

**ConnectionError**：

- SSH port 無法連接
- 提供詳細的故障排除建議

**部署/執行錯誤**：

- SCP 上傳失敗 → RuntimeError
- SSH 執行失敗 → RuntimeError
- 超時控制：deploy.py 120 秒

### 使用方式

#### 從 deploy_node 調用

```python
from deploy_operations import deploy_firmware

result = deploy_firmware(
    build_dir=project_root_path / "build",
    config=config,  # ProjectConfig directly
    binary_args=binary_args,
)
```

#### 獨立 CLI 使用

```bash
# 基本使用（使用預設的 execution_mode 和 ssh_options）
python3 .fwauto/deploy/deploy.py \
    --board-ip 192.168.50.169 \
    --binary-args "--verbose" \
    --remote-log-path "/home/root/.fwauto/logs/app.log"

# 如需使用非預設值，可透過環境變數設定
export EXECUTION_MODE=foreground
export SSH_OPTIONS="-o ConnectTimeout=10"
python3 .fwauto/deploy/deploy.py --board-ip 192.168.50.169
```
