# バッチ設計書 17-add_license_to_files.jl

## 概要

本ドキュメントは、Juliaプロジェクトにおける `contrib/add_license_to_files.jl` のバッチ設計書である。このJuliaスクリプトは、ソースファイルにMITライセンスヘッダーを自動付与するメンテナンスバッチ処理である。

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

`add_license_to_files.jl` は、Juliaリポジトリ内の指定ディレクトリ配下のソースファイル（.jl, .sh, .h, .c, .cpp, .S）に対して、MITライセンスヘッダー行を自動的に挿入するバッチ処理である。既存のライセンス行の重複チェックと除去も行う。

**業務上の目的・背景**：オープンソースプロジェクトとして、各ソースファイルにライセンス表示を含めることは法的要件であり、コンプライアンスの観点から重要である。新規ファイルの追加や既存ファイルのリファクタリング時にライセンスヘッダーが欠落することがあるため、一括で付与・検証するバッチが必要である。リリースプロセスの `release-candidate` ターゲット（No.10）からも呼び出される。

**バッチの実行タイミング**：リリース候補作成時（`make release-candidate` の一部として）に自動実行されるほか、メンテナンス目的で随時手動実行される。

**主要な処理内容**：
1. 設定されたルートディレクトリ（base/, cli/, contrib/, src/, stdlib/）の再帰的走査
2. 対象拡張子（.jl, .sh, .h, .c, .cpp, .S）のファイルを特定
3. 除外ディレクトリ・除外ファイルのスキップ
4. 古いライセンステキストの検索・除去（設定されている場合）
5. 新しいライセンステキストの重複チェック・除去
6. ファイルの適切な位置（shebang行の次、またはファイル先頭）にライセンスヘッダーを挿入
7. ファイルの上書き保存

**前後の処理との関連**：`release-candidate` ターゲット（No.10）の一部として、リリース準備フローの中で実行される。本バッチの実行後、ソースファイルにライセンスヘッダーが付与された状態でリリースtarballが生成される。

**影響範囲**：base/, cli/, contrib/, src/, stdlib/ 配下の対象拡張子の全ソースファイルが影響を受ける。除外リストに含まれるファイル・ディレクトリは影響を受けない。

## バッチ種別

メンテナンス / ライセンス管理

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（リリース時および必要時） |
| 実行時刻 | 指定なし |
| 実行曜日 | 指定なし |
| 実行日 | 指定なし |
| トリガー | 手動（`julia contrib/add_license_to_files.jl`）、またはmake release-candidateの一部 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| Julia実行環境 | Juliaが実行可能であること |
| ソースディレクトリ | base/, cli/, contrib/, src/, stdlib/ が存在すること |
| 除外ファイルの存在 | excludedirs, skipfilesに定義されたパスが存在すること |

### 実行可否判定

設定で指定された `rootdirs` および除外パスの存在を起動時に検証する。存在しないパスが含まれている場合はエラーが発生する。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| rootdirs | 配列（スクリプト内定義） | Yes | ["../base", "../cli", "../contrib", "../src", "../stdlib"] | 処理対象ルートディレクトリ |
| excludedirs | 配列（スクリプト内定義） | Yes | ["../base/ryu", "../src/flisp", ...] | 除外ディレクトリ |
| skipfiles | 配列（スクリプト内定義） | Yes | 約20ファイル | 除外ファイル |
| new_license | 文字列（スクリプト内定義） | Yes | "This file is a part of Julia. License is MIT: https://julialang.org/license" | 付与するライセンステキスト |
| old_license | 文字列（スクリプト内定義） | No | "" | 除去する旧ライセンステキスト |
| print_result | 真偽値（スクリプト内定義） | No | true | 未処理ファイルリストの出力 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| ソースファイル群 | テキストファイル | 対象ディレクトリ配下の.jl, .sh, .h, .c, .cpp, .Sファイル |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| ソースファイル | テキスト | ライセンスヘッダーが挿入されたファイル（上書き） |
| stdout | テキスト | 未処理ファイルのリスト（print_result=true時） |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | 入力と同じファイル |
| 出力先 | 入力と同じパス |
| 文字コード | 入力ファイルと同一 |
| 区切り文字 | N/A |

## 処理フロー

### 処理シーケンス

