# 機能設計書 63-DCD更新

## 概要

本ドキュメントは、serve-dにおけるDCD更新機能（served/updateDCD）の設計を記述する。DCDをソースからビルドまたはプリビルドバイナリをダウンロードして更新するファイル。DCDが古い場合や存在しない場合に、自動または手動でDCDの最新バージョンを取得・インストールする。

### 本機能の処理概要

**業務上の目的・背景**：DCD（D Completion Daemon）はserve-dのコード補完・定義ジャンプ等のコア機能に必要な外部ツールである。DCDが未インストールの場合やバージョンが古い場合、serve-dの主要機能が利用できなくなる。本機能はDCDの自動インストール・更新を提供し、ユーザーが手動でDCDをセットアップする手間を軽減する。

**機能の利用シーン**：
- サーバー初期化時にDCDが見つからない/古い場合に自動トリガー
- ユーザーがDCD更新確認ダイアログでインストールを選択した場合
- 手動でserved/updateDCDを呼び出した場合

**主要な処理内容**：
1. 既存のDCDファイルをクリーンアップする
2. プラットフォームに応じてソースからのビルドまたはバイナリダウンロードを選択する
3. ソースビルドの場合：GitHubからDCDリポジトリをクローンし、dubでビルドする
4. バイナリダウンロードの場合：GitHubリリースページからアーカイブをダウンロード・展開する
5. インストール成功時：クライアント設定を更新し、全ワークスペースでDCDサーバーを起動する
6. インストール失敗時：デフォルトパスにフォールバックし、エラーをログに通知する

**関連システム・外部連携**：
- GitHub（DCD リポジトリ / リリースバイナリ）
- dub（D言語パッケージマネージャ / ビルドツール）
- git（ソースコード取得）
- tar / ZipArchive（アーカイブ展開）

**権限による制御**：特別な権限制御はない。ファイルシステムへの書き込み権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | グローバルスタートアップ | 遷移元 | DCDが古い場合にDCD更新処理をトリガーする |
| 4 | DCD更新確認ダイアログ | 主画面 | ユーザーにコンパイル/ダウンロードの選択肢を表示し、選択に応じてDCD更新を実行する |
| 14 | インストールログ通知 | 結果表示画面 | DCD更新処理の進捗をcoded/logInstall通知でクライアントに送信する |
| 15 | 設定更新通知 | 結果表示画面 | DCD更新完了時にcoded/updateSetting通知でDCDパス設定をクライアントに反映する |
| 39 | DCD更新（served/updateDCD） | 主画面 | DCDをソースからコンパイルまたはバイナリをダウンロードして更新する |

## 機能種別

外部ツール管理（インストール・更新）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| (なし) | - | - | パラメータなしの通知 | - |

### 入力データソース

- LSPクライアントからの `served/updateDCD` 通知
- グローバル変数 `dcdUpdateReason` によりインストール理由が指定される場合がある

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| coded/logInstall | string | インストール進捗ログをクライアントに通知 |
| coded/updateSetting | UpdateSettingParams | DCDパス設定の更新をクライアントに通知 |

### 出力先

- LSPクライアントへの通知（coded/logInstall, coded/updateSetting）
- ファイルシステム（DCDバイナリの配置先）

## 処理フロー

### 処理シーケンス

```
1. served/updateDCD通知を受信
   └─ updateDCD()関数が呼び出される
2. インストール開始をログに通知
   └─ coded/logInstallでインストール開始メッセージ送信
3. 出力フォルダの決定とクリーンアップ
   └─ determineOutputFolder()でプラットフォーム別の出力先を決定
   └─ 既存のDCD関連ファイル/ディレクトリを削除
4. プラットフォーム判定
   └─ isDCDFromSource判定でソースビルドかバイナリダウンロードかを決定
5a. ソースビルドの場合
   └─ compileDependency()でGitHubからクローン+dubビルド
5b. バイナリダウンロードの場合
   └─ downloadFile()でGitHubリリースからダウンロード
   └─ tar/zipで展開
6. 実行可能ファイルの存在確認
   └─ dcd-client, dcd-serverが存在するか確認
7. バージョン確認
   └─ dcd-server --version で動作確認
8. 設定の更新
   └─ coded/updateSettingでクライアント設定を更新
   └─ backend.globalConfigurationにパスを設定
   └─ 各ワークスペースの設定を更新
9. DCDサーバーの起動
   └─ 各ワークスペースでlazyStartDCDServerを呼び出し
10. 完了通知
    └─ coded/logInstallで成功/失敗メッセージ送信
```

