tanmi-dock 0.10.0-beta → 1.0.4
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 +26 -5
- package/dist/commands/calibrate.d.ts +10 -0
- package/dist/commands/calibrate.d.ts.map +1 -0
- package/dist/commands/calibrate.js +158 -0
- package/dist/commands/calibrate.js.map +1 -0
- package/dist/commands/check.d.ts +45 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +322 -101
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/clean.d.ts +2 -6
- package/dist/commands/clean.d.ts.map +1 -1
- package/dist/commands/clean.js +224 -209
- package/dist/commands/clean.js.map +1 -1
- package/dist/commands/dashboard.d.ts.map +1 -1
- package/dist/commands/dashboard.js +56 -28
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/link.d.ts +8 -7
- package/dist/commands/link.d.ts.map +1 -1
- package/dist/commands/link.js +717 -221
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/migrate.d.ts +11 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +277 -57
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/reset.d.ts.map +1 -1
- package/dist/commands/reset.js +65 -41
- package/dist/commands/reset.js.map +1 -1
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +182 -40
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/unavailable.d.ts.map +1 -1
- package/dist/commands/unavailable.js +7 -2
- package/dist/commands/unavailable.js.map +1 -1
- package/dist/commands/unlink.d.ts.map +1 -1
- package/dist/commands/unlink.js +43 -39
- package/dist/commands/unlink.js.map +1 -1
- package/dist/core/codepac.d.ts +44 -0
- package/dist/core/codepac.d.ts.map +1 -1
- package/dist/core/codepac.js +287 -5
- package/dist/core/codepac.js.map +1 -1
- package/dist/core/config.d.ts +3 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +7 -3
- package/dist/core/config.js.map +1 -1
- package/dist/core/linker.d.ts +7 -0
- package/dist/core/linker.d.ts.map +1 -1
- package/dist/core/linker.js +47 -0
- package/dist/core/linker.js.map +1 -1
- package/dist/core/parser.d.ts +30 -5
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +376 -57
- package/dist/core/parser.js.map +1 -1
- package/dist/core/registry.d.ts +11 -29
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/registry.js +46 -113
- package/dist/core/registry.js.map +1 -1
- package/dist/core/space/calibration-executor.d.ts +16 -0
- package/dist/core/space/calibration-executor.d.ts.map +1 -0
- package/dist/core/space/calibration-executor.js +142 -0
- package/dist/core/space/calibration-executor.js.map +1 -0
- package/dist/core/space/calibration-planner.d.ts +5 -0
- package/dist/core/space/calibration-planner.d.ts.map +1 -0
- package/dist/core/space/calibration-planner.js +157 -0
- package/dist/core/space/calibration-planner.js.map +1 -0
- package/dist/core/space/cleanup-executor.d.ts +15 -0
- package/dist/core/space/cleanup-executor.d.ts.map +1 -0
- package/dist/core/space/cleanup-executor.js +188 -0
- package/dist/core/space/cleanup-executor.js.map +1 -0
- package/dist/core/space/cleanup-journal.d.ts +43 -0
- package/dist/core/space/cleanup-journal.d.ts.map +1 -0
- package/dist/core/space/cleanup-journal.js +96 -0
- package/dist/core/space/cleanup-journal.js.map +1 -0
- package/dist/core/space/cleanup-planner.d.ts +14 -0
- package/dist/core/space/cleanup-planner.d.ts.map +1 -0
- package/dist/core/space/cleanup-planner.js +166 -0
- package/dist/core/space/cleanup-planner.js.map +1 -0
- package/dist/core/space/cleanup-selection.d.ts +10 -0
- package/dist/core/space/cleanup-selection.d.ts.map +1 -0
- package/dist/core/space/cleanup-selection.js +84 -0
- package/dist/core/space/cleanup-selection.js.map +1 -0
- package/dist/core/space/estimator.d.ts +11 -0
- package/dist/core/space/estimator.d.ts.map +1 -0
- package/dist/core/space/estimator.js +142 -0
- package/dist/core/space/estimator.js.map +1 -0
- package/dist/core/space/inventory.d.ts +15 -0
- package/dist/core/space/inventory.d.ts.map +1 -0
- package/dist/core/space/inventory.js +587 -0
- package/dist/core/space/inventory.js.map +1 -0
- package/dist/core/space/meter.d.ts +5 -0
- package/dist/core/space/meter.d.ts.map +1 -0
- package/dist/core/space/meter.js +87 -0
- package/dist/core/space/meter.js.map +1 -0
- package/dist/core/space/migration-journal.d.ts +31 -0
- package/dist/core/space/migration-journal.d.ts.map +1 -0
- package/dist/core/space/migration-journal.js +121 -0
- package/dist/core/space/migration-journal.js.map +1 -0
- package/dist/core/space/service.d.ts +26 -0
- package/dist/core/space/service.d.ts.map +1 -0
- package/dist/core/space/service.js +54 -0
- package/dist/core/space/service.js.map +1 -0
- package/dist/core/space/types.d.ts +241 -0
- package/dist/core/space/types.d.ts.map +1 -0
- package/dist/core/space/types.js +13 -0
- package/dist/core/space/types.js.map +1 -0
- package/dist/core/store.d.ts +2 -0
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +44 -12
- package/dist/core/store.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +63 -10
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/atomic-file.d.ts +6 -0
- package/dist/utils/atomic-file.d.ts.map +1 -0
- package/dist/utils/atomic-file.js +37 -0
- package/dist/utils/atomic-file.js.map +1 -0
- package/dist/utils/fs-utils.d.ts +18 -1
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +150 -2
- package/dist/utils/fs-utils.js.map +1 -1
- package/dist/utils/git.d.ts +20 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +181 -4
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +2 -2
- package/dist/utils/prompt.d.ts.map +1 -1
- package/dist/utils/prompt.js +4 -4
- package/dist/utils/prompt.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/migrate.js
CHANGED
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
* migrate 命令 - 迁移 Store 位置
|
|
3
3
|
*/
|
|
4
4
|
import fs from 'fs/promises';
|
|
5
|
+
import os from 'os';
|
|
5
6
|
import path from 'path';
|
|
6
7
|
import { Command } from 'commander';
|
|
7
8
|
import { ensureInitialized } from '../core/guard.js';
|
|
8
9
|
import * as config from '../core/config.js';
|
|
9
10
|
import { getRegistry } from '../core/registry.js';
|
|
10
|
-
import
|
|
11
|
-
import { expandHome, shrinkHome, isPathSafe } from '../core/platform.js';
|
|
11
|
+
import { expandHome, shrinkHome, isPathSafe, pathsEqual } from '../core/platform.js';
|
|
12
12
|
import { formatSize, getFreeSpace } from '../utils/disk.js';
|
|
13
|
-
import { copyDirWithProgress } from '../utils/fs-utils.js';
|
|
13
|
+
import { copyDirWithProgress, rewriteInternalSymlinks, verifyCopiedDirectory, } from '../utils/fs-utils.js';
|
|
14
|
+
import { SpaceService, estimateMigrationSpace } from '../core/space/service.js';
|
|
15
|
+
import { MigrationJournal } from '../core/space/migration-journal.js';
|
|
14
16
|
import * as store from '../core/store.js';
|
|
15
|
-
import { info, success, warn, error, title, blank, separator, progressBar, } from '../utils/logger.js';
|
|
17
|
+
import { info, success, warn, error, title, blank, separator, progressBar, debug, } from '../utils/logger.js';
|
|
16
18
|
import { withGlobalLock } from '../utils/global-lock.js';
|
|
17
19
|
/**
|
|
18
20
|
* 创建 migrate 命令
|
|
@@ -34,11 +36,252 @@ export function createMigrateCommand() {
|
|
|
34
36
|
}
|
|
35
37
|
});
|
|
36
38
|
}
|
|
39
|
+
function isPathWithin(root, target) {
|
|
40
|
+
const relative = path.relative(path.resolve(root), path.resolve(target));
|
|
41
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
42
|
+
}
|
|
43
|
+
function isCatastrophicMigrationPath(targetPath) {
|
|
44
|
+
const resolved = path.resolve(targetPath);
|
|
45
|
+
return resolved === path.parse(resolved).root || pathsEqual(resolved, os.homedir());
|
|
46
|
+
}
|
|
47
|
+
function migrationCopyOptions(sourcePath, destinationPath) {
|
|
48
|
+
return {
|
|
49
|
+
preserveSymlinks: true,
|
|
50
|
+
rewriteInternalAbsoluteSymlinks: {
|
|
51
|
+
sourceRoot: sourcePath,
|
|
52
|
+
destinationRoot: destinationPath,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function destinationState(sourcePath, destinationPath) {
|
|
57
|
+
let entries;
|
|
58
|
+
try {
|
|
59
|
+
entries = await fs.readdir(destinationPath);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (err.code === 'ENOENT')
|
|
63
|
+
return 'missing';
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
if (entries.length === 0)
|
|
67
|
+
return 'empty';
|
|
68
|
+
const verification = await verifyCopiedDirectory(sourcePath, destinationPath, migrationCopyOptions(sourcePath, destinationPath));
|
|
69
|
+
return verification.valid ? 'valid' : 'conflict';
|
|
70
|
+
}
|
|
71
|
+
async function verifySourceIdentity(data) {
|
|
72
|
+
let stat;
|
|
73
|
+
try {
|
|
74
|
+
stat = await fs.stat(data.sourcePath);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
if (err.code === 'ENOENT')
|
|
78
|
+
return 'missing';
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
if (stat.dev !== data.sourceDevice || stat.ino !== data.sourceInode) {
|
|
82
|
+
throw new Error(`旧 Store 路径内容来源已变化,拒绝继续迁移: ${data.sourcePath}`);
|
|
83
|
+
}
|
|
84
|
+
return 'valid';
|
|
85
|
+
}
|
|
86
|
+
async function verifyDestinationAgainstSource(data, category) {
|
|
87
|
+
const verification = await verifyCopiedDirectory(data.sourcePath, data.destinationPath, migrationCopyOptions(data.sourcePath, data.destinationPath));
|
|
88
|
+
debug(`[migrate] 恢复目标验证: id=${data.id}, category=${category}, valid=${verification.valid}, error=${verification.error ?? 'none'}`);
|
|
89
|
+
if (!verification.valid) {
|
|
90
|
+
throw new Error(`迁移目标验证失败,已保留新旧目录: ${verification.error}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function verifyDestinationIdentity(data, category) {
|
|
94
|
+
if (!Number.isFinite(data.destinationDevice) || !Number.isFinite(data.destinationInode)) {
|
|
95
|
+
throw new Error(`迁移目标身份缺失,无法从 ${data.phase} 阶段恢复`);
|
|
96
|
+
}
|
|
97
|
+
const stat = await fs.stat(data.destinationPath).catch(() => null);
|
|
98
|
+
const valid = Boolean(stat?.isDirectory() && stat.dev === data.destinationDevice && stat.ino === data.destinationInode);
|
|
99
|
+
debug(`[migrate] 目标身份验证: id=${data.id}, category=${category}, valid=${valid}, expectedDevice=${data.destinationDevice}, expectedInode=${data.destinationInode}, actualDevice=${stat?.dev ?? 'missing'}, actualInode=${stat?.ino ?? 'missing'}`);
|
|
100
|
+
if (!valid) {
|
|
101
|
+
throw new Error(`迁移目标目录身份已变化,已保留迁移日志: ${data.destinationPath}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function verifyConfiguredDestination(data, category) {
|
|
105
|
+
const configuredStorePath = await config.getStorePath();
|
|
106
|
+
const valid = Boolean(configuredStorePath && pathsEqual(configuredStorePath, data.destinationPath));
|
|
107
|
+
debug(`[migrate] 目标配置验证: id=${data.id}, category=${category}, valid=${valid}, configured=${configuredStorePath ?? 'missing'}, destination=${data.destinationPath}`);
|
|
108
|
+
if (!valid) {
|
|
109
|
+
throw new Error(`迁移配置未指向目标 Store,已保留迁移日志: ${configuredStorePath ?? 'missing'}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async function executeMigrationJournal(journal, registry, knownRequiredSize) {
|
|
113
|
+
let data = journal.getData();
|
|
114
|
+
const { sourcePath, destinationPath, stagingPath } = data;
|
|
115
|
+
const destinationParent = path.dirname(destinationPath);
|
|
116
|
+
const expectedStagingPath = path.join(destinationParent, `.${path.basename(destinationPath)}.tanmi-dock-migrate-${data.id}`);
|
|
117
|
+
if (isCatastrophicMigrationPath(sourcePath) || isCatastrophicMigrationPath(destinationPath)) {
|
|
118
|
+
throw new Error('迁移日志不能指向文件系统根目录或用户主目录');
|
|
119
|
+
}
|
|
120
|
+
const configuredStorePath = await config.getStorePath();
|
|
121
|
+
if (!configuredStorePath ||
|
|
122
|
+
(!pathsEqual(configuredStorePath, sourcePath) &&
|
|
123
|
+
!pathsEqual(configuredStorePath, destinationPath))) {
|
|
124
|
+
throw new Error(`迁移日志与当前 Store 配置不一致: configured=${configuredStorePath ?? 'missing'}, source=${sourcePath}, destination=${destinationPath}`);
|
|
125
|
+
}
|
|
126
|
+
if (path.resolve(stagingPath) !== path.resolve(expectedStagingPath) ||
|
|
127
|
+
path.dirname(path.resolve(stagingPath)) !== path.resolve(destinationParent)) {
|
|
128
|
+
throw new Error(`迁移暂存目录无效: ${stagingPath}`);
|
|
129
|
+
}
|
|
130
|
+
if (isPathWithin(sourcePath, destinationPath) || isPathWithin(destinationPath, sourcePath)) {
|
|
131
|
+
throw new Error('迁移日志中的新旧 Store 目录互相包含');
|
|
132
|
+
}
|
|
133
|
+
debug(`[migrate] 恢复或执行迁移: id=${data.id}, phase=${data.phase}, source=${sourcePath}, destination=${destinationPath}, staging=${stagingPath}, keepOld=${data.keepOld}`);
|
|
134
|
+
const sourceIdentity = await verifySourceIdentity(data);
|
|
135
|
+
if (sourceIdentity === 'missing') {
|
|
136
|
+
if (data.phase === 'linksUpdated' && !data.keepOld) {
|
|
137
|
+
// 删除源目录后、记录 sourceRemoved 前发生中断时,只能依据持久目标身份继续。
|
|
138
|
+
await verifyDestinationIdentity(data, 'source-missing-after-removal');
|
|
139
|
+
await verifyConfiguredDestination(data, 'source-missing-after-removal');
|
|
140
|
+
await journal.update('sourceRemoved');
|
|
141
|
+
data = journal.getData();
|
|
142
|
+
}
|
|
143
|
+
else if (data.phase !== 'sourceRemoved') {
|
|
144
|
+
if (data.keepOld && data.phase === 'sourcePreserved') {
|
|
145
|
+
throw new Error(`迁移要求保留旧 Store,但旧目录不存在: ${sourcePath}`);
|
|
146
|
+
}
|
|
147
|
+
throw new Error(`旧 Store 不存在,无法从 ${data.phase} 阶段恢复: ${sourcePath}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (sourceIdentity === 'valid' &&
|
|
151
|
+
['promoted', 'configSwitched', 'linksUpdating', 'linksUpdated', 'sourcePreserved'].includes(data.phase)) {
|
|
152
|
+
await verifyDestinationIdentity(data, `resume-${data.phase}`);
|
|
153
|
+
await verifyDestinationAgainstSource(data, `resume-${data.phase}`);
|
|
154
|
+
}
|
|
155
|
+
if (data.phase === 'prepared' || data.phase === 'copying') {
|
|
156
|
+
const estimate = knownRequiredSize == null ? await estimateMigrationSpace(sourcePath) : null;
|
|
157
|
+
const requiredSize = knownRequiredSize ?? estimate?.amount?.bytes;
|
|
158
|
+
if (requiredSize == null || estimate?.status === 'unknown') {
|
|
159
|
+
throw new Error(`无法恢复迁移复制: ${estimate?.warnings.join('; ') || '容量未知'}`);
|
|
160
|
+
}
|
|
161
|
+
const freeSpace = await getFreeSpace(destinationParent);
|
|
162
|
+
debug(`[migrate] 恢复复制空间检查: id=${data.id}, required=${requiredSize}, available=${freeSpace}`);
|
|
163
|
+
if (freeSpace < requiredSize) {
|
|
164
|
+
throw new Error(`恢复迁移时目标空间不足: 需要 ${formatSize(requiredSize)},可用 ${formatSize(freeSpace)}`);
|
|
165
|
+
}
|
|
166
|
+
await fs.rm(stagingPath, { recursive: true, force: true });
|
|
167
|
+
await journal.update('copying');
|
|
168
|
+
info('[1/3] 复制文件到迁移暂存目录...');
|
|
169
|
+
await copyDirWithProgress(sourcePath, stagingPath, requiredSize, (copied, total) => progressBar(copied, total), migrationCopyOptions(sourcePath, destinationPath));
|
|
170
|
+
if (requiredSize > 0)
|
|
171
|
+
progressBar(requiredSize, requiredSize);
|
|
172
|
+
const verification = await verifyCopiedDirectory(sourcePath, stagingPath, migrationCopyOptions(sourcePath, destinationPath));
|
|
173
|
+
debug(`[migrate] 暂存复制验证返回: id=${data.id}, valid=${verification.valid}, error=${verification.error ?? 'none'}`);
|
|
174
|
+
if (!verification.valid)
|
|
175
|
+
throw new Error(`迁移复制验证失败: ${verification.error}`);
|
|
176
|
+
await journal.update('copied');
|
|
177
|
+
data = journal.getData();
|
|
178
|
+
}
|
|
179
|
+
if (data.phase === 'copied' || data.phase === 'promoting') {
|
|
180
|
+
await journal.update('promoting');
|
|
181
|
+
const state = await destinationState(sourcePath, destinationPath);
|
|
182
|
+
debug(`[migrate] 目标目录状态: id=${data.id}, state=${state}, destination=${destinationPath}`);
|
|
183
|
+
if (state === 'conflict') {
|
|
184
|
+
throw new Error(`迁移目标包含非本次复制内容,已保留现场: ${destinationPath}`);
|
|
185
|
+
}
|
|
186
|
+
if (state !== 'valid') {
|
|
187
|
+
if (state === 'empty')
|
|
188
|
+
await fs.rmdir(destinationPath);
|
|
189
|
+
await fs.rename(stagingPath, destinationPath);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
await fs.rm(stagingPath, { recursive: true, force: true });
|
|
193
|
+
}
|
|
194
|
+
const destinationStat = await fs.stat(destinationPath);
|
|
195
|
+
if (!destinationStat.isDirectory()) {
|
|
196
|
+
throw new Error(`迁移目标不是目录,无法记录目标身份: ${destinationPath}`);
|
|
197
|
+
}
|
|
198
|
+
await journal.markPromoted(destinationStat.dev, destinationStat.ino);
|
|
199
|
+
data = journal.getData();
|
|
200
|
+
}
|
|
201
|
+
if (data.phase === 'promoted') {
|
|
202
|
+
await config.setStorePath(destinationPath);
|
|
203
|
+
await journal.update('configSwitched');
|
|
204
|
+
data = journal.getData();
|
|
205
|
+
debug(`[migrate] 配置切换完成: id=${data.id}, store=${destinationPath}`);
|
|
206
|
+
}
|
|
207
|
+
if (data.phase === 'configSwitched' || data.phase === 'linksUpdating') {
|
|
208
|
+
await journal.update('linksUpdating');
|
|
209
|
+
info('[2/3] 更新项目符号链接...');
|
|
210
|
+
let updatedLinkCount = 0;
|
|
211
|
+
for (const project of registry.listProjects()) {
|
|
212
|
+
let updatedCount = 0;
|
|
213
|
+
const visited = new Set();
|
|
214
|
+
for (const dep of project.dependencies) {
|
|
215
|
+
const localPath = path.join(project.path, dep.linkedPath);
|
|
216
|
+
if (visited.has(localPath))
|
|
217
|
+
continue;
|
|
218
|
+
visited.add(localPath);
|
|
219
|
+
const count = await rewriteInternalSymlinks(localPath, sourcePath, destinationPath);
|
|
220
|
+
updatedCount += count;
|
|
221
|
+
updatedLinkCount += count;
|
|
222
|
+
}
|
|
223
|
+
success(` [ok] ${shrinkHome(project.path)} (${updatedCount} 个链接)`);
|
|
224
|
+
}
|
|
225
|
+
await journal.update('linksUpdated');
|
|
226
|
+
data = journal.getData();
|
|
227
|
+
debug(`[migrate] 项目链接更新完成: id=${data.id}, updatedLinks=${updatedLinkCount}`);
|
|
228
|
+
}
|
|
229
|
+
if (data.phase === 'linksUpdated') {
|
|
230
|
+
await verifyDestinationIdentity(data, 'before-source-handling');
|
|
231
|
+
await verifyDestinationAgainstSource(data, 'before-source-removal');
|
|
232
|
+
await verifySourceIdentity(data);
|
|
233
|
+
await verifyConfiguredDestination(data, 'before-source-handling');
|
|
234
|
+
info(data.keepOld ? '[3/3] 保留旧目录' : '[3/3] 清理旧目录...');
|
|
235
|
+
if (data.keepOld) {
|
|
236
|
+
await journal.update('sourcePreserved');
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
await fs.rm(sourcePath, { recursive: true, force: true });
|
|
240
|
+
await journal.update('sourceRemoved');
|
|
241
|
+
}
|
|
242
|
+
data = journal.getData();
|
|
243
|
+
debug(`[migrate] 旧目录处理完成: id=${data.id}, keepOld=${data.keepOld}, source=${sourcePath}`);
|
|
244
|
+
}
|
|
245
|
+
if (data.phase === 'sourcePreserved' || data.phase === 'sourceRemoved') {
|
|
246
|
+
await verifyDestinationIdentity(data, 'before-completion');
|
|
247
|
+
await verifyConfiguredDestination(data, 'before-completion');
|
|
248
|
+
const finalSourceIdentity = await verifySourceIdentity(data);
|
|
249
|
+
if (data.phase === 'sourcePreserved') {
|
|
250
|
+
if (!data.keepOld || finalSourceIdentity !== 'valid') {
|
|
251
|
+
throw new Error(`迁移未满足保留旧 Store 的完成条件: ${sourcePath}`);
|
|
252
|
+
}
|
|
253
|
+
await verifyDestinationAgainstSource(data, 'before-completion');
|
|
254
|
+
}
|
|
255
|
+
else if (data.keepOld || finalSourceIdentity !== 'missing') {
|
|
256
|
+
throw new Error(`迁移未满足删除旧 Store 的完成条件: ${sourcePath}`);
|
|
257
|
+
}
|
|
258
|
+
await journal.complete();
|
|
259
|
+
success('迁移完成');
|
|
260
|
+
debug(`[migrate] 迁移日志完成: id=${data.id}, destination=${destinationPath}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/** 恢复上次进程中断留下的迁移。 */
|
|
264
|
+
export async function recoverPendingMigrations(registry) {
|
|
265
|
+
const pending = await MigrationJournal.listPending();
|
|
266
|
+
if (pending.length > 1) {
|
|
267
|
+
throw new Error(`发现 ${pending.length} 个待恢复迁移,拒绝猜测执行顺序`);
|
|
268
|
+
}
|
|
269
|
+
if (pending.length === 0)
|
|
270
|
+
return 0;
|
|
271
|
+
const journal = pending[0];
|
|
272
|
+
const data = journal.getData();
|
|
273
|
+
warn(`发现待恢复迁移 (${data.id.slice(0, 8)}),从 ${data.phase} 阶段继续`);
|
|
274
|
+
await executeMigrationJournal(journal, registry);
|
|
275
|
+
return 1;
|
|
276
|
+
}
|
|
37
277
|
/**
|
|
38
278
|
* 迁移 Store
|
|
39
279
|
*/
|
|
40
|
-
async function migrateStore(newPath, options) {
|
|
280
|
+
export async function migrateStore(newPath, options) {
|
|
41
281
|
const absoluteNewPath = expandHome(newPath);
|
|
282
|
+
const registry = getRegistry();
|
|
283
|
+
await registry.load();
|
|
284
|
+
await recoverPendingMigrations(registry);
|
|
42
285
|
// 安全检查
|
|
43
286
|
const safetyResult = isPathSafe(absoluteNewPath);
|
|
44
287
|
if (!safetyResult.safe) {
|
|
@@ -46,23 +289,44 @@ async function migrateStore(newPath, options) {
|
|
|
46
289
|
process.exit(1);
|
|
47
290
|
}
|
|
48
291
|
const oldPath = await store.getStorePath();
|
|
49
|
-
|
|
292
|
+
const oldResolved = path.resolve(oldPath);
|
|
293
|
+
const newResolved = path.resolve(absoluteNewPath);
|
|
294
|
+
if (newResolved === oldResolved) {
|
|
50
295
|
warn('新路径与当前路径相同');
|
|
51
296
|
return;
|
|
52
297
|
}
|
|
298
|
+
if (isPathWithin(oldResolved, newResolved) || isPathWithin(newResolved, oldResolved)) {
|
|
299
|
+
throw new Error('新旧 Store 目录不能互相包含');
|
|
300
|
+
}
|
|
53
301
|
title('迁移 Store');
|
|
54
302
|
blank();
|
|
55
303
|
// 获取当前 Store 信息
|
|
56
304
|
const libraries = await store.listLibraries();
|
|
57
|
-
const
|
|
58
|
-
|
|
305
|
+
const snapshot = await new SpaceService(registry, oldPath).buildSnapshot('summary');
|
|
306
|
+
const migrationEstimate = await estimateMigrationSpace(oldPath);
|
|
307
|
+
if (migrationEstimate.status === 'unknown' || !migrationEstimate.amount) {
|
|
308
|
+
throw new Error(`无法估算迁移空间: ${migrationEstimate.warnings.join('; ')}`);
|
|
309
|
+
}
|
|
310
|
+
const actualSize = snapshot.totals.physical.bytes;
|
|
311
|
+
const requiredSize = migrationEstimate.amount.bytes;
|
|
312
|
+
for (const warningMessage of migrationEstimate.warnings)
|
|
313
|
+
warn(`迁移提示: ${warningMessage}`);
|
|
314
|
+
for (const evidence of migrationEstimate.evidence)
|
|
315
|
+
debug(`[migrate] 容量依据: ${evidence}`);
|
|
316
|
+
info(`当前位置: ${shrinkHome(oldPath)} (实际占用 ${formatSize(actualSize)}, ${libraries.length} 个库)`);
|
|
59
317
|
info(`目标位置: ${shrinkHome(absoluteNewPath)}`);
|
|
318
|
+
info(`预计复制: ${formatSize(requiredSize)} (保留符号链接)`);
|
|
319
|
+
debug(`[migrate] 空间计算完成: source=${oldPath}, destination=${absoluteNewPath}, snapshot=${snapshot.id}, actual=${actualSize}, required=${requiredSize}, basis=${migrationEstimate.amount.basis}, quality=${migrationEstimate.amount.quality}`);
|
|
60
320
|
blank();
|
|
61
321
|
// 检查目标路径
|
|
62
322
|
info('检查:');
|
|
63
323
|
// 检查可写性
|
|
64
324
|
try {
|
|
65
325
|
await fs.mkdir(absoluteNewPath, { recursive: true });
|
|
326
|
+
const existingEntries = await fs.readdir(absoluteNewPath);
|
|
327
|
+
if (existingEntries.length > 0) {
|
|
328
|
+
throw new Error(`目标目录必须为空,当前包含 ${existingEntries.length} 个项目`);
|
|
329
|
+
}
|
|
66
330
|
success(' [ok] 目标路径可写');
|
|
67
331
|
}
|
|
68
332
|
catch (err) {
|
|
@@ -71,14 +335,12 @@ async function migrateStore(newPath, options) {
|
|
|
71
335
|
}
|
|
72
336
|
// 检查空间
|
|
73
337
|
const freeSpace = await getFreeSpace(absoluteNewPath);
|
|
74
|
-
if (freeSpace <
|
|
75
|
-
error(` [err] 目标空间不足 (需要 ${formatSize(
|
|
338
|
+
if (freeSpace < requiredSize) {
|
|
339
|
+
error(` [err] 目标空间不足 (需要 ${formatSize(requiredSize)}, 可用 ${formatSize(freeSpace)})`);
|
|
76
340
|
process.exit(1);
|
|
77
341
|
}
|
|
78
342
|
success(` [ok] 目标空间充足 (${formatSize(freeSpace)} 可用)`);
|
|
79
343
|
// 获取需要更新的项目
|
|
80
|
-
const registry = getRegistry();
|
|
81
|
-
await registry.load();
|
|
82
344
|
const projects = registry.listProjects();
|
|
83
345
|
info(` [info] ${projects.length} 个项目的符号链接需要更新`);
|
|
84
346
|
blank();
|
|
@@ -86,52 +348,10 @@ async function migrateStore(newPath, options) {
|
|
|
86
348
|
warn('使用 --force 选项确认迁移');
|
|
87
349
|
return;
|
|
88
350
|
}
|
|
89
|
-
//
|
|
351
|
+
// 执行迁移。复制、配置切换、链接更新和旧目录清理均由日志驱动。
|
|
90
352
|
separator();
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
await copyDirWithProgress(oldPath, absoluteNewPath, totalSize, (copied, total) => {
|
|
94
|
-
progressBar(copied, total);
|
|
95
|
-
});
|
|
96
|
-
// 确保进度条完成
|
|
97
|
-
if (totalSize > 0) {
|
|
98
|
-
progressBar(totalSize, totalSize);
|
|
99
|
-
}
|
|
100
|
-
// 2. 更新符号链接
|
|
101
|
-
info('[2/3] 更新符号链接...');
|
|
102
|
-
for (const project of projects) {
|
|
103
|
-
let updatedCount = 0;
|
|
104
|
-
for (const dep of project.dependencies) {
|
|
105
|
-
const localPath = path.join(project.path, dep.linkedPath);
|
|
106
|
-
// 使用依赖记录的平台,或项目的第一个平台
|
|
107
|
-
const migratePlatform = dep.platform ?? project.platforms?.[0] ?? 'macOS';
|
|
108
|
-
const newStorePath = store.getLibraryPath(absoluteNewPath, dep.libName, dep.commit, migratePlatform);
|
|
109
|
-
if (await linker.isSymlink(localPath)) {
|
|
110
|
-
await linker.unlink(localPath);
|
|
111
|
-
await linker.link(newStorePath, localPath);
|
|
112
|
-
updatedCount++;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
success(` [ok] ${shrinkHome(project.path)} (${updatedCount} 个链接)`);
|
|
116
|
-
}
|
|
117
|
-
// 3. 更新配置
|
|
118
|
-
await config.setStorePath(absoluteNewPath);
|
|
119
|
-
// 4. 清理旧目录
|
|
120
|
-
if (!options.keepOld) {
|
|
121
|
-
info('[3/3] 清理旧目录...');
|
|
122
|
-
try {
|
|
123
|
-
await fs.rm(oldPath, { recursive: true, force: true });
|
|
124
|
-
success(` [ok] 已删除 ${shrinkHome(oldPath)}`);
|
|
125
|
-
}
|
|
126
|
-
catch (err) {
|
|
127
|
-
warn(` [warn] 删除旧目录失败: ${err.message}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
info('[3/3] 保留旧目录');
|
|
132
|
-
}
|
|
133
|
-
blank();
|
|
134
|
-
success('迁移完成');
|
|
353
|
+
const journal = await MigrationJournal.create(oldPath, absoluteNewPath, options.keepOld);
|
|
354
|
+
await executeMigrationJournal(journal, registry, requiredSize);
|
|
135
355
|
}
|
|
136
356
|
export default createMigrateCommand;
|
|
137
357
|
//# sourceMappingURL=migrate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../src/commands/reset.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../src/commands/reset.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAaD,wBAAgB,kBAAkB,IAAI,OAAO,CA6B5C;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAwEf;AAkPD,eAAe,kBAAkB,CAAC"}
|
package/dist/commands/reset.js
CHANGED
|
@@ -7,13 +7,14 @@ import { Command } from 'commander';
|
|
|
7
7
|
import { ensureInitialized } from '../core/guard.js';
|
|
8
8
|
import { getRegistry } from '../core/registry.js';
|
|
9
9
|
import { getStorePath } from '../core/config.js';
|
|
10
|
-
import { findCodepacConfig, parseCodepacDep, extractDependencies, extractActions,
|
|
11
|
-
import { shrinkHome } from '../core/platform.js';
|
|
10
|
+
import { findCodepacConfig, parseCodepacDep, extractDependencies, extractActions, buildActionExecutionPlan, extractNestedDependencies, resolveProjectRootPath } from '../core/parser.js';
|
|
11
|
+
import { getBaseKeyForCodepac, shrinkHome } from '../core/platform.js';
|
|
12
12
|
import { isSymlink } from '../core/linker.js';
|
|
13
|
+
import { SpaceService } from '../core/space/service.js';
|
|
13
14
|
import { withGlobalLock } from '../utils/global-lock.js';
|
|
14
15
|
import { findSubmoduleConfigs } from '../utils/git.js';
|
|
15
16
|
import { confirmAction, PROMPT_CANCELLED } from '../utils/prompt.js';
|
|
16
|
-
import { info, warn, success, error, blank, separator } from '../utils/logger.js';
|
|
17
|
+
import { info, warn, success, error, blank, separator, debug } from '../utils/logger.js';
|
|
17
18
|
export function createResetCommand() {
|
|
18
19
|
return new Command('reset')
|
|
19
20
|
.description('重置指定库的缓存与元数据,便于重新干净拉取')
|
|
@@ -76,9 +77,25 @@ export async function resetLibrary(libName, commit, options, currentPath) {
|
|
|
76
77
|
if (!storePath) {
|
|
77
78
|
throw new Error('Store 路径未配置,请先运行 tanmi-dock init');
|
|
78
79
|
}
|
|
80
|
+
debug(`[reset] 开始重置: source=${projectRoot ?? 'global'}, targets=${targets.length}, affectedProjects=${affectedProjects.length}, store=${storePath}`);
|
|
81
|
+
const spaceService = new SpaceService(registry, storePath);
|
|
82
|
+
const executor = spaceService.createCleanupExecutor();
|
|
83
|
+
const recovered = await executor.recoverPending();
|
|
84
|
+
debug(`[reset] 清理日志恢复完成: recovered=${recovered}`);
|
|
79
85
|
await cleanupProjectLinks(affectedProjects);
|
|
80
86
|
removeProjectDependencyMetadata(registry, targets, affectedProjects);
|
|
81
|
-
await
|
|
87
|
+
const plan = await spaceService.buildCleanupPlan({
|
|
88
|
+
reason: 'reset',
|
|
89
|
+
selections: targets.map((target) => ({ id: target, platforms: 'all' })),
|
|
90
|
+
requireUnreferenced: false,
|
|
91
|
+
allowUnknownContent: true,
|
|
92
|
+
});
|
|
93
|
+
debug(`[reset] 调用统一清理执行器: plan=${plan.id}, groups=${plan.groups.length}, expected=${plan.expectedRelease.bytes}`);
|
|
94
|
+
const cleanupResult = await executor.execute(plan);
|
|
95
|
+
debug(`[reset] 清理执行返回: plan=${plan.id}, status=${cleanupResult.status}, succeeded=${cleanupResult.succeeded.length}, failed=${cleanupResult.failed.length}, released=${cleanupResult.released.bytes}`);
|
|
96
|
+
if (cleanupResult.status !== 'completed') {
|
|
97
|
+
throw new Error(`Store 重置未完整完成: ${cleanupResult.failed.map((item) => item.message).join('; ')}`);
|
|
98
|
+
}
|
|
82
99
|
await registry.save();
|
|
83
100
|
blank();
|
|
84
101
|
separator();
|
|
@@ -118,28 +135,41 @@ async function collectProjectTargets(registry, projectRoot, libName) {
|
|
|
118
135
|
const projectHash = registry.hashPath(projectRoot);
|
|
119
136
|
const project = registry.getProject(projectHash);
|
|
120
137
|
if (project) {
|
|
121
|
-
|
|
138
|
+
const registryTargets = project.dependencies
|
|
122
139
|
.filter((dep) => dep.libName === libName)
|
|
123
140
|
.map((dep) => ({ libName: dep.libName, commit: dep.commit }));
|
|
141
|
+
if (registryTargets.length > 0) {
|
|
142
|
+
return registryTargets;
|
|
143
|
+
}
|
|
144
|
+
return collectTargetsFromConfigs(projectRoot, libName, project.platforms ?? []);
|
|
124
145
|
}
|
|
125
146
|
return collectTargetsFromConfigs(projectRoot, libName);
|
|
126
147
|
}
|
|
127
|
-
async function collectTargetsFromConfigs(projectRoot, libName) {
|
|
148
|
+
async function collectTargetsFromConfigs(projectRoot, libName, platforms = []) {
|
|
128
149
|
const configPath = await findCodepacConfig(projectRoot);
|
|
129
150
|
if (!configPath)
|
|
130
151
|
return [];
|
|
152
|
+
const codepacPlatforms = [...new Set(platforms.map((platform) => getBaseKeyForCodepac(platform)))];
|
|
131
153
|
const targets = [];
|
|
132
154
|
const visited = new Set();
|
|
133
|
-
const queue = [
|
|
134
|
-
|
|
155
|
+
const queue = [
|
|
156
|
+
{ configPath, targetDir: path.dirname(configPath), codepacPlatforms },
|
|
157
|
+
];
|
|
158
|
+
const submodules = await findSubmoduleConfigs(projectRoot, '', 0, codepacPlatforms);
|
|
135
159
|
for (const submodule of submodules) {
|
|
136
|
-
queue.push(
|
|
160
|
+
queue.push({
|
|
161
|
+
configPath: submodule.configPath,
|
|
162
|
+
targetDir: path.dirname(submodule.configPath),
|
|
163
|
+
codepacPlatforms,
|
|
164
|
+
});
|
|
137
165
|
}
|
|
138
166
|
while (queue.length > 0) {
|
|
139
|
-
const
|
|
140
|
-
|
|
167
|
+
const current = queue.shift();
|
|
168
|
+
const currentConfig = current.configPath;
|
|
169
|
+
const visitKey = buildResetActionVisitKey(currentConfig, current.targetDir);
|
|
170
|
+
if (visited.has(visitKey))
|
|
141
171
|
continue;
|
|
142
|
-
visited.add(
|
|
172
|
+
visited.add(visitKey);
|
|
143
173
|
let parsed;
|
|
144
174
|
try {
|
|
145
175
|
parsed = await parseCodepacDep(currentConfig);
|
|
@@ -147,28 +177,41 @@ async function collectTargetsFromConfigs(projectRoot, libName) {
|
|
|
147
177
|
catch {
|
|
148
178
|
continue;
|
|
149
179
|
}
|
|
150
|
-
|
|
180
|
+
const extractOptions = { platforms: current.codepacPlatforms, configPath: currentConfig };
|
|
181
|
+
for (const dep of extractDependencies(parsed, extractOptions)) {
|
|
151
182
|
if (dep.libName === libName) {
|
|
152
183
|
targets.push({ libName: dep.libName, commit: dep.commit });
|
|
153
184
|
}
|
|
154
185
|
}
|
|
155
|
-
for (const action of extractActions(parsed)) {
|
|
156
|
-
let
|
|
186
|
+
for (const action of extractActions(parsed, extractOptions)) {
|
|
187
|
+
let plan;
|
|
157
188
|
try {
|
|
158
|
-
|
|
189
|
+
plan = buildActionExecutionPlan(action, {
|
|
190
|
+
parentConfigPath: currentConfig,
|
|
191
|
+
parentTargetDir: current.targetDir,
|
|
192
|
+
inheritedCodepacPlatforms: current.codepacPlatforms,
|
|
193
|
+
});
|
|
159
194
|
}
|
|
160
195
|
catch {
|
|
161
196
|
continue;
|
|
162
197
|
}
|
|
163
|
-
const nestedConfigPath = path.resolve(path.dirname(currentConfig), parsedAction.configDir, 'codepac-dep.json');
|
|
164
198
|
try {
|
|
165
|
-
const nested = await extractNestedDependencies(nestedConfigPath,
|
|
199
|
+
const nested = await extractNestedDependencies(plan.nestedConfigPath, plan.libraries, {
|
|
200
|
+
platforms: plan.effectiveCodepacPlatforms,
|
|
201
|
+
configPath: plan.nestedConfigPath,
|
|
202
|
+
});
|
|
166
203
|
for (const dep of nested.dependencies) {
|
|
167
204
|
if (dep.libName === libName) {
|
|
168
205
|
targets.push({ libName: dep.libName, commit: dep.commit });
|
|
169
206
|
}
|
|
170
207
|
}
|
|
171
|
-
|
|
208
|
+
if (!plan.parsed.disableAction) {
|
|
209
|
+
queue.push({
|
|
210
|
+
configPath: plan.nestedConfigPath,
|
|
211
|
+
targetDir: plan.nestedTargetDir,
|
|
212
|
+
codepacPlatforms: plan.effectiveCodepacPlatforms,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
172
215
|
}
|
|
173
216
|
catch {
|
|
174
217
|
continue;
|
|
@@ -177,6 +220,9 @@ async function collectTargetsFromConfigs(projectRoot, libName) {
|
|
|
177
220
|
}
|
|
178
221
|
return targets;
|
|
179
222
|
}
|
|
223
|
+
function buildResetActionVisitKey(configPath, targetDir) {
|
|
224
|
+
return `${configPath}::${targetDir}`;
|
|
225
|
+
}
|
|
180
226
|
function dedupeTargets(targets) {
|
|
181
227
|
const seen = new Set();
|
|
182
228
|
return targets.filter((target) => {
|
|
@@ -254,27 +300,5 @@ function removeProjectDependencyMetadata(registry, targets, projectMatches) {
|
|
|
254
300
|
registry.updateProject(match.projectHash, { dependencies: remaining });
|
|
255
301
|
}
|
|
256
302
|
}
|
|
257
|
-
async function removeStoreAndRegistryData(registry, storePath, targets) {
|
|
258
|
-
for (const target of targets) {
|
|
259
|
-
const storeKeys = registry.getLibraryStoreKeys(target.libName, target.commit);
|
|
260
|
-
for (const storeKey of storeKeys) {
|
|
261
|
-
registry.removeStore(storeKey);
|
|
262
|
-
}
|
|
263
|
-
const libKey = registry.getLibraryKey(target.libName, target.commit);
|
|
264
|
-
registry.removeLibrary(libKey);
|
|
265
|
-
const commitPath = path.join(storePath, target.libName, target.commit);
|
|
266
|
-
await fs.rm(commitPath, { recursive: true, force: true }).catch(() => { });
|
|
267
|
-
const libPath = path.join(storePath, target.libName);
|
|
268
|
-
try {
|
|
269
|
-
const entries = await fs.readdir(libPath);
|
|
270
|
-
if (entries.length === 0) {
|
|
271
|
-
await fs.rm(libPath, { recursive: true, force: true });
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
catch {
|
|
275
|
-
// ignore
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
303
|
export default createResetCommand;
|
|
280
304
|
//# sourceMappingURL=reset.js.map
|