# 機能設計書 70-コマンド実行

## 概要

本ドキュメントは、Juliaにおけるシェルコマンド実行とプロセス管理機能（`run` / `read` / `success` / `pipeline` / `Cmd`）の設計と実装を記述するものである。

### 本機能の処理概要

本機能は、外部プロセスの起動・実行・入出力制御を提供する。バッククォートリテラルによるコマンド構築、`run` による実行、パイプラインの構築、プロセスの入出力リダイレクションを含む。

**業務上の目的・背景**：Julia プログラムから OS のコマンドやツールを呼び出す需要は非常に多い。シェルスクリプトの代替としてJuliaを使用する場合や、外部ツール（Git, Docker, make 等）との連携、データパイプラインの構築において不可欠な機能である。Julia のコマンドリテラル（バッククォート）はシェルの補間攻撃を防ぐ安全な構文を提供する。

**機能の利用シーン**：REPL のシェルモード（`;` キー）、CI/CD スクリプトでの外部ツール実行、データ処理パイプラインの構築、テストスイートでの外部プロセス起動、ビルドスクリプトでの make/cmake 呼び出しに利用される。

**主要な処理内容**：
1. `Cmd` 型によるコマンドの表現（引数、環境変数、作業ディレクトリ等）
2. `run(cmd)` による同期的なコマンド実行
3. `open(cmd)` による非同期プロセス起動と I/O ストリーム取得
4. `read(cmd)` によるコマンド出力の一括取得
5. `pipeline(a, b)` によるプロセスパイプラインの構築
6. `|>` / `|` / `&` 演算子によるパイプライン構文
7. I/O リダイレクション（ファイル、パイプ、devnull）

**関連システム・外部連携**：libuv によるプロセス管理、OS のプロセス生成 API（`posix_spawn` / `CreateProcess`）。

**権限による制御**：UID/GID 設定オプション（Unix のみ）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | シェルモード（shell>） | 主画面 | run/Cmdによるシェルコマンド実行。Base.repl_cmd()でコマンドをパース・実行する |
| 2 | Juliaプロンプト（julia>） | 遷移先画面 | 「;」キー押下によるシェルモードへの遷移。Base.repl_cmd()を介したOSコマンド実行を開始 |

## 機能種別

外部プロセス管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cmd | `AbstractCmd` | Yes | 実行するコマンド | exec が空でないこと |
| wait | `Bool` | No | 同期的に待機するか | デフォルト `true` |
| ignorestatus | `Bool` | No | 非ゼロ終了コードを無視するか | デフォルト `false` |
| detach | `Bool` | No | 新しいプロセスグループで実行するか | デフォルト `false` |
| env | `Dict` or `Vector{String}` | No | 環境変数の設定 | - |
| dir | `AbstractString` | No | 作業ディレクトリ | - |
| uid | `UInt32` | No | ユーザーID（Unix） | - |
| gid | `UInt32` | No | グループID（Unix） | - |

### 入力データソース

バッククォートリテラル、ユーザーコードからの直接呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| process | `Process` or `ProcessChain` | プロセスオブジェクト |
| output | `Vector{UInt8}` | `read(cmd)` の場合のコマンド出力 |
| success | `Bool` | 終了コードが0かどうか |

### 出力先

プロセスの stdout/stderr はリダイレクション設定に従う

## 処理フロー

### 処理シーケンス

```
1. Cmd オブジェクト構築
   └─ バッククォートリテラルからコマンド引数・オプションを構築
2. I/O セットアップ
   └─ stdin/stdout/stderr のリダイレクション設定（パイプ、ファイル、devnull）
3. プロセス生成
   └─ _spawn_primitive で libuv の jl_spawn を呼び出し
4. プロセス監視
   └─ wait=true の場合は終了を待機
5. 終了コード確認
   └─ success() で終了コードを確認、非ゼロなら ProcessFailedException
6. リソース解放
   └─ プロセスハンドルの解放、I/O ストリームのクローズ
```

### フローチャート

