# バッチ設計書 4-check_for_upgrade.sh

## 概要

本ドキュメントは、Oh My Zshの更新有無を定期的にチェックするシェルスクリプト`check_for_upgrade.sh`のバッチ設計書である。このスクリプトは更新モード（prompt/auto/reminder/background-alpha/disabled）に応じて処理を分岐し、適切なタイミングで更新を実行または通知する。

### 本バッチの処理概要

このバッチはOh My Zshの自動更新チェック機能を提供する。Zshの起動時にソースとして読み込まれ、設定された更新頻度に基づいて更新の必要性を判定し、更新モードに応じた処理を実行する。

**業務上の目的・背景**：Oh My Zshは継続的に更新されるフレームワークであり、ユーザーが手動で更新チェックを行うことは煩雑である。このスクリプトは、シェル起動時に自動的に更新チェックを行い、ユーザーの好みに応じた方法（自動更新、確認プロンプト、リマインダー表示）で更新を促すことで、フレームワークを最新状態に保つ。

**バッチの実行タイミング**：Zshシェル起動時に自動的にソースとして読み込まれる。更新チェックは設定された頻度（デフォルト13日）ごとに実行される。

**主要な処理内容**：
1. .zsh-updateファイルの移行（旧パスから$ZSH_CACHE_DIRへ）
2. 更新モードの取得（zstyle設定または旧スタイル設定）
3. 更新可否の判定（権限、TTY、Git可用性）
4. 最終更新日時の確認
5. 更新間隔の判定
6. GitHub APIを使用したリモート更新の有無確認
7. 更新モードに応じた処理実行：
   - prompt: ユーザーに確認後に更新
   - auto: 自動更新
   - reminder: リマインダー表示のみ
   - background-alpha: バックグラウンドで更新
   - disabled: 何もしない
8. 更新結果の記録

**前後の処理との関連**：このスクリプトは`upgrade.sh`（No.3）を呼び出して実際の更新を実行する。oh-my-zsh.shから起動時にソースとして読み込まれる。

**影響範囲**：$ZSH_CACHE_DIR/.zsh-update（更新状態ファイル）、$ZSH/log/update.lock（ロックディレクトリ）

## バッチ種別

定期チェック処理 / 自動更新管理

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | Zshシェル起動時（更新チェックは設定間隔ごと） |
| 実行時刻 | シェル起動時 |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | Zshシェル起動 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| Oh My Zshインストール済み | $ZSHディレクトリが存在すること |
| Zsh起動時に読み込み | oh-my-zsh.shからソースとして読み込まれること |

### 実行可否判定

以下のいずれかの条件に該当する場合、更新チェックをスキップ：
1. update_mode = disabled
2. $ZSHディレクトリへの書き込み権限がない（!-w）
3. $ZSHディレクトリのオーナーでない（!-O）
4. TTYが接続されていない（!-t 1）かつPOWERLEVEL9K_INSTANT_PROMPTがoff
5. gitコマンドが利用不可
6. $ZSHがGitリポジトリでない

## 入力仕様

### 入力パラメータ

該当なし（ソースとして読み込まれるため引数は使用しない）

### zstyle設定

| 設定項目 | 値 | デフォルト | 説明 |
|---------|-----|-----------|------|
| :omz:update mode | prompt/auto/reminder/background-alpha/disabled | prompt | 更新モード |
| :omz:update frequency | 数値（日数） | 13 | 更新チェック間隔 |
| :omz:update verbose | default/minimal/silent | default | 冗長性モード |

### 環境変数

| 環境変数名 | 必須 | デフォルト値 | 説明 |
|-----------|-----|-------------|------|
| DISABLE_UPDATE_PROMPT | No | false | trueの場合、mode=auto |
| DISABLE_AUTO_UPDATE | No | false | trueの場合、mode=disabled |
| UPDATE_ZSH_DAYS | No | 13 | 更新チェック間隔（旧スタイル） |
| ZSH_CACHE_DIR | Yes | - | キャッシュディレクトリ |
| POWERLEVEL9K_INSTANT_PROMPT | No | off | Powerlevel9kインスタントプロンプト設定 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| ${ZSH_CACHE_DIR}/.zsh-update | テキスト | 最終更新日時情報（LAST_EPOCH） |
| GitHub API | HTTPS | リモートHEADの取得 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| ${ZSH_CACHE_DIR}/.zsh-update | テキスト | 更新状態（LAST_EPOCH, EXIT_STATUS, ERROR） |
| $ZSH/log/update.lock | ディレクトリ | ロック用ディレクトリ |
| 標準出力 | テキスト | 更新プロンプト、リマインダーメッセージ |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | .zsh-update |
| 出力先 | $ZSH_CACHE_DIR |
| 形式 | シェル変数形式（LAST_EPOCH=xxx） |
| 内容 | LAST_EPOCH: 最終チェック日（エポック日数）、EXIT_STATUS: 更新結果、ERROR: エラーメッセージ |

## 処理フロー

### 処理シーケンス

