# 機能設計書 95-Gstatプラグイン

## 概要

本ドキュメントはNushellのGstatプラグイン（nu_plugin_gstat）について記述する。Gitリポジトリの状態を表示するプラグインの設計を定義する。

### 本機能の処理概要

Gstatプラグインは、指定されたパスのGitリポジトリの状態（ステージング状況、変更ファイル数、ahead/behind、ブランチ情報等）を取得し、構造化データとして返す。プロンプトのカスタマイズやスクリプトでのGit状態チェックに活用できる。

**業務上の目的・背景**：開発者はGitリポジトリの状態を頻繁に確認する必要がある。Gstatプラグインは、git statusの情報を構造化データとして提供することで、シェルプロンプトへの組み込みや、バッチ処理での状態確認を容易にする。

**機能の利用シーン**：
- シェルプロンプトにGitステータスを表示する際
- 複数リポジトリの状態を一括確認する際
- CI/CDスクリプトでリポジトリ状態をチェックする際
- コミット前の変更確認を自動化する際

**主要な処理内容**：
1. リポジトリの検出（Repository::discover）
2. ファイルステータスの集計（ステージ済み、変更、未追跡等）
3. ブランチ情報の取得（ローカル、リモート）
4. ahead/behind情報の計算
5. stash数のカウント
6. タグ情報の取得（オプション）

**関連システム・外部連携**：git2クレート（libgit2のRustバインディング）

**権限による制御**：リポジトリディレクトリへの読み取り権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はCLIコマンドとして提供され、特定の画面とは関連しない |

## 機能種別

情報取得 / 状態表示

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | String | No | リポジトリのパス（デフォルト: カレントディレクトリ） | 存在するディレクトリ |
| --calculate-tag | Switch | No | タグ情報を計算する | - |

### 入力データソース

- パイプライン入力: パスの指定（オプション）
- カレントディレクトリ: デフォルトのリポジトリパス

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| idx_added_staged | Int | ステージ済み追加ファイル数 |
| idx_modified_staged | Int | ステージ済み変更ファイル数 |
| idx_deleted_staged | Int | ステージ済み削除ファイル数 |
| idx_renamed | Int | リネームされたファイル数 |
| idx_type_changed | Int | 型が変更されたファイル数 |
| wt_untracked | Int | 未追跡ファイル数 |
| wt_modified | Int | 変更ファイル数（未ステージ） |
| wt_deleted | Int | 削除ファイル数（未ステージ） |
| wt_type_changed | Int | 型変更ファイル数（未ステージ） |
| wt_renamed | Int | リネームファイル数（未ステージ） |
| ignored | Int | 無視されたファイル数 |
| conflicts | Int | コンフリクトファイル数 |
| ahead | Int | リモートより先行しているコミット数 |
| behind | Int | リモートより遅れているコミット数 |
| stashes | Int | stash数 |
| repo_name | String | リポジトリ名 |
| tag | String | 現在のタグ（--calculate-tag使用時） |
| branch | String | 現在のブランチ名 |
| remote | String | 上流ブランチ名 |
| state | String | リポジトリ状態（clean, merge, rebase等） |

### 出力先

- パイプライン出力: レコード形式

## 処理フロー

### 処理シーケンス

