# 機能設計書 13-doom upgrade

## 概要

本ドキュメントは、Doom Emacsのアップグレードコマンド「doom upgrade」の機能設計を定義する。このコマンドは、Doomのコアおよびパッケージを最新バージョンに更新するためのコマンドである。

### 本機能の処理概要

doom upgradeは、Doom Emacsを最新バージョンにアップグレードするための統合コマンドである。GitリポジトリからDoomのコアを更新し、その後パッケージの同期を実行する。

**業務上の目的・背景**：Doom Emacsは活発に開発されており、新機能やバグ修正が頻繁にリリースされる。ユーザーがこれらの更新を手動で適用するには、gitコマンドの知識とdoom syncの実行が必要である。doom upgradeはこのプロセスを自動化し、ユーザーが簡単にDoomを最新状態に保てるようにする。また、更新前に変更内容を確認できる機能を提供し、意図しない変更を防ぐ。

**機能の利用シーン**：
- Doomの新バージョンがリリースされた時
- バグ修正や新機能が必要な時
- 定期的なメンテナンスとして
- パッケージのみを更新したい時（-pオプション）

**主要な処理内容**：
1. 現在のブランチと状態の確認
2. ローカル変更の検出（--forceで上書き可能）
3. アップストリームからの変更取得
4. 新旧リビジョンの比較と表示
5. ユーザー確認（差分URL表示、ブラウザで確認可能）
6. gitでHEADを更新
7. CLIとライブラリのリロード
8. doom sync -uの実行（パッケージ更新含む）

**関連システム・外部連携**：
- git: リポジトリ管理、フェッチ、リセット
- GitHub: 差分比較URL生成
- straight.el: パッケージ管理

**権限による制御**：--forceオプションでローカル変更を破棄してアップグレード可能。

## 関連画面

本機能はCLIコマンドであり、GUIの画面は持たない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | ターミナル | 主画面 | コマンドライン実行、進捗・結果表示 |
| - | Webブラウザ | 参照画面 | GitHub差分比較ページの表示 |

## 機能種別

バッチ処理 / バージョン管理 / アップデート処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --aot | フラグ | No | パッケージを事前にネイティブコンパイル | - |
| -p, --packages | フラグ | No | パッケージのみ更新（Doomは更新しない） | - |
| -j, --jobs | 数値 | No | ネイティブコンパイルに使用するCPU数 | 正の整数 |
| -B | フラグ | No | ホスト名やEmacsバージョン変更時も再ビルドしない | - |
| --force | フラグ | No | ローカル変更を破棄してアップグレード | コンテキストから取得 |

### 入力データソース

- Gitリポジトリ（doom-emacs-dir）
- doom-upgrade-url: アップストリームURL（https://github.com/doomemacs/doomemacs）
- CLIコンテキスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 現在のリビジョン | 文字列 | 現在のgitコミットハッシュ |
| 新しいリビジョン | 文字列 | 更新後のgitコミットハッシュ |
| 差分URL | URL | GitHubの比較ページURL |
| 進捗メッセージ | 文字列 | 各処理ステップの状態 |

### 出力先

- 標準出力: 進捗・結果メッセージ
- Webブラウザ: 差分比較ページ（ユーザーが選択した場合）

## 処理フロー

### 処理シーケンス

```
1. オプション判定
   └─ -p/--packagesオプションの場合はパッケージのみ更新

2. ブランチ検出
   └─ git name-revで現在のブランチを取得
   └─ HEADが取得できない場合はエラー

3. ローカル変更チェック
   └─ git statusで変更されたファイルを検出
   └─ 変更がある場合:
       └─ --forceなし: エラー終了
       └─ --forceあり: git reset --hard + git clean -ffd

4. 一時リモート設定
   └─ _upgradeという名前でリモートを追加
   └─ アップストリームからフェッチ

5. リビジョン比較
   └─ 現在のHEADと新しいリビジョンを比較
   └─ 同じ場合: 「既に最新」と表示して終了

6. 更新内容の表示
   └─ 新旧リビジョンとコミット日時を表示
   └─ GitHub差分URLを生成・表示
   └─ ユーザーにブラウザで確認するか質問

7. アップグレード確認
   └─ ユーザーに更新を続行するか確認
   └─ Noの場合: 中止

8. git reset実行
   └─ git reset --hardで新リビジョンに移動
   └─ 成功確認

9. CLIリロードとパッケージ更新
   └─ doom upgradeを-pオプションで再起動
   └─ doom sync -uを実行

10. クリーンアップ
    └─ 一時リモートとブランチを削除
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{-pオプション?}
    B -->|Yes| C[doom sync -u実行]
    B -->|No| D[ブランチ検出]
    C --> Z[終了]
    D --> E{ブランチ取得成功?}
    E -->|No| F[エラー終了]
    E -->|Yes| G[ローカル変更チェック]
    G --> H{変更あり?}
    H -->|Yes| I{--force?}
    H -->|No| J[リモート設定]
    I -->|No| K[エラー終了]
    I -->|Yes| L[変更を破棄]
    L --> J
    J --> M[フェッチ]
    M --> N[リビジョン比較]
    N --> O{最新?}
    O -->|Yes| P[最新メッセージ]
    O -->|No| Q[差分表示]
    P --> R[クリーンアップ]
    Q --> S{ブラウザで確認?}
    S -->|Yes| T[URLを開く]
    S -->|No| U{更新確認}
    T --> U
    U -->|No| V[中止]
    U -->|Yes| W[git reset]
    V --> R
    W --> X[CLI再起動]
    X --> Y[doom sync -u]
    Y --> R
    R --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ローカル変更保護 | ローカル変更がある場合はアップグレードを拒否 | --forceフラグがない場合 |
| BR-02 | 強制アップグレード | --forceでローカル変更を破棄してアップグレード | --forceフラグがある場合 |
| BR-03 | ユーザー確認 | 更新前にユーザー確認を求める | --forceフラグがない場合 |
| BR-04 | straight更新チェック | straight.elのレシピが変更された場合、リポジトリを削除 | パッケージ更新時 |

### 計算ロジック

**ブランチ名の抽出**:
```elisp
(replace-regexp-in-string
 "^\\(?:[^/]+/[^/]+/\\)?\\(.+\\)\\(?:~[0-9]+\\)?$" "\\1"
 (cdr (sh! "git" "name-rev" "--name-only" "HEAD")))