```mermaid
flowchart TD
    A["`cmd args`"] --> B[Cmd 構築]
    B --> C{実行方法}
    C -->|run| D[spawn + wait + 終了コード確認]
    C -->|open| E[spawn + IO ストリーム返却]
    C -->|read| F[spawn + stdout 読み取り + 終了コード確認]
    D --> G{ignorestatus?}
    G -->|Yes| H[Process 返却]
    G -->|No| I{exitcode == 0?}
    I -->|Yes| H
    I -->|No| J[ProcessFailedException]
    E --> K[Process/ProcessChain 返却]
    F --> L["Vector{UInt8} 返却"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-70-01 | 終了コード確認 | `run` はデフォルトで非ゼロ終了コードを例外にする | `wait=true` かつ `ignorestatus=false` の場合 |
| BR-70-02 | パイプライン失敗 | パイプラインでは全プロセスの終了コードが確認される | pipeline 使用時 |
| BR-70-03 | 空コマンド禁止 | 空の exec 配列の Cmd は spawn できない | Cmd.exec が空の場合 |
| BR-70-04 | I/O デフォルト | `wait=false` の場合、I/O は devnull にリダイレクトされる | `run(cmd; wait=false)` |
| BR-70-05 | detach | `detach=true` の場合、プロセスは新しいプロセスグループで実行され Julia の Ctrl-C が転送されない | detach 指定時 |

### 計算ロジック

該当なし。

## データベース操作仕様

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ProcessFailedException | プロセスが非ゼロ終了コードで終了した場合 | ignorestatus を使用、またはコマンドを修正 |
| - | ArgumentError | 空の Cmd を spawn しようとした場合 | 有効なコマンドを指定 |
| - | UVError | プロセスの spawn に失敗した場合（コマンドが見つからない等） | コマンドパスを確認 |
| - | ArgumentError | open のモードが不正な場合 | "r", "w", "r+", "w+" を使用 |

### リトライ仕様

該当なし。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- プロセス起動は libuv を介して非同期に行われる
- パイプライン接続時のデータコピーは最小限

## セキュリティ考慮事項

- Julia のコマンドリテラルはシェルを介さないため、シェルインジェクションのリスクがない
- uid/gid の設定は Unix のみで、適切な権限が必要
- 環境変数の設定により、子プロセスに機密情報が漏洩する可能性がある

## 備考

- Julia のコマンドリテラル（バッククォート）はシェルのそれとは異なり、各引数が個別にクォートされる
- `windows_verbatim=true` は Windows でコマンドライン引数のクォートを無効化する
- `setcpuaffinity` で CPU アフィニティを設定可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | cmd.jl | `base/cmd.jl` | `AbstractCmd` 抽象型（3行目）: 全コマンド型の基底 |
| 1-2 | cmd.jl | `base/cmd.jl` | `Cmd` 構造体（13-40行目）: exec(引数配列), ignorestatus, flags, env, dir, cpus, uid, gid を保持 |
| 1-3 | cmd.jl | `base/cmd.jl` | `OrCmds` / `ErrOrCmds` / `AndCmds` 構造体（103-119行目）: パイプライン構造 |
| 1-4 | process.jl | `base/process.jl` | `Process` 構造体（3-21行目）: cmd, handle, in, out, err, syncd, exitcode, termsignal, exitnotify を保持 |
| 1-5 | process.jl | `base/process.jl` | `ProcessChain` 構造体（27-35行目）: 複数プロセスの管理 |

**読解のコツ**: `Cmd` は不変データ構造で、コマンドの設定を保持する。`Process` は可変で、実行中のプロセスの状態を管理する。パイプラインは `OrCmds`（stdout→stdin）、`ErrOrCmds`（stderr→stdin）、`AndCmds`（逐次実行）のツリー構造で表現される。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | process.jl | `base/process.jl` | `run(cmds, args...; wait)` 関数（522-547行目）: コマンド実行の公開API |
| 2-2 | process.jl | `base/process.jl` | `read(cmd)` 関数（487-492行目）: コマンド出力の一括取得 |
| 2-3 | process.jl | `base/process.jl` | `open(cmds, ...; read, write)` 関数（405-426行目）: 非同期プロセス起動 |

**主要処理フロー**:
1. **522-525行目**: `wait=true` の場合、`_spawn` + `success` チェック
2. **527-528行目**: `wait=false` の場合、I/O を devnull にして `_spawn`
3. **487-492行目**: `read` は `open(cmd, "r")` → `read(procs.out)` → `success` チェック

#### Step 3: プロセス生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | process.jl | `base/process.jl` | `_spawn_primitive` 関数（100-150行目）: libuv を介したプロセス生成の低レベル実装 |
| 3-2 | process.jl | `base/process.jl` | `_spawn(cmd::Cmd, ...)` 関数（163-166行目）: 単一コマンドの spawn |
| 3-3 | process.jl | `base/process.jl` | `_spawn(cmds::OrCmds, ...)` 関数（193-205行目）: パイプライン接続の spawn |

**主要処理フロー**:
- **100-101行目**: `eventloop()` でイベントループ取得、CPU マスク処理
- **125-139行目**: `ccall(:jl_spawn, ...)` で libuv のプロセス生成呼び出し
- **140-149行目**: 成功なら `Process` オブジェクト構築、失敗なら `UVError`
- **194-203行目**: `link_pipe` でパイプ作成、左右のプロセスを接続

#### Step 4: I/O セットアップを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | process.jl | `base/process.jl` | `setup_stdios` 関数（236-251行目）: stdio の初期化 |
| 4-2 | process.jl | `base/process.jl` | `setup_stdio` 各オーバーロード（253-334行目）: PipeEndpoint, Pipe, IOStream, FileRedirect, IO 等の型別セットアップ |

#### Step 5: プロセス終了処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | process.jl | `base/process.jl` | `uv_return_spawn` コールバック（63-79行目）: プロセス終了時の処理 |
| 5-2 | process.jl | `base/process.jl` | `uvfinalize` 関数（49-60行目）: libuv ハンドルの解放 |

### プログラム呼び出し階層図

```
run(`cmd args`)
    │
    ├─ _spawn(cmd, spawn_opts_inherit())
    │      │
    │      ├─ setup_stdios()                  # I/O 初期化
    │      │      └─ setup_stdio()            # 型別セットアップ
    │      │
    │      └─ _spawn_primitive(file, cmd, stdios)
    │             │
    │             ├─ eventloop()              # libuv イベントループ
    │             ├─ ccall(:jl_spawn, ...)    # プロセス生成
    │             └─ Process(cmd, handle, syncd)
    │
    ├─ success(ps)                            # 終了コード確認
    │      └─ wait(ps)
    │             └─ uv_return_spawn()        # コールバック
    │
    └─ pipeline_error(ps)                     # エラー時例外
```

### データフロー図

```
[入力]                        [処理]                       [出力]

コマンドリテラル `ls -l` ──▶ Cmd 構築
                               │
環境変数 env ──────────▶      │
作業ディレクトリ dir ───▶     │
                               ▼
                          _spawn_primitive()
                               │
                               ├──▶ stdin  ◀── ユーザー入力/パイプ/ファイル
                               ├──▶ stdout ──▶ ユーザー出力/パイプ/ファイル
                               └──▶ stderr ──▶ ユーザー出力/ファイル
                               │
                               ▼
                          Process オブジェクト
                               │
                               ▼
                          exitcode / termsignal
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cmd.jl | `base/cmd.jl` | ソース | Cmd / OrCmds / AndCmds 等のデータ構造定義 |
| process.jl | `base/process.jl` | ソース | プロセス生成・管理・I/Oセットアップの実装 |
| pipe.jl | `base/pipe.jl` | ソース | パイプのセットアップ |
| stream.jl | `base/stream.jl` | ソース | ストリーム操作の基盤 |
| libuv.jl | `base/libuv.jl` | ソース | libuv イベントループとの連携 |