```
gstat:
1. パスの解決
   └─ 入力パスまたはカレントディレクトリ
2. リポジトリの検出
   └─ Repository::discover()
3. ステータス取得
   └─ repo.statuses() でファイル状態を取得
4. 各カテゴリの集計
   └─ INDEX_*, WT_*, IGNORED, CONFLICTED をカウント
5. ブランチ情報取得
   └─ repo.head() からブランチ名取得
6. 上流ブランチ情報
   └─ find_branch(), upstream() で取得
7. ahead/behind計算
   └─ graph_ahead_behind() で計算
8. stash数カウント
   └─ repo.stash_foreach() でカウント
9. タグ取得（オプション）
   └─ describe() でタグ情報取得
10. 結果をレコードとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[gstat] --> B[パス解決]
    B --> C{リポジトリ検出}
    C -->|失敗| D[空のステータス返却]
    C -->|成功| E[ステータス取得]
    E --> F[ファイル状態集計]
    F --> G[ブランチ情報取得]
    G --> H[ahead/behind計算]
    H --> I[stash数カウント]
    I --> J{--calculate-tag?}
    J -->|Yes| K[タグ情報取得]
    J -->|No| L[タグ="no_tag"]
    K --> M[レコード返却]
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-95-01 | 非リポジトリ時のデフォルト | Gitリポジトリでない場合は-1とデフォルト値を返却 | リポジトリ検出失敗時 |
| BR-95-02 | デタッチドHEAD | デタッチドHEADの場合はコミットID先頭8文字 | HEADがブランチでない場合 |
| BR-95-03 | 空リポジトリ | 空リポジトリの場合はブランチ名"master" | repo.is_empty()がtrue |
| BR-95-04 | タグ計算オプション | パフォーマンスのためタグ計算はオプション | --calculate-tag指定時のみ |

### 計算ロジック

ステータスフラグの判定:
- `INDEX_NEW`: ステージ済み新規ファイル
- `INDEX_MODIFIED`: ステージ済み変更ファイル
- `INDEX_DELETED`: ステージ済み削除ファイル
- `INDEX_RENAMED`: ステージ済みリネーム
- `INDEX_TYPECHANGE`: ステージ済み型変更
- `WT_NEW`: 未追跡ファイル
- `WT_MODIFIED`: 変更ファイル
- `WT_DELETED`: 削除ファイル
- `WT_TYPECHANGE`: 型変更
- `WT_RENAMED`: リネーム
- `IGNORED`: 無視ファイル
- `CONFLICTED`: コンフリクトファイル

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

本機能はデータベースを使用しない。Gitリポジトリのデータを直接読み取る。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| LabeledError | LabeledError | パスが存在しない | 有効なパスを指定 |
| LabeledError | LabeledError | ディレクトリでない | ディレクトリパスを指定 |
| (デフォルト値) | - | Gitリポジトリでない | エラーでなくデフォルト値を返却 |

### リトライ仕様

特になし。

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

該当なし（読み取り専用処理）。

## パフォーマンス要件

- 即座に処理実行
- --calculate-tagはdescribe操作のため追加コストあり
- 大規模リポジトリでもstatusオプションで最適化

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

- リポジトリディレクトリへの読み取り権限が必要
- リモートへの通信は行わない（ローカル情報のみ）

## 備考

- git2クレートはlibgit2のRustバインディング
- ステータスオプションでuntracked_dirsの再帰的取得を有効化
- リネーム検出はhead-to-indexで有効

---

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

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

### 推奨読解順序

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

Statsデータ構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | gstat.rs | `crates/nu_plugin_gstat/src/gstat.rs` | Stats構造体の定義（172-215行目） |

**読解のコツ**: Stats構造体のフィールドがそのまま出力レコードのカラムになる。各フィールドの意味を把握することが重要。

#### Step 2: メイン処理を理解する

gstatコマンドの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | gstat.rs | `crates/nu_plugin_gstat/src/gstat.rs` | GStat::gstatメソッド（19-140行目） |
| 2-2 | nu/mod.rs | `crates/nu_plugin_gstat/src/nu/mod.rs` | コマンド定義とプラグイン登録 |

**主要処理フロー（gstat.rs）**:
1. **31-41行目**: パスの解決とデフォルト値設定
2. **43-70行目**: パスの検証とリポジトリ検出
3. **83-87行目**: リポジトリ検出、失敗時は空ステータス
4. **89-104行目**: リポジトリ名とタグの取得
5. **115-139行目**: レコードの構築と返却

#### Step 3: Stats計算を理解する

ファイルステータス集計の処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | gstat.rs | `crates/nu_plugin_gstat/src/gstat.rs` | Stats::new（217-282行目） |

**主要処理フロー（Stats::new）**:
1. **219-223行目**: Stats初期化とブランチ読み込み
2. **225-230行目**: StatusOptionsの設定
3. **232-274行目**: ステータスフラグのカウント
4. **276-280行目**: stash数のカウント

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

```
GStatPlugin::run()
    │
    └─ GStat::gstat()
           │
           ├─ Path解決
           │      └─ カレントディレクトリ or 入力パス
           │
           ├─ Repository::discover()
           │      └─ Gitリポジトリを検出
           │
           ├─ Stats::new()
           │      ├─ read_branch()
           │      │      └─ repo.head()
           │      ├─ read_upstream_name()
           │      │      └─ branch.upstream()
           │      ├─ read_ahead_behind()
           │      │      └─ repo.graph_ahead_behind()
           │      ├─ repo.statuses()
           │      │      └─ ファイルステータス集計
           │      └─ repo.stash_foreach()
           │             └─ stash数カウント
           │
           └─ repo.describe()（オプション）
                  └─ タグ情報取得
```

### データフロー図

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

パス(String)  ─────────▶  Repository::discover  ─────▶  Stats
または                     │
カレントディレクトリ         ├─ repo.statuses()
                           ├─ repo.head()
                           ├─ branch.upstream()
                           └─ repo.graph_ahead_behind()
                                    │
                                    ▼
                           Record {
                             idx_added_staged: Int,
                             wt_modified: Int,
                             branch: String,
                             ahead: Int,
                             behind: Int,
                             ...
                           }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lib.rs | `crates/nu_plugin_gstat/src/lib.rs` | ソース | モジュールエクスポート |
| gstat.rs | `crates/nu_plugin_gstat/src/gstat.rs` | ソース | GStat構造体とStatsの実装 |
| nu/mod.rs | `crates/nu_plugin_gstat/src/nu/mod.rs` | ソース | プラグインコマンド定義 |
| main.rs | `crates/nu_plugin_gstat/src/main.rs` | ソース | プラグインエントリーポイント |