```

**差分URL生成**:
```elisp
(format "%s/compare/%s...%s"
        doom-upgrade-url
        this-rev
        new-rev)
```

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

本機能はデータベースを使用しない。Gitリポジトリの操作を行う。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ユーザーエラー | ローカル変更があり--forceなし | stash/undo変更または--forceを使用 |
| - | エラー | .gitディレクトリが見つからない | Doomが正しくクローンされているか確認 |
| - | エラー | ブランチを検出できない | Doomがdetachedでないか確認 |
| - | エラー | リモート追加に失敗 | ネットワーク接続を確認 |
| - | エラー | フェッチに失敗 | ネットワーク接続を確認 |
| - | エラー | チェックアウトに失敗 | リポジトリの状態を確認 |

### リトライ仕様

特になし。ユーザーが手動でdoom upgradeを再実行する。

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

- 一時リモートとブランチはunwind-protectで必ずクリーンアップされる
- git resetに失敗した場合、手動でリカバリが必要

## パフォーマンス要件

- --jobsオプションでネイティブコンパイルの並列度を制御可能
- ネットワーク速度に依存

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

- doom-upgrade-url（github.com/doomemacs/doomemacs）のみからフェッチ
- 一時リモート名（_upgrade）を使用し、既存リモートとの競合を回避

## 備考

- アップグレード後、CLIを再起動してから同期を実行するため、二段階の実行となる
- -pオプションのみの場合は、doom sync -uを直接呼び出す

---

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

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

### 推奨読解順序

#### Step 1: 変数定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | upgrade.el | `lisp/cli/upgrade.el` | 11-14行目の変数定義 |

**読解のコツ**: `doom-upgrade-url`はアップストリームのGitHub URL、`doom-upgrade-remote`は一時リモート名（_upgrade）を定義。

#### Step 2: コマンド定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | upgrade.el | `lisp/cli/upgrade.el` | 21-64行目のdefcli!定義 |

**主要処理フロー**:
- **21-26行目**: コマンド定義と引数パース
- **35-53行目**: -pオプション（パッケージのみ更新）の処理
- **55-64行目**: Doomアップグレード処理の開始と再起動

#### Step 3: アップグレードロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | upgrade.el | `lisp/cli/upgrade.el` | 70-149行目のdoom-cli-upgrade関数 |

**主要処理フロー**:
- **76-83行目**: ブランチ名の検出と正規化
- **90-99行目**: ローカル変更チェックと--force処理
- **101-109行目**: 一時リモートの設定とフェッチ
- **111-146行目**: リビジョン比較、確認、更新

#### Step 4: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | upgrade.el | `lisp/cli/upgrade.el` | 151-166行目のヘルパー関数 |

**主要処理フロー**:
- **151-156行目**: doom-upgrade--working-tree-dirty-p - ローカル変更の検出
- **158-166行目**: doom-upgrade--get-straight-recipe - straight.elのレシピ取得

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

```
doom upgrade (defcli!)
    │
    ├─ [packages?]
    │      └─ call! '(sync -u ...)
    │
    └─ doom-cli-upgrade
           │
           ├─ sh! "git" "name-rev" ...
           │
           ├─ doom-upgrade--working-tree-dirty-p
           │      └─ doom-call-process "git" "status"
           │
           ├─ sh! "git" "reset" "--hard"
           │
           ├─ sh! "git" "remote" "add"
           │
           ├─ sh! "git" "fetch"
           │
           ├─ sh! "git" "rev-parse"
           │
           ├─ browse-url (差分URL)
           │
           ├─ sh! "git" "reset" "--hard"
           │
           └─ exit! "doom" "upgrade" "-p" ...
                  └─ doom sync -u
```

### データフロー図

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

doom-emacs-dir        ───▶  ブランチ検出   ───▶  現在のブランチ名
(.git)                           │
                                 │
doom-upgrade-url      ───▶  フェッチ      ───▶  新リビジョン
(GitHub)                         │
                                 │
現在のHEAD            ───▶  比較          ───▶  差分URL
                                 │                (GitHubへ)
                                 │
ユーザー入力          ───▶  確認          ───▶  更新実行
                                 │
                                 │
git reset             ───▶  HEAD更新      ───▶  doom sync -u
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| upgrade.el | `lisp/cli/upgrade.el` | ソース | upgradeコマンドの主実装 |
| sync.el | `lisp/cli/sync.el` | ソース | パッケージ同期処理 |
| doom-cli.el | `lisp/doom-cli.el` | ソース | CLIフレームワーク |
| packages.el | `lisp/lib/packages.el` | ソース | パッケージ管理ライブラリ |
