# 画面設計書 39-DCD更新（served/updateDCD）

## 概要

本ドキュメントは、serve-d LSPサーバーが提供する `served/updateDCD` 通知ハンドラの画面設計書である。DCD（D Completion Daemon）をソースからコンパイルまたはバイナリをダウンロードして更新し、進捗をクライアントに通知する機能を定義する。

### 本画面の処理概要

本機能は、DCDの更新処理を実行する。プラットフォームに応じてソースコードからのコンパイルまたはプリビルドバイナリのダウンロードを選択し、完了後にDCDのパス設定を更新してDCDサーバーを起動する。

**業務上の目的・背景**：DCDはD言語のコード補完・定義ジャンプ等の中核機能を提供するデーモンプロセスである。DCDのバージョンが古い場合、最新の言語機能に対応できない可能性がある。本機能はDCDの自動更新を実現し、開発者がDCDのバージョン管理を手動で行う必要をなくす。起動時にDCDが古い場合のダイアログ（No.4）から呼び出される。ソースからのコンパイルとバイナリダウンロードの2つの更新パスを備え、プラットフォーム対応を最大化している。

**画面へのアクセス方法**：(1) DCD更新確認ダイアログ（No.4）から「コンパイル/ダウンロード」を選択した場合、(2) `served/updateDCD` 通知の直接送信。

**主要な操作・処理内容**：
1. クライアントから `served/updateDCD` 通知を受信する
2. 更新理由がある場合は `coded/logInstall` 通知でクライアントに送信
3. 出力フォルダを決定し、既存のDCDファイルを削除
4. プラットフォームに応じてソースコンパイルまたはバイナリダウンロードを選択
5. ソースコンパイルの場合：gitクローン、サブモジュール更新、dubビルド（client/server）
6. バイナリダウンロードの場合：GitHubリリースからアーカイブをダウンロード・展開
7. ダウンロード/コンパイル完了後、dcd-serverの `--version` 確認を実行
8. `coded/updateSetting` 通知でdcdClientPath/dcdServerPathをクライアントに設定
9. 成功時：バックエンド設定更新、全ワークスペースのDCDサーバー起動
10. 失敗時：フォールバックとして"dcd-client"/"dcd-server"をパスに設定

**画面遷移**：DCD更新確認ダイアログ（No.4）から遷移。更新完了後はDCDサーバー起動処理が実行される。

**権限による表示制御**：特別な権限制御はない。プラットフォーム（OS/アーキテクチャ）による処理パスの自動選択のみ。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 63 | DCD更新 (served/updateDCD) | 主機能 | DCDをソースからコンパイルまたはバイナリをダウンロードして更新する |
| 82 | 進捗レポート | 補助機能 | DCD更新の進捗をcoded/logInstall通知でクライアントに送信する |

## 画面種別

LSP通知ハンドラ（長時間処理）

## URL/ルーティング

LSPメソッド: `served/updateDCD`（通知）

## 入出力項目

### 入力

本通知はパラメータなし。更新理由は `dcdUpdateReason` グローバル変数で事前設定。

### 出力（通知）

| 通知メソッド | 説明 |
|-------------|------|
| coded/logInstall | インストール進捗メッセージ |
| coded/updateSetting | DCD client/server パス設定更新 |

## 表示項目

| 表示項目 | 説明 |
|----------|------|
| インストールログ | coded/logInstall通知によるインストール進捗表示 |
| 設定更新 | coded/updateSetting通知によるDCDパス設定反映 |

## イベント仕様

### 1-updateDCD通知処理

1. `updateDCD()` 関数が呼び出される
2. scope(exit)で `dcdUpdating = false`, `dcdUpdateReason = null` を設定
3. `coded/logInstall` で開始メッセージ送信（理由付きまたは通常）
4. `determineOutputFolder` で出力フォルダ決定
5. 既存のDCD関連ファイル/フォルダを削除（"dcd", "DCD", "dcd-client", "dcd-server"）
6. プラットフォーム判定：
   - **ソースコンパイルパス**（`isDCDFromSource` = true）:
     - `compileDependency` でGitHubからクローン・ビルド
     - git submodule update, dub build --config=client, dub build --config=server
     - 実行可能ファイルパスを "DCD/dcd-client", "DCD/bin/dcd-client" 等から検索
   - **バイナリダウンロードパス**:
     - bundledDCDVersion（v0.15.2）に基づくURLを構築
     - Windows: .zip, Linux/macOS: .tar.gz
     - `downloadFile` でダウンロード
     - zip/tar.gzを展開
     - 実行可能ファイルパスを "dcd-client", "bin/dcd-client" 等から検索
7. 実行可能ファイルの存在確認
8. `dcd-server --version` で動作確認
9. `coded/updateSetting` でdcdClientPath/dcdServerPathを通知
10. 成功時：`backend.globalConfiguration.set`, 全ワークスペースの設定更新、`lazyStartDCDServer` 呼び出し
11. 失敗時："dcd-client"/"dcd-server" にフォールバック

## データベース更新仕様

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

本機能はデータベースへの更新を行わない。ファイルシステムへの書き込みが発生する。

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| DCD更新 | ファイルシステム | WRITE | DCD実行可能ファイルのダウンロード/コンパイル |
| 設定更新 | グローバル設定/ワークスペース設定 | UPDATE | DCDパス設定の更新 |