```
1. .zsh-updateファイル移行
   └─ ~/.zsh-updateから${ZSH_CACHE_DIR}/.zsh-updateへ移動

2. 更新モード取得
   ├─ zstyle ':omz:update' mode から取得
   ├─ 未設定時: DISABLE_UPDATE_PROMPTとDISABLE_AUTO_UPDATEを確認
   └─ デフォルト: prompt

3. 更新可否判定
   ├─ mode = disabled → return
   ├─ $ZSH書き込み権限なし → return
   ├─ $ZSHオーナーでない → return
   ├─ TTY未接続（POWERLEVEL9K_INSTANT_PROMPT=off時） → return
   ├─ gitコマンドなし → return
   └─ $ZSHがGitリポジトリでない → return

4. handle_update関数
   ├─ ロックディレクトリ確認・作成
   │   └─ 1日以上古いロックは削除
   ├─ .zsh-updateファイル読み込み
   │   └─ 存在しないか不正な場合は作成してreturn
   ├─ 更新間隔判定
   │   └─ (現在エポック - LAST_EPOCH) < epoch_target → return
   ├─ Gitリポジトリ確認
   ├─ is_update_available呼び出し
   │   └─ 更新なし → update_last_updated_file & return
   ├─ モード別処理
   │   ├─ reminder または ユーザー入力あり → リマインダー表示
   │   ├─ auto/background-alpha → update_ohmyzsh
   │   └─ prompt → 確認後にupdate_ohmyzsh
   └─ クリーンアップ（ロック削除、関数unset）

5. background-alphaモードの場合
   ├─ _omz_bg_update: precmdフックでバックグラウンド更新
   └─ _omz_bg_update_status: 更新結果表示
```

### フローチャート

```mermaid
flowchart TD
    A[シェル起動] --> B[.zsh-updateファイル移行]
    B --> C[更新モード取得]
    C --> D{mode = disabled?}
    D -->|Yes| E[return]
    D -->|No| F{権限・環境チェック}
    F -->|失敗| E
    F -->|成功| G[handle_update]
    G --> H{ロック取得}
    H -->|失敗| E
    H -->|成功| I[.zsh-update読み込み]
    I --> J{更新間隔到達?}
    J -->|No| K[ロック解放]
    J -->|Yes| L[is_update_available]
    L --> M{更新あり?}
    M -->|No| N[LAST_EPOCH更新]
    M -->|Yes| O{mode判定}
    O -->|reminder| P[リマインダー表示]
    O -->|auto/background| Q[update_ohmyzsh]
    O -->|prompt| R[確認プロンプト]
    R --> S{Y/y/Enter?}
    S -->|Yes| Q
    S -->|No| T[リマインダー表示]
    N --> K
    P --> K
    Q --> K
    T --> K
    K --> E
```

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

### 操作別データベース影響一覧

該当なし（本スクリプトはデータベース操作を行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | $ZSHへの書き込み権限なし | 適切な権限を設定 |
| - | 環境エラー | Gitリポジトリでない | Oh My Zshを再インストール |
| - | ネットワークエラー | GitHub APIアクセス失敗 | 更新スキップ（エラーとしない） |
| - | 更新エラー | upgrade.sh失敗 | エラーメッセージを.zsh-updateに記録 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（自動リトライなし） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

### 障害時対応

1. ロックディレクトリが残存：1日以上古いロックは自動削除される
2. 更新失敗：エラー情報が.zsh-updateに記録され、次回起動時に表示（background-alpha）

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | handle_update関数全体（ロック制御） |
| コミットタイミング | 更新完了時 |
| ロールバック条件 | trapによりロック解放を保証 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 各シェル起動時に1回 |
| 目標処理時間 | 更新なし時: 数ミリ秒、更新チェック時: 2-3秒（APIタイムアウト含む） |
| メモリ使用量上限 | 通常のシェルスクリプト実行範囲 |

## 排他制御

- `$ZSH/log/update.lock`ディレクトリによる排他制御
- 1日以上古いロックは自動削除（デッドロック防止）
- trap によるクリーンアップ保証（EXIT, INT, QUIT）

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| プロンプト | 更新確認時 | "[oh-my-zsh] Would you like to update? [Y/n]" |
| リマインダー | リマインダーモード時 | "[oh-my-zsh] It's time to update! You can do that by running `omz update`" |
| 情報ログ | 更新スキップ時 | "[oh-my-zsh] You can update manually by running `omz update`" |
| エラーログ | Gitリポジトリでない時 | "[oh-my-zsh] Can't update: not a git repository." |
| 成功ログ | バックグラウンド更新成功時 | "[oh-my-zsh] Update successful." |
| エラーログ | バックグラウンド更新失敗時 | "[oh-my-zsh] There was an error updating:" |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 該当なし | - | - |

## 備考

- current_epoch関数はEPOCHSECONDSを日数に変換（EPOCHSECONDS / 60 / 60 / 24）
- is_update_available関数はGitHub APIを使用してリモートHEADを取得（curl/wget/fetchのいずれかを使用）
- 接続タイムアウトは2秒に設定
- has_typed_input関数でユーザーの入力をポーリング（promptモード時の割り込み検出）
- Powerlevel9kのインスタントプロンプトが有効な場合、verbose_modeは自動的にsilentに設定
- background-alphaモードはprecmdフックを使用して非同期更新を実現