### フローチャート

```mermaid
flowchart TD
    A[served/updateDCD 通知受信] --> B[インストール開始ログ通知]
    B --> C[出力フォルダ決定・クリーンアップ]
    C --> D{ソースビルド?}
    D -->|Yes| E[GitHubからクローン + dubビルド]
    D -->|No| F[GitHubリリースからバイナリダウンロード]
    E --> G{ビルド成功?}
    F --> H{ダウンロード成功?}
    G -->|Yes| I[実行ファイル存在確認]
    G -->|No| J[デフォルトパスにフォールバック]
    H -->|Yes| K[アーカイブ展開]
    H -->|No| J
    K --> I
    I -->|存在する| L[dcd-server --version 実行確認]
    I -->|存在しない| J
    L -->|成功| M[設定更新 + DCDサーバー起動]
    L -->|失敗| J
    J --> N[coded/updateSetting でデフォルトパス設定]
    M --> O[成功ログ通知]
    N --> P[失敗ログ通知]
    O --> Q[完了]
    P --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-63-01 | プラットフォーム判定 | Win32 x86_64以外のWin32、非x86_64の非Windows/Linux/macOS環境ではソースビルドを強制 | コンパイル時のversion条件 |
| BR-63-02 | バンドルバージョン | ダウンロード可能なDCDのバージョンはv0.15.2（bundledDCDVersion） | バイナリダウンロード時 |
| BR-63-03 | バージョン整合性 | bundledDCDVersionがDCDComponent.latestKnownVersionより古い場合はソースビルドに切り替え | バイナリダウンロード判定時 |
| BR-63-04 | 失敗時フォールバック | インストール失敗時はdcd-client/dcd-serverのデフォルト名をパスとして設定 | インストール失敗時 |
| BR-63-05 | 出力フォルダ | Linux: ~/.local/share/code-d/bin、Windows: %APPDATA%/code-d/bin、その他: ~/.code-d/bin | 常時 |

### 計算ロジック

特になし。

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

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

データベース操作はない。ファイルシステムへのバイナリ配置のみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ダウンロード失敗 | ネットワーク接続不良またはURL無効 | coded/logInstallでエラーを通知、手動ダウンロードを案内 |
| - | ビルド失敗 | dubまたはgitが未インストール、またはビルドエラー | coded/logInstallでエラーを通知 |
| - | 実行ファイル未発見 | ビルド/展開後にdcd-client/dcd-serverが見つからない | パス候補をログに出力し、手動設定を案内 |
| - | バージョン確認失敗 | dcd-server --versionが非0終了 | coded/logInstallで出力を通知 |

### リトライ仕様

既にダウンロード済みのzipファイルが存在する場合は再ダウンロードせず既存ファイルを利用する。

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

トランザクション管理は不要。ファイルシステム操作は冪等ではないが、既存ファイルのクリーンアップにより再実行可能。

## パフォーマンス要件

ネットワークダウンロードおよびソースビルドを含むため、数分単位の処理時間が発生しうる。進捗はcoded/logInstall通知でリアルタイムに報告される。

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

- GitHubからのHTTPSダウンロードを使用
- ダウンロードしたバイナリの実行を伴うため、ダウンロード元の信頼性に依存
- ファイルシステムへの書き込みはユーザーのホームディレクトリ配下に限定

## 備考

- `@protocolNotification("served/updateDCD")` アノテーションにより、LSP通知として登録
- グローバル変数 `dcdUpdating` でDCD更新中フラグを管理
- グローバル変数 `dcdUpdateReason` でインストール理由を保持
- scope(exit)で `dcdUpdating` と `dcdUpdateReason` がクリアされる
- `latestReleaseBinaryBroken` フラグにより、リリースバイナリに問題がある場合にソースビルドに強制切り替え可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dcd_update.d | `source/served/commands/dcd_update.d` | グローバル変数 dcdUpdateReason, dcdUpdating（80-81行目） |
| 1-2 | types.d | `source/served/types.d` | UpdateSettingParams型の定義 |

**読解のコツ**: D言語の `version` ブロックはコンパイル時条件分岐。`version (Win32)`, `version (X86_64)` 等でプラットフォーム別コードを切り替える。`enum` を使った `isDCDFromSource` はコンパイル時定数。

#### Step 2: プラットフォーム判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dcd_update.d | `source/served/commands/dcd_update.d` | version分岐（22-78行目）でisDCDFromSourceを決定 |

**主要処理フロー**:
- **22-45行目**: Win32環境の判定（WoW64チェック含む）
- **46-68行目**: 非Windows環境でx86_64/AArch64の判定
- **71-78行目**: コンパイル時定数 `isDCDFromSource` の確定

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dcd_update.d | `source/served/commands/dcd_update.d` | updateDCD関数（82-307行目） |

**主要処理フロー**:
1. **85-89行目**: scope(exit)でdcdUpdating/dcdUpdateReasonのクリーンアップ
2. **91-94行目**: coded/logInstallでインストール開始通知
3. **96-112行目**: 出力フォルダの決定とクリーンアップ
4. **126-129行目**: ソースビルドか判定（isDCDFromSource + バージョンチェック）
5. **133-153行目**: ソースビルドパス（compileDependencyでGitクローン+dubビルド）
6. **156-237行目**: バイナリダウンロードパス（URL構築、ダウンロード、展開）
7. **239-261行目**: 実行ファイル存在確認とバージョンチェック
8. **270-273行目**: coded/updateSettingでクライアント設定通知
9. **275-301行目**: 成功時の設定反映とDCDサーバー起動

#### Step 4: 依存関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | extension.d | `source/served/extension.d` | determineOutputFolder関数（1057-1076行目）- プラットフォーム別の出力先決定 |
| 4-2 | extension.d | `source/served/extension.d` | lazyStartDCDServer関数（1028-1055行目）- DCDサーバーの遅延起動 |
| 4-3 | git_build.d | `source/served/io/git_build.d` | compileDependency関数 - Gitクローンとビルドの実行 |

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

```
updateDCD() [dcd_update.d:82-307]
    |
    +-- rpc.notifyMethod("coded/logInstall", ...) (進捗通知)
    |
    +-- determineOutputFolder() [extension.d:1057-1076]
    |       +-- プラットフォーム別の出力先パスを返却
    |
    +-- [ソースビルドパス]
    |   +-- compileDependency() [git_build.d]
    |       +-- git submodule update
    |       +-- dub build --config=client
    |       +-- dub build --config=server
    |
    +-- [バイナリダウンロードパス]
    |   +-- downloadFile() [http_wrap.d]
    |   +-- tar xvfz / ZipArchive展開
    |
    +-- execute([dcd-server, "--version"]) (バージョン確認)
    |
    +-- rpc.notifyMethod("coded/updateSetting", ...) (設定更新通知)
    |
    +-- [成功時] 各ワークスペース設定更新
        +-- lazyStartDCDServer() [extension.d:1028-1055]
```

### データフロー図

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

served/updateDCD      ──▶  updateDCD()                              ──▶  coded/logInstall (進捗ログ)
(LSP通知)                    |                                           coded/updateSetting (設定更新)
                            +-- GitHub DCD リポジトリ/リリース               DCD バイナリ (ファイルシステム)
dcdUpdateReason       ──▶  +-- ダウンロード or ソースビルド
(グローバル変数)              +-- バイナリ配置・検証
                            +-- 設定反映・DCD起動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dcd_update.d | `source/served/commands/dcd_update.d` | ソース | updateDCD関数の定義（全307行） |
| extension.d | `source/served/extension.d` | ソース | determineOutputFolder, lazyStartDCDServer |
| git_build.d | `source/served/io/git_build.d` | ソース | compileDependency - Gitクローン+ビルド |
| http_wrap.d | `source/served/io/http_wrap.d` | ソース | downloadFile - HTTPダウンロード |
| types.d | `source/served/types.d` | ソース | UpdateSettingParams型、DCD パス検出ロジック |