## メッセージ仕様

| メッセージ種別 | 条件 | メッセージ内容 |
|---------------|------|---------------|
| logInstall | 更新開始 | "Installing DCD" または "Installing DCD: {理由}" |
| logInstall | ダウンロード時 | "Downloading from {url} to {outputFolder}" |
| logInstall | 展開時 | "Extracting download..." |
| logInstall | 成功時 | "Successfully installed DCD" |
| logInstall | 失敗時 | "DCD install failed" |
| logInstall | 実行可能ファイル未発見 | "Successfully downloaded DCD, but could not find the executables." |
| logInstall | --version失敗 | "Successfully downloaded DCD, but trying to run `{path} --version` failed:" |
| updateSetting | 完了時 | dcdClientPath, dcdServerPath の設定値 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| ダウンロード失敗 | logInstall通知でエラー表示、success=false |
| コンパイル失敗 | compileDependencyがfalseを返し、success=false |
| 実行可能ファイル未発見 | logInstall通知で手動設定を案内、success=false |
| --version実行失敗 | logInstall通知で出力を表示、success=false |
| 全失敗時 | "dcd-client"/"dcd-server" をフォールバックパスとして設定 |

## 備考

- bundledDCDVersion = "v0.15.2"（ダウンロード可能な最新リリースバージョン）
- ソースコンパイルが選択される条件：(1) isDCDFromSource定数（プラットフォーム非対応時）、(2) latestReleaseBinaryBroken=true時、(3) bundledDCDVersionがDCDComponent.latestKnownVersionより古い場合
- Win32 x86環境では実行時にWoW64チェックを行い、64bitプロセス互換性がない場合はソースコンパイルにフォールバック
- dcdUpdatingフラグで二重実行を防止
- 既存ZIPファイルが存在する場合はダウンロードをスキップして展開のみ実行
- scope(exit)により、関数終了時に確実にフラグがリセットされる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dcd_update.d | `source/served/commands/dcd_update.d` | グローバル変数 dcdUpdateReason, dcdUpdating（行80-81） |
| 1-2 | dcd_update.d | `source/served/commands/dcd_update.d` | プラットフォーム判定のversion条件分岐（行22-78） |
| 1-3 | types.d | `source/served/types.d` | UpdateSettingParams型の定義 |

**読解のコツ**: D言語の `version` 文はコンパイル時条件分岐である。`version (DCDFromSource)` はプラットフォームに応じて静的に決定される。`version (RuntimeSourceCheck)` は実行時判定が必要な特殊ケース（Win32 x86）である。

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

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

**主要処理フロー**:
1. **行82**: `@protocolNotification("served/updateDCD")` で通知ハンドラとして登録
2. **行85-89**: scope(exit)でフラグリセット
3. **行91-94**: 開始ログ通知
4. **行96-112**: 出力フォルダ準備・既存ファイル削除
5. **行126-153**: ソースコンパイルパス（compileDependency呼び出し）
6. **行155-237**: バイナリダウンロードパス（downloadFile, tar/zip展開）
7. **行239-261**: 実行可能ファイル検証
8. **行270-273**: coded/updateSetting通知
9. **行275-301**: 成功時の設定更新・DCDサーバー起動
10. **行303-306**: 失敗時のログ通知

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

```
updateDCD (dcd_update.d:83)
    |
    +-- rpc.notifyMethod("coded/logInstall") 進捗通知
    +-- determineOutputFolder
    +-- [既存ファイル削除]
    |
    +-- [ソースコンパイルパス]
    |   +-- compileDependency (io/git_build.d)
    |       +-- git clone
    |       +-- git submodule update
    |       +-- dub build --config=client
    |       +-- dub build --config=server
    |
    +-- [バイナリダウンロードパス]
    |   +-- downloadFile (io/http_wrap.d)
    |   +-- tar/zip 展開
    |
    +-- execute([finalDestinationServer, "--version"]) 動作確認
    +-- rpc.notifyMethod("coded/updateSetting") パス設定通知
    +-- backend.globalConfiguration.set 設定更新
    +-- [各ワークスペース] lazyStartDCDServer
```

### データフロー図

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

served/updateDCD   --->   updateDCD関数                   --->  coded/logInstall通知
(パラメータなし)            |                                     (進捗メッセージ)
                           +-- プラットフォーム判定
                           +-- [ソース] git clone + dub build     coded/updateSetting通知
                           +-- [バイナリ] download + extract       (dcdClientPath)
                           +-- 実行可能ファイル検証                (dcdServerPath)
                           +-- 設定更新
                           +-- DCDサーバー起動                    DCDサーバープロセス起動
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dcd_update.d | `source/served/commands/dcd_update.d` | ソース | DCD更新処理本体（307行） |
| git_build.d | `source/served/io/git_build.d` | ソース | compileDependency関数（Git+dubビルド） |
| http_wrap.d | `source/served/io/http_wrap.d` | ソース | downloadFile関数（HTTPダウンロード） |
| extension.d | `source/served/extension.d` | ソース | グローバル変数、lazyStartDCDServer関数 |
| types.d | `source/served/types.d` | ソース | UpdateSettingParams等のLSP型定義 |