```
1. パス検証
   └─ rootdirs, excludedirs, skipfilesの全パスが存在するか確認
2. ルートディレクトリ走査
   └─ 各rootdirについて再帰的にファイルを走査
3. ファイル判定
   └─ シンボリックリンク: スキップ
   └─ ディレクトリ（除外対象）: 未処理リストに追加してスキップ
   └─ ファイル（skipfiles内）: 未処理リストに追加してスキップ
   └─ ファイル（対象拡張子外）: 未処理リストに追加してスキップ
4. ファイル読み込み
   └─ 全行を読み込み
5. 旧ライセンス除去（設定時）
   └─ old_licenseテキストを含む行を検出・除去
6. 新ライセンス重複チェック
   └─ new_licenseテキストを含む行を検出・除去
7. ライセンスヘッダー挿入
   └─ shebang行がある場合は2行目、ない場合は1行目に挿入
8. ファイル上書き保存
   └─ ライセンスヘッダー付きの内容でファイルを上書き
9. 結果出力
   └─ 未処理ファイルのリストを出力
```

### フローチャート

```mermaid
flowchart TD
    A[add_license開始] --> B[パス検証]
    B --> C[各rootdirを走査]
    C --> D{ファイル/ディレクトリ判定}
    D -->|シンボリックリンク| E[スキップ]
    D -->|除外ディレクトリ| F[未処理リスト追加]
    D -->|skipfile| F
    D -->|対象拡張子外| F
    D -->|対象ファイル| G[ファイル読み込み]
    G --> H{空ファイル?}
    H -->|Yes| F
    H -->|No| I[旧ライセンス除去]
    I --> J[新ライセンス重複除去]
    J --> K{shebang行?}
    K -->|Yes| L[2行目にライセンス挿入]
    K -->|No| M[1行目にライセンス挿入]
    L --> N[ファイル上書き保存]
    M --> N
    N --> O{次のファイル?}
    O -->|Yes| D
    O -->|No| P[未処理ファイルリスト出力]
    E --> O
    F --> O
    P --> Q[add_license完了]
```

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

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

本バッチはデータベース操作を行わない。ファイルシステム操作のみである。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | パスエラー | rootdirs/excludedirs/skipfilesのパスが存在しない | 設定のパスを修正 |
| N/A | ライセンス重複エラー | ファイル内の他の行にライセンステキストが存在し、単純除去できない | 該当ファイルをskipfilesに追加するか、手動修正 |
| N/A | 設定エラー | new_licenseが空文字 | new_license設定を修正 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | N/A |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

### 障害時対応

1. エラーメッセージを確認し、問題のファイルを特定する
2. 該当ファイルをskipfilesに追加するか、手動でライセンスヘッダーの問題を修正する
3. gitで変更を元に戻すことが可能

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | ファイル単位 |
| コミットタイミング | 各ファイルの処理完了時にwrite |
| ロールバック条件 | N/A（gitによるバージョン管理で対応） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 対象ディレクトリ内の対象拡張子ファイル全数（数百〜数千ファイル） |
| 目標処理時間 | 数秒〜数十秒 |
| メモリ使用量上限 | 特に制限なし |

## 排他制御

同時実行は不可。ファイルの同時書き込みが発生する可能性がある。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 結果ログ | 処理完了時 | 各rootdir内の未処理ファイルリスト |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理結果 | 異常終了 | 実行者（手動実行のため） |

## 備考

- 拡張子とプレフィックスの対応: `.jl` -> `# `, `.sh` -> `# `, `.h` -> `// `, `.c` -> `// `, `.cpp` -> `// `, `.S` -> `// `
- ライセンステキスト: `This file is a part of Julia. License is MIT: https://julialang.org/license`
- 除外ディレクトリ: `base/ryu`（サードパーティコード）、`src/flisp`（サードパーティコード）、`stdlib/TOML/test/testfiles`（テストデータ）、`test/testhelpers/allocation_file.jl`
- skipfilesには独自の著作権表示を持つファイルが含まれる（例: `base/special/trig.jl`, `src/disasm.cpp` 等）
- スクリプト自身（`contrib/add_license_to_files.jl`）もskipfilesに含まれる
- `old_license` を設定することで、ライセンステキストの変更にも対応可能
