@einja/dev-cli 0.1.44 → 0.1.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/cli.js +0 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +51 -31
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/sync.test.js +1 -1
- package/dist/commands/sync.test.js.map +1 -1
- package/dist/lib/sync/file-filter.d.ts.map +1 -1
- package/dist/lib/sync/file-filter.js +51 -2
- package/dist/lib/sync/file-filter.js.map +1 -1
- package/dist/lib/sync/file-filter.test.js +60 -0
- package/dist/lib/sync/file-filter.test.js.map +1 -1
- package/dist/lib/sync/json-processor.d.ts +49 -27
- package/dist/lib/sync/json-processor.d.ts.map +1 -1
- package/dist/lib/sync/json-processor.js +182 -82
- package/dist/lib/sync/json-processor.js.map +1 -1
- package/dist/lib/sync/json-processor.test.d.ts +2 -0
- package/dist/lib/sync/json-processor.test.d.ts.map +1 -0
- package/dist/lib/sync/json-processor.test.js +334 -0
- package/dist/lib/sync/json-processor.test.js.map +1 -0
- package/dist/lib/sync/metadata-manager.d.ts +6 -1
- package/dist/lib/sync/metadata-manager.d.ts.map +1 -1
- package/dist/lib/sync/metadata-manager.js +26 -6
- package/dist/lib/sync/metadata-manager.js.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/sync.d.ts +2 -0
- package/dist/types/sync.d.ts.map +1 -1
- package/dist/types/sync.js +1 -0
- package/dist/types/sync.js.map +1 -1
- package/package.json +1 -1
- package/presets/default/.claude/commands/einja/einja-sync.md +6 -6
- package/presets/default/docs/einja/instructions/setup-flow.md +40 -0
- package/presets/default/package.json +73 -0
- package/presets/default/preset.yaml +2 -2
- package/presets/default/scripts/ensure-serena.sh +26 -7
- package/dist/lib/sync/backup-manager.d.ts +0 -50
- package/dist/lib/sync/backup-manager.d.ts.map +0 -1
- package/dist/lib/sync/backup-manager.js +0 -117
- package/dist/lib/sync/backup-manager.js.map +0 -1
- package/dist/lib/sync/backup-manager.test.d.ts +0 -2
- package/dist/lib/sync/backup-manager.test.d.ts.map +0 -1
- package/dist/lib/sync/backup-manager.test.js +0 -155
- package/dist/lib/sync/backup-manager.test.js.map +0 -1
|
@@ -202,6 +202,8 @@ sequenceDiagram
|
|
|
202
202
|
| `scripts` | `scripts/` | ユーティリティスクリプト(`_` プレフィックスは除外) |
|
|
203
203
|
| `env` | `.envrc` | direnv 設定 |
|
|
204
204
|
| `tools` | `.vscode/settings.json` | VS Code 設定 |
|
|
205
|
+
| `root-config` | `package.json`, `.mcp.json` | ルート設定ファイル |
|
|
206
|
+
| `claude-config` | `.claude/settings.json` | Claude Code設定 |
|
|
205
207
|
|
|
206
208
|
**マージ方式:**
|
|
207
209
|
|
|
@@ -213,6 +215,44 @@ sequenceDiagram
|
|
|
213
215
|
| JSON マージ | `.json` 拡張子のファイル | managed/project-private の JSON パス指定に基づきマージ |
|
|
214
216
|
| 3方向マージ | マーカーなしの通常ファイル | base(前回テンプレート)・local・template の3方向差分で自動マージ。コンフリクト時はマーカー付きで出力 |
|
|
215
217
|
|
|
218
|
+
#### JSON マージモード(3モード構成)
|
|
219
|
+
|
|
220
|
+
| モード | 動作 | 設定方法 |
|
|
221
|
+
|--------|------|---------|
|
|
222
|
+
| `managed` | テンプレート値で強制上書き | jsonPaths.managed にパス指定 |
|
|
223
|
+
| `project-private` | 完全除外(テンプレートから追加しない) | jsonPaths["project-private"] にパス指定 |
|
|
224
|
+
| デフォルト | 3方向マージ(base/local/template比較、コンフリクト検出) | 上記以外の全パス |
|
|
225
|
+
|
|
226
|
+
#### JSON ファイルの同期動作(3方向マージ)
|
|
227
|
+
|
|
228
|
+
| 操作 | 結果 |
|
|
229
|
+
|------|------|
|
|
230
|
+
| テンプレートに新キーが追加された(利用者は未変更) | sync時に利用者のファイルに追加される |
|
|
231
|
+
| 利用者が独自キーを追加した | 保持される |
|
|
232
|
+
| 利用者がテンプレート由来のキーを削除(テンプレート側は未変更) | 削除が維持される |
|
|
233
|
+
| 利用者がテンプレート由来のキーを変更(テンプレート側は未変更) | 利用者の変更が保持される |
|
|
234
|
+
| テンプレートがキーを更新(利用者側は未変更) | テンプレートの更新が自動適用される |
|
|
235
|
+
| 両方が同じキーを異なる値に変更 | コンフリクト警告(利用者の値を保持) |
|
|
236
|
+
| project-private 指定のキー | テンプレートから一切追加・変更されない |
|
|
237
|
+
| managed 指定のキー | テンプレート値で常に上書き |
|
|
238
|
+
|
|
239
|
+
#### ファイル別 jsonPaths 設定
|
|
240
|
+
|
|
241
|
+
| ファイル | managed | project-private | 残り |
|
|
242
|
+
|---------|---------|----------------|------|
|
|
243
|
+
| `package.json` | — | name, version, private, workspaces, packageManager, volta | 3方向マージ |
|
|
244
|
+
| `.claude/settings.json` | plansDirectory, includeCoAuthoredBy | — | 3方向マージ |
|
|
245
|
+
| `.vscode/settings.json` | editor.*, eslint.*, prettier.*, [json], [jsonc] | — | 3方向マージ |
|
|
246
|
+
| `.mcp.json` | — | — | 3方向マージ |
|
|
247
|
+
|
|
248
|
+
#### base スナップショット
|
|
249
|
+
|
|
250
|
+
3方向マージには「前回sync時のテンプレート内容」(base)が必要。
|
|
251
|
+
`.einja-sync.json` の `baseContent` フィールドに保存される。
|
|
252
|
+
|
|
253
|
+
- 初回sync(baseなし): ローカル優先 + テンプレートの新規キーのみ追加
|
|
254
|
+
- 2回目以降: base/local/template の3方向比較でマージ
|
|
255
|
+
|
|
216
256
|
#### create-einja-app sync の同期対象カテゴリ
|
|
217
257
|
|
|
218
258
|
| カテゴリ | 対象パターン | デフォルト選択 |
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "einja-management-monorepo",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"packageManager": "pnpm@10.14.0",
|
|
6
|
+
"workspaces": [
|
|
7
|
+
"apps/*",
|
|
8
|
+
"packages/*"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"prepare": "husky",
|
|
12
|
+
"dev": "tsx scripts/worktree/dev.ts",
|
|
13
|
+
"dev:bg": "tsx scripts/worktree/dev.ts --background",
|
|
14
|
+
"dev:stop": "tsx scripts/worktree/dev.ts --stop",
|
|
15
|
+
"dev:status": "tsx scripts/worktree/dev.ts --status",
|
|
16
|
+
"dev:logs": "tail -f log/dev.log",
|
|
17
|
+
"dev:skip-setup": "turbo run dev",
|
|
18
|
+
"build": "dotenvx run -f .env.production -- turbo run build",
|
|
19
|
+
"build:dev": "dotenvx run -f .env.develop -- turbo run build",
|
|
20
|
+
"build:local": "turbo run build",
|
|
21
|
+
"start": "turbo run start",
|
|
22
|
+
"generate": "turbo run generate",
|
|
23
|
+
"lint": "turbo run lint",
|
|
24
|
+
"lint:fix": "turbo run lint:fix",
|
|
25
|
+
"format": "turbo run format",
|
|
26
|
+
"format:fix": "turbo run format:fix",
|
|
27
|
+
"typecheck": "turbo run typecheck",
|
|
28
|
+
"test": "turbo run test",
|
|
29
|
+
"test:watch": "turbo run test:watch",
|
|
30
|
+
"test:ui": "turbo run test:ui",
|
|
31
|
+
"test:coverage": "turbo run test:coverage",
|
|
32
|
+
"prepush": "pnpm prepush:lint && pnpm prepush:typecheck && pnpm prepush:test",
|
|
33
|
+
"prepush:lint": "lint-staged",
|
|
34
|
+
"prepush:typecheck": "turbo run typecheck",
|
|
35
|
+
"prepush:test": "turbo run test",
|
|
36
|
+
"db:generate": "turbo run db:generate",
|
|
37
|
+
"db:push": "turbo run db:push",
|
|
38
|
+
"db:migrate": "turbo run db:migrate",
|
|
39
|
+
"db:migrate:deploy": "turbo run db:migrate:deploy",
|
|
40
|
+
"db:studio": "turbo run db:studio",
|
|
41
|
+
"db:seed": "turbo run db:seed",
|
|
42
|
+
"dev:setup": "tsx scripts/setup-dev.ts",
|
|
43
|
+
"dotenvx": "dotenvx",
|
|
44
|
+
"env:update": "tsx scripts/env.ts",
|
|
45
|
+
"env:encrypt": "dotenvx encrypt",
|
|
46
|
+
"env:show": "tsx scripts/env-show.ts",
|
|
47
|
+
"env:rotate-secrets": "tsx scripts/env-rotate-secrets.ts",
|
|
48
|
+
"einja:sync": "npx --yes @einja/dev-cli@latest sync",
|
|
49
|
+
"init:github": "tsx scripts/init-github.ts",
|
|
50
|
+
"task:loop": "npx --yes @einja/dev-cli@latest task:loop",
|
|
51
|
+
"changeset": "changeset"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@changesets/changelog-github": "^0.5.1",
|
|
55
|
+
"@changesets/cli": "^2.29.0",
|
|
56
|
+
"@clack/prompts": "^0.11.0",
|
|
57
|
+
"@dotenvx/dotenvx": "^1.51.4",
|
|
58
|
+
"@types/node": "^25.0.3",
|
|
59
|
+
"husky": "^9.1.7",
|
|
60
|
+
"lint-staged": "^16.1.0",
|
|
61
|
+
"tsx": "^4.7.0",
|
|
62
|
+
"turbo": "^2.5.8"
|
|
63
|
+
},
|
|
64
|
+
"volta": {
|
|
65
|
+
"node": "22.16.0",
|
|
66
|
+
"pnpm": "10.14.0"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"@hono/zod-validator": "^0.7.6",
|
|
70
|
+
"hono": "^4.11.3",
|
|
71
|
+
"zod": "^4.3.5"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -124,8 +124,8 @@ requirements:
|
|
|
124
124
|
"format:fix": "biome format --write ."
|
|
125
125
|
typecheck: "tsc --noEmit"
|
|
126
126
|
prepush: "{pm} run lint && {pm} run typecheck"
|
|
127
|
-
"task:loop": "npx @einja/dev-cli task:loop"
|
|
128
|
-
"einja:sync": "npx @einja/dev-cli sync"
|
|
127
|
+
"task:loop": "npx @einja/dev-cli@latest task:loop"
|
|
128
|
+
"einja:sync": "npx @einja/dev-cli@latest sync"
|
|
129
129
|
|
|
130
130
|
# システムコマンド(警告表示のみ、自動インストールしない)
|
|
131
131
|
systemCommands:
|
|
@@ -7,15 +7,34 @@ _SERENA_BASE="${1:-$(pwd)}"
|
|
|
7
7
|
_SERENA_PORT_FILE="$_SERENA_BASE/.serena-port"
|
|
8
8
|
_SERENA_DEFAULT_PORT="${SERENA_PORT:-9850}"
|
|
9
9
|
|
|
10
|
-
# ---
|
|
10
|
+
# --- ヘルパー関数 ---
|
|
11
|
+
_is_uint() {
|
|
12
|
+
case "$1" in
|
|
13
|
+
""|0|*[!0-9]*) return 1 ;;
|
|
14
|
+
*) return 0 ;;
|
|
15
|
+
esac
|
|
16
|
+
}
|
|
17
|
+
_escape_ere() {
|
|
18
|
+
printf '%s' "$1" | sed -e 's/[][(){}.^$*+?|\\]/\\&/g'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# --- 既存インスタンスチェック(PID×プロセス検証) ---
|
|
11
22
|
if [ -f "$_SERENA_PORT_FILE" ]; then
|
|
12
|
-
read -r _saved_port _saved_pid < "$_SERENA_PORT_FILE"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
IFS=' ' read -r _saved_port _saved_pid _rest < "$_SERENA_PORT_FILE" || true
|
|
24
|
+
|
|
25
|
+
if _is_uint "$_saved_pid" && _is_uint "$_saved_port"; then
|
|
26
|
+
_cmd="$(ps -p "$_saved_pid" -ww -o command= 2>/dev/null || true)"
|
|
27
|
+
_base_ere="$(_escape_ere "$_SERENA_BASE")"
|
|
28
|
+
|
|
29
|
+
if [ -n "$_cmd" ] \
|
|
30
|
+
&& printf '%s\n' "$_cmd" | grep -Eq -- "(^|[[:space:]])--project(=|[[:space:]])${_base_ere}([[:space:]]|$)"; then
|
|
31
|
+
# 自プロジェクトのSerenaプロセス → 再利用
|
|
32
|
+
export SERENA_PORT="$_saved_port"
|
|
33
|
+
return 0 2>/dev/null || true
|
|
34
|
+
fi
|
|
17
35
|
fi
|
|
18
|
-
|
|
36
|
+
|
|
37
|
+
# PID死亡 or 数値不正 or 別プロセス/別プロジェクトのSerena → クリーンアップ
|
|
19
38
|
rm -f "$_SERENA_PORT_FILE"
|
|
20
39
|
fi
|
|
21
40
|
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* バックアップ管理クラス
|
|
3
|
-
* 同期前のファイルバックアップとリストア機能を提供
|
|
4
|
-
*/
|
|
5
|
-
export declare class BackupManager {
|
|
6
|
-
private projectRoot;
|
|
7
|
-
private backupDir;
|
|
8
|
-
constructor(projectRoot: string);
|
|
9
|
-
/**
|
|
10
|
-
* バックアップディレクトリを作成する
|
|
11
|
-
*/
|
|
12
|
-
ensureBackupDir(): Promise<void>;
|
|
13
|
-
/**
|
|
14
|
-
* ファイルをバックアップする
|
|
15
|
-
* @param filePath - プロジェクトルートからの相対パス
|
|
16
|
-
* @returns バックアップファイルのパス
|
|
17
|
-
*/
|
|
18
|
-
backupFile(filePath: string): Promise<string>;
|
|
19
|
-
/**
|
|
20
|
-
* 複数のファイルをバックアップする
|
|
21
|
-
* @param filePaths - バックアップするファイルパスのリスト
|
|
22
|
-
* @returns バックアップファイルパスのマップ
|
|
23
|
-
*/
|
|
24
|
-
backupFiles(filePaths: string[]): Promise<Map<string, string>>;
|
|
25
|
-
/**
|
|
26
|
-
* バックアップファイルをリストアする
|
|
27
|
-
* @param backupPath - バックアップファイルのパス
|
|
28
|
-
* @param targetPath - リストア先のパス
|
|
29
|
-
*/
|
|
30
|
-
restoreFile(backupPath: string, targetPath: string): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* すべてのバックアップファイルをリストアする
|
|
33
|
-
* @param backupMap - backupFilesで取得したマップ
|
|
34
|
-
*/
|
|
35
|
-
restoreFiles(backupMap: Map<string, string>): Promise<void>;
|
|
36
|
-
/**
|
|
37
|
-
* 古いバックアップファイルをクリーンアップする
|
|
38
|
-
* @param maxAge - 保持する最大日数(デフォルト: 7日)
|
|
39
|
-
*/
|
|
40
|
-
cleanupOldBackups(maxAge?: number): Promise<number>;
|
|
41
|
-
/**
|
|
42
|
-
* すべてのバックアップファイルを削除する
|
|
43
|
-
*/
|
|
44
|
-
clearAllBackups(): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* バックアップディレクトリのパスを取得する
|
|
47
|
-
*/
|
|
48
|
-
getBackupDir(): string;
|
|
49
|
-
}
|
|
50
|
-
//# sourceMappingURL=backup-manager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"backup-manager.d.ts","sourceRoot":"","sources":["../../../src/lib/sync/backup-manager.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;gBAEd,WAAW,EAAE,MAAM;IAK/B;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;;;OAIG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBnD;;;;OAIG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAmBpE;;;;OAIG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxE;;;OAGG;IACG,YAAY,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjE;;;OAGG;IACG,iBAAiB,CAAC,MAAM,SAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBpD;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtC;;OAEG;IACH,YAAY,IAAI,MAAM;CAGvB"}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
/**
|
|
4
|
-
* バックアップ管理クラス
|
|
5
|
-
* 同期前のファイルバックアップとリストア機能を提供
|
|
6
|
-
*/
|
|
7
|
-
export class BackupManager {
|
|
8
|
-
constructor(projectRoot) {
|
|
9
|
-
this.projectRoot = projectRoot;
|
|
10
|
-
this.backupDir = path.join(projectRoot, ".einja-sync-backups");
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* バックアップディレクトリを作成する
|
|
14
|
-
*/
|
|
15
|
-
async ensureBackupDir() {
|
|
16
|
-
await fs.ensureDir(this.backupDir);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* ファイルをバックアップする
|
|
20
|
-
* @param filePath - プロジェクトルートからの相対パス
|
|
21
|
-
* @returns バックアップファイルのパス
|
|
22
|
-
*/
|
|
23
|
-
async backupFile(filePath) {
|
|
24
|
-
const sourcePath = path.join(this.projectRoot, filePath);
|
|
25
|
-
if (!(await fs.pathExists(sourcePath))) {
|
|
26
|
-
throw new Error(`バックアップ対象ファイルが存在しません: ${filePath}`);
|
|
27
|
-
}
|
|
28
|
-
await this.ensureBackupDir();
|
|
29
|
-
// バックアップファイル名:タイムスタンプ付き
|
|
30
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
31
|
-
const fileName = path.basename(filePath);
|
|
32
|
-
const backupFileName = `${fileName}.${timestamp}.bak`;
|
|
33
|
-
const backupPath = path.join(this.backupDir, backupFileName);
|
|
34
|
-
await fs.copy(sourcePath, backupPath);
|
|
35
|
-
return backupPath;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* 複数のファイルをバックアップする
|
|
39
|
-
* @param filePaths - バックアップするファイルパスのリスト
|
|
40
|
-
* @returns バックアップファイルパスのマップ
|
|
41
|
-
*/
|
|
42
|
-
async backupFiles(filePaths) {
|
|
43
|
-
const backupMap = new Map();
|
|
44
|
-
for (const filePath of filePaths) {
|
|
45
|
-
try {
|
|
46
|
-
const backupPath = await this.backupFile(filePath);
|
|
47
|
-
backupMap.set(filePath, backupPath);
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
// ファイルが存在しない場合はスキップ
|
|
51
|
-
if (error instanceof Error && error.message.includes("存在しません")) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return backupMap;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* バックアップファイルをリストアする
|
|
61
|
-
* @param backupPath - バックアップファイルのパス
|
|
62
|
-
* @param targetPath - リストア先のパス
|
|
63
|
-
*/
|
|
64
|
-
async restoreFile(backupPath, targetPath) {
|
|
65
|
-
if (!(await fs.pathExists(backupPath))) {
|
|
66
|
-
throw new Error(`バックアップファイルが存在しません: ${backupPath}`);
|
|
67
|
-
}
|
|
68
|
-
const targetFullPath = path.join(this.projectRoot, targetPath);
|
|
69
|
-
await fs.copy(backupPath, targetFullPath, { overwrite: true });
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* すべてのバックアップファイルをリストアする
|
|
73
|
-
* @param backupMap - backupFilesで取得したマップ
|
|
74
|
-
*/
|
|
75
|
-
async restoreFiles(backupMap) {
|
|
76
|
-
for (const [filePath, backupPath] of backupMap.entries()) {
|
|
77
|
-
await this.restoreFile(backupPath, filePath);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* 古いバックアップファイルをクリーンアップする
|
|
82
|
-
* @param maxAge - 保持する最大日数(デフォルト: 7日)
|
|
83
|
-
*/
|
|
84
|
-
async cleanupOldBackups(maxAge = 7) {
|
|
85
|
-
if (!(await fs.pathExists(this.backupDir))) {
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
88
|
-
const files = await fs.readdir(this.backupDir);
|
|
89
|
-
const now = Date.now();
|
|
90
|
-
const maxAgeMs = maxAge * 24 * 60 * 60 * 1000;
|
|
91
|
-
let deletedCount = 0;
|
|
92
|
-
for (const file of files) {
|
|
93
|
-
const filePath = path.join(this.backupDir, file);
|
|
94
|
-
const stat = await fs.stat(filePath);
|
|
95
|
-
if (now - stat.mtime.getTime() > maxAgeMs) {
|
|
96
|
-
await fs.remove(filePath);
|
|
97
|
-
deletedCount++;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return deletedCount;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* すべてのバックアップファイルを削除する
|
|
104
|
-
*/
|
|
105
|
-
async clearAllBackups() {
|
|
106
|
-
if (await fs.pathExists(this.backupDir)) {
|
|
107
|
-
await fs.remove(this.backupDir);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* バックアップディレクトリのパスを取得する
|
|
112
|
-
*/
|
|
113
|
-
getBackupDir() {
|
|
114
|
-
return this.backupDir;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
//# sourceMappingURL=backup-manager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"backup-manager.js","sourceRoot":"","sources":["../../../src/lib/sync/backup-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"backup-manager.test.d.ts","sourceRoot":"","sources":["../../../src/lib/sync/backup-manager.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import os from "node:os";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import fs from "fs-extra";
|
|
4
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
5
|
-
import { BackupManager } from "./backup-manager.js";
|
|
6
|
-
describe("BackupManager", () => {
|
|
7
|
-
let tempDir;
|
|
8
|
-
let manager;
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
// テスト用一時ディレクトリを作成
|
|
11
|
-
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "backup-test-"));
|
|
12
|
-
manager = new BackupManager(tempDir);
|
|
13
|
-
});
|
|
14
|
-
describe("backupFile", () => {
|
|
15
|
-
it("ファイルをバックアップディレクトリにコピーする", async () => {
|
|
16
|
-
const testFile = "test.txt";
|
|
17
|
-
const testContent = "Test content";
|
|
18
|
-
const testFilePath = path.join(tempDir, testFile);
|
|
19
|
-
// テストファイルを作成
|
|
20
|
-
await fs.writeFile(testFilePath, testContent, "utf-8");
|
|
21
|
-
// バックアップを実行
|
|
22
|
-
const backupPath = await manager.backupFile(testFile);
|
|
23
|
-
// バックアップファイルが存在することを確認
|
|
24
|
-
expect(await fs.pathExists(backupPath)).toBe(true);
|
|
25
|
-
// バックアップの内容が元のファイルと一致することを確認
|
|
26
|
-
const backupContent = await fs.readFile(backupPath, "utf-8");
|
|
27
|
-
expect(backupContent).toBe(testContent);
|
|
28
|
-
});
|
|
29
|
-
it("存在しないファイルをバックアップしようとした場合、エラーをスローする", async () => {
|
|
30
|
-
await expect(manager.backupFile("nonexistent.txt")).rejects.toThrow("バックアップ対象ファイルが存在しません");
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
describe("backupFiles", () => {
|
|
34
|
-
it("複数のファイルをバックアップする", async () => {
|
|
35
|
-
const files = ["file1.txt", "file2.txt"];
|
|
36
|
-
const content1 = "Content 1";
|
|
37
|
-
const content2 = "Content 2";
|
|
38
|
-
// テストファイルを作成
|
|
39
|
-
await fs.writeFile(path.join(tempDir, files[0]), content1, "utf-8");
|
|
40
|
-
await fs.writeFile(path.join(tempDir, files[1]), content2, "utf-8");
|
|
41
|
-
// バックアップを実行
|
|
42
|
-
const backupMap = await manager.backupFiles(files);
|
|
43
|
-
// 2つのファイルがバックアップされたことを確認
|
|
44
|
-
expect(backupMap.size).toBe(2);
|
|
45
|
-
expect(backupMap.has(files[0])).toBe(true);
|
|
46
|
-
expect(backupMap.has(files[1])).toBe(true);
|
|
47
|
-
// バックアップファイルの内容を確認
|
|
48
|
-
const backup1Content = await fs.readFile(backupMap.get(files[0]), "utf-8");
|
|
49
|
-
const backup2Content = await fs.readFile(backupMap.get(files[1]), "utf-8");
|
|
50
|
-
expect(backup1Content).toBe(content1);
|
|
51
|
-
expect(backup2Content).toBe(content2);
|
|
52
|
-
});
|
|
53
|
-
it("存在しないファイルはスキップする", async () => {
|
|
54
|
-
const files = ["exists.txt", "nonexistent.txt"];
|
|
55
|
-
await fs.writeFile(path.join(tempDir, files[0]), "Content", "utf-8");
|
|
56
|
-
// バックアップを実行(エラーにならず、存在するファイルのみバックアップ)
|
|
57
|
-
const backupMap = await manager.backupFiles(files);
|
|
58
|
-
expect(backupMap.size).toBe(1);
|
|
59
|
-
expect(backupMap.has(files[0])).toBe(true);
|
|
60
|
-
expect(backupMap.has(files[1])).toBe(false);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
describe("restoreFile", () => {
|
|
64
|
-
it("バックアップファイルをリストアする", async () => {
|
|
65
|
-
const originalFile = "test.txt";
|
|
66
|
-
const originalContent = "Original content";
|
|
67
|
-
const originalPath = path.join(tempDir, originalFile);
|
|
68
|
-
// 元のファイルを作成してバックアップ
|
|
69
|
-
await fs.writeFile(originalPath, originalContent, "utf-8");
|
|
70
|
-
const backupPath = await manager.backupFile(originalFile);
|
|
71
|
-
// 元のファイルを変更
|
|
72
|
-
await fs.writeFile(originalPath, "Modified content", "utf-8");
|
|
73
|
-
// リストアを実行
|
|
74
|
-
await manager.restoreFile(backupPath, originalFile);
|
|
75
|
-
// 元の内容に戻っていることを確認
|
|
76
|
-
const restoredContent = await fs.readFile(originalPath, "utf-8");
|
|
77
|
-
expect(restoredContent).toBe(originalContent);
|
|
78
|
-
});
|
|
79
|
-
it("バックアップファイルが存在しない場合、エラーをスローする", async () => {
|
|
80
|
-
await expect(manager.restoreFile("/nonexistent/backup.txt", "test.txt")).rejects.toThrow("バックアップファイルが存在しません");
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
describe("restoreFiles", () => {
|
|
84
|
-
it("複数のバックアップファイルをリストアする", async () => {
|
|
85
|
-
const files = ["file1.txt", "file2.txt"];
|
|
86
|
-
const originalContents = ["Content 1", "Content 2"];
|
|
87
|
-
// 元のファイルを作成してバックアップ
|
|
88
|
-
await fs.writeFile(path.join(tempDir, files[0]), originalContents[0], "utf-8");
|
|
89
|
-
await fs.writeFile(path.join(tempDir, files[1]), originalContents[1], "utf-8");
|
|
90
|
-
const backupMap = await manager.backupFiles(files);
|
|
91
|
-
// 元のファイルを変更
|
|
92
|
-
await fs.writeFile(path.join(tempDir, files[0]), "Modified 1", "utf-8");
|
|
93
|
-
await fs.writeFile(path.join(tempDir, files[1]), "Modified 2", "utf-8");
|
|
94
|
-
// リストアを実行
|
|
95
|
-
await manager.restoreFiles(backupMap);
|
|
96
|
-
// 両方のファイルが元の内容に戻っていることを確認
|
|
97
|
-
const restored1 = await fs.readFile(path.join(tempDir, files[0]), "utf-8");
|
|
98
|
-
const restored2 = await fs.readFile(path.join(tempDir, files[1]), "utf-8");
|
|
99
|
-
expect(restored1).toBe(originalContents[0]);
|
|
100
|
-
expect(restored2).toBe(originalContents[1]);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe("cleanupOldBackups", () => {
|
|
104
|
-
it("古いバックアップファイルを削除する", async () => {
|
|
105
|
-
const backupDir = manager.getBackupDir();
|
|
106
|
-
await fs.ensureDir(backupDir);
|
|
107
|
-
// 古いバックアップファイルを作成(8日前)
|
|
108
|
-
const oldBackup = path.join(backupDir, "old-backup.txt");
|
|
109
|
-
await fs.writeFile(oldBackup, "Old backup", "utf-8");
|
|
110
|
-
const oldDate = new Date();
|
|
111
|
-
oldDate.setDate(oldDate.getDate() - 8);
|
|
112
|
-
await fs.utimes(oldBackup, oldDate, oldDate);
|
|
113
|
-
// 新しいバックアップファイルを作成(今日)
|
|
114
|
-
const newBackup = path.join(backupDir, "new-backup.txt");
|
|
115
|
-
await fs.writeFile(newBackup, "New backup", "utf-8");
|
|
116
|
-
// クリーンアップを実行(7日より古いファイルを削除)
|
|
117
|
-
const deletedCount = await manager.cleanupOldBackups(7);
|
|
118
|
-
// 1ファイルが削除されたことを確認
|
|
119
|
-
expect(deletedCount).toBe(1);
|
|
120
|
-
// 古いファイルが削除され、新しいファイルは残っていることを確認
|
|
121
|
-
expect(await fs.pathExists(oldBackup)).toBe(false);
|
|
122
|
-
expect(await fs.pathExists(newBackup)).toBe(true);
|
|
123
|
-
});
|
|
124
|
-
it("バックアップディレクトリが存在しない場合、0を返す", async () => {
|
|
125
|
-
const deletedCount = await manager.cleanupOldBackups(7);
|
|
126
|
-
expect(deletedCount).toBe(0);
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
describe("clearAllBackups", () => {
|
|
130
|
-
it("すべてのバックアップファイルを削除する", async () => {
|
|
131
|
-
const backupDir = manager.getBackupDir();
|
|
132
|
-
// バックアップファイルを作成
|
|
133
|
-
const testFile = "test.txt";
|
|
134
|
-
await fs.writeFile(path.join(tempDir, testFile), "Content", "utf-8");
|
|
135
|
-
await manager.backupFile(testFile);
|
|
136
|
-
// バックアップディレクトリが存在することを確認
|
|
137
|
-
expect(await fs.pathExists(backupDir)).toBe(true);
|
|
138
|
-
// すべてのバックアップを削除
|
|
139
|
-
await manager.clearAllBackups();
|
|
140
|
-
// バックアップディレクトリが削除されたことを確認
|
|
141
|
-
expect(await fs.pathExists(backupDir)).toBe(false);
|
|
142
|
-
});
|
|
143
|
-
it("バックアップディレクトリが存在しない場合、エラーにならない", async () => {
|
|
144
|
-
// エラーなく実行できることを確認
|
|
145
|
-
await expect(manager.clearAllBackups()).resolves.toBeUndefined();
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
describe("getBackupDir", () => {
|
|
149
|
-
it("バックアップディレクトリのパスを返す", () => {
|
|
150
|
-
const backupDir = manager.getBackupDir();
|
|
151
|
-
expect(backupDir).toBe(path.join(tempDir, ".einja-sync-backups"));
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
//# sourceMappingURL=backup-manager.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"backup-manager.test.js","sourceRoot":"","sources":["../../../src/lib/sync/backup-manager.test.ts"],"names":[],"mappings":"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"}
|