tanmi-dock 0.9.0 → 0.9.3
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/dist/commands/link.d.ts +27 -1
- package/dist/commands/link.d.ts.map +1 -1
- package/dist/commands/link.js +470 -297
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/reset.d.ts +9 -0
- package/dist/commands/reset.d.ts.map +1 -0
- package/dist/commands/reset.js +280 -0
- package/dist/commands/reset.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +34 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/unavailable.d.ts +7 -0
- package/dist/commands/unavailable.d.ts.map +1 -0
- package/dist/commands/unavailable.js +202 -0
- package/dist/commands/unavailable.js.map +1 -0
- package/dist/commands/unlink.d.ts.map +1 -1
- package/dist/commands/unlink.js +8 -4
- package/dist/commands/unlink.js.map +1 -1
- package/dist/core/codepac.d.ts +3 -1
- package/dist/core/codepac.d.ts.map +1 -1
- package/dist/core/codepac.js +5 -4
- package/dist/core/codepac.js.map +1 -1
- package/dist/core/linker.d.ts +6 -0
- package/dist/core/linker.d.ts.map +1 -1
- package/dist/core/linker.js +26 -1
- package/dist/core/linker.js.map +1 -1
- package/dist/core/parser.d.ts +10 -0
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +18 -0
- package/dist/core/parser.js.map +1 -1
- package/dist/core/platform.d.ts +4 -0
- package/dist/core/platform.d.ts.map +1 -1
- package/dist/core/platform.js +52 -0
- package/dist/core/platform.js.map +1 -1
- package/dist/core/registry.d.ts +16 -0
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/registry.js +66 -1
- package/dist/core/registry.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/utils/prompt.d.ts +12 -0
- package/dist/utils/prompt.d.ts.map +1 -1
- package/dist/utils/prompt.js +102 -0
- package/dist/utils/prompt.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/doctor.d.ts +0 -7
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -178
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/projects.d.ts +0 -7
- package/dist/commands/projects.d.ts.map +0 -1
- package/dist/commands/projects.js +0 -126
- package/dist/commands/projects.js.map +0 -1
- package/dist/commands/repair.d.ts +0 -16
- package/dist/commands/repair.d.ts.map +0 -1
- package/dist/commands/repair.js +0 -364
- package/dist/commands/repair.js.map +0 -1
- package/dist/commands/verify.d.ts +0 -11
- package/dist/commands/verify.d.ts.map +0 -1
- package/dist/commands/verify.js +0 -266
- package/dist/commands/verify.js.map +0 -1
package/dist/commands/link.js
CHANGED
|
@@ -7,13 +7,13 @@ import { Command } from 'commander';
|
|
|
7
7
|
import { ensureInitialized } from '../core/guard.js';
|
|
8
8
|
import * as config from '../core/config.js';
|
|
9
9
|
import { setLogLevel } from '../utils/logger.js';
|
|
10
|
-
import { parseProjectDependencies, getRelativeConfigPath, parseCodepacDep, extractActions, parseActionCommand, extractNestedDependencies,
|
|
10
|
+
import { parseProjectDependencies, getRelativeConfigPath, parseCodepacDep, extractActions, parseActionCommand, extractNestedDependencies, findAllCodepacConfigs, extractDependencies, resolveProjectRootPath, } from '../core/parser.js';
|
|
11
11
|
import { getRegistry } from '../core/registry.js';
|
|
12
12
|
import * as store from '../core/store.js';
|
|
13
13
|
import * as linker from '../core/linker.js';
|
|
14
14
|
import * as codepac from '../core/codepac.js';
|
|
15
15
|
import { setProxyConfig } from '../core/codepac.js';
|
|
16
|
-
import {
|
|
16
|
+
import { getPlatformHelpText, GENERAL_PLATFORM, SHARED_PLATFORM, pathsEqual, isSparseOnlyCommon, KNOWN_PLATFORM_VALUES, getRequestedPlatformTargets, } from '../core/platform.js';
|
|
17
17
|
import { Transaction } from '../core/transaction.js';
|
|
18
18
|
import { formatSize, checkDiskSpace } from '../utils/disk.js';
|
|
19
19
|
import { getDirSize } from '../utils/fs-utils.js';
|
|
@@ -60,6 +60,181 @@ export function createLinkCommand() {
|
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
+
function resolveRequestedPlatformsByActual(requestedPlatforms, sparse, actualPlatforms, vars) {
|
|
64
|
+
const actualExisting = [...new Set(actualPlatforms)];
|
|
65
|
+
const actualPlatformSet = new Set(actualExisting);
|
|
66
|
+
const satisfiedRequested = requestedPlatforms.filter((requestedPlatform) => {
|
|
67
|
+
const targets = getRequestedPlatformTargets(requestedPlatform, sparse, vars);
|
|
68
|
+
return targets.some((target) => actualPlatformSet.has(target));
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
actualExisting,
|
|
72
|
+
satisfiedRequested,
|
|
73
|
+
missingRequested: requestedPlatforms.filter((platform) => !satisfiedRequested.includes(platform)),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export function assessDownloadResult(requestedPlatforms, sparse, downloadResult, vars) {
|
|
77
|
+
const downloadedActual = new Set(downloadResult.platformDirs);
|
|
78
|
+
const { satisfiedRequested, missingRequested, } = resolveRequestedPlatformsByActual(requestedPlatforms, sparse, downloadResult.platformDirs, vars);
|
|
79
|
+
const downloadedRequested = [...new Set(satisfiedRequested.flatMap((requestedPlatform) => getRequestedPlatformTargets(requestedPlatform, sparse, vars)
|
|
80
|
+
.filter((target) => downloadedActual.has(target))))];
|
|
81
|
+
const unavailableRequested = missingRequested;
|
|
82
|
+
const hasAnyPlatformArtifacts = downloadResult.allPlatformDirs.length > 0;
|
|
83
|
+
const isPureGeneral = Boolean((!sparse || isSparseOnlyCommon(sparse)) &&
|
|
84
|
+
!hasAnyPlatformArtifacts);
|
|
85
|
+
return {
|
|
86
|
+
downloadedRequested,
|
|
87
|
+
satisfiedRequested,
|
|
88
|
+
unavailableRequested,
|
|
89
|
+
hasAnyPlatformArtifacts,
|
|
90
|
+
isPureGeneral,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function resolveRequestedStoreState(dependency, requestedPlatforms, vars) {
|
|
94
|
+
const resolvedExisting = [];
|
|
95
|
+
const candidatePlatforms = [...new Set(requestedPlatforms.flatMap((platform) => getRequestedPlatformTargets(platform, dependency.sparse, vars)))];
|
|
96
|
+
for (const platform of candidatePlatforms) {
|
|
97
|
+
if (await store.exists(dependency.libName, dependency.commit, platform)) {
|
|
98
|
+
resolvedExisting.push(platform);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return resolveRequestedPlatformsByActual(requestedPlatforms, dependency.sparse, resolvedExisting, vars);
|
|
102
|
+
}
|
|
103
|
+
function getBlockedRequestedPlatforms(registry, dependency, requestedPlatforms, vars) {
|
|
104
|
+
const { manualPlatforms, autoPlatforms } = resolveUnavailablePlatforms(registry, dependency);
|
|
105
|
+
const manualBlocked = requestedPlatforms.filter((platform) => manualPlatforms.includes(platform));
|
|
106
|
+
const autoBlocked = requestedPlatforms.filter((platform) => {
|
|
107
|
+
if (!autoPlatforms.includes(platform))
|
|
108
|
+
return false;
|
|
109
|
+
const targets = getRequestedPlatformTargets(platform, dependency.sparse, vars);
|
|
110
|
+
return targets.length === 1 && targets[0] === platform;
|
|
111
|
+
});
|
|
112
|
+
return [...new Set([...manualBlocked, ...autoBlocked])];
|
|
113
|
+
}
|
|
114
|
+
function clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested) {
|
|
115
|
+
if (satisfiedRequested.length === 0)
|
|
116
|
+
return;
|
|
117
|
+
const libKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
118
|
+
const library = registry.getLibrary(libKey);
|
|
119
|
+
if (!library?.unavailablePlatforms || library.unavailablePlatforms.length === 0)
|
|
120
|
+
return;
|
|
121
|
+
const nextUnavailable = library.unavailablePlatforms.filter((platform) => !satisfiedRequested.includes(platform));
|
|
122
|
+
if (nextUnavailable.length === library.unavailablePlatforms.length) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
registry.updateLibrary(libKey, {
|
|
126
|
+
unavailablePlatforms: nextUnavailable,
|
|
127
|
+
lastAccess: new Date().toISOString(),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function upsertLibraryAvailability(dependency, updates) {
|
|
131
|
+
const registry = getRegistry();
|
|
132
|
+
const libKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
133
|
+
const existing = registry.getLibrary(libKey);
|
|
134
|
+
if (existing) {
|
|
135
|
+
registry.updateLibrary(libKey, {
|
|
136
|
+
unavailablePlatforms: updates.unavailablePlatforms ?? existing.unavailablePlatforms,
|
|
137
|
+
platforms: updates.platforms ?? existing.platforms,
|
|
138
|
+
isGeneral: updates.isGeneral ?? existing.isGeneral,
|
|
139
|
+
lastAccess: new Date().toISOString(),
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
registry.addLibrary({
|
|
144
|
+
libName: dependency.libName,
|
|
145
|
+
commit: dependency.commit,
|
|
146
|
+
branch: dependency.branch,
|
|
147
|
+
url: dependency.url,
|
|
148
|
+
platforms: updates.platforms ?? [],
|
|
149
|
+
size: 0,
|
|
150
|
+
isGeneral: updates.isGeneral,
|
|
151
|
+
referencedBy: [],
|
|
152
|
+
unavailablePlatforms: updates.unavailablePlatforms,
|
|
153
|
+
createdAt: new Date().toISOString(),
|
|
154
|
+
lastAccess: new Date().toISOString(),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
export async function resolveLibraryGeneralState(dependency) {
|
|
158
|
+
const registry = getRegistry();
|
|
159
|
+
const libKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
160
|
+
const library = registry.getLibrary(libKey);
|
|
161
|
+
if (typeof library?.isGeneral === 'boolean') {
|
|
162
|
+
return library.isGeneral;
|
|
163
|
+
}
|
|
164
|
+
return store.isGeneralLib(dependency.libName, dependency.commit);
|
|
165
|
+
}
|
|
166
|
+
export function resolveUnavailablePlatforms(registry, dependency) {
|
|
167
|
+
const libKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
168
|
+
const autoPlatforms = registry.getLibrary(libKey)?.unavailablePlatforms || [];
|
|
169
|
+
const manualPlatforms = registry.getManualUnavailablePlatforms(dependency.libName, dependency.commit);
|
|
170
|
+
return {
|
|
171
|
+
platforms: [...new Set([...manualPlatforms, ...autoPlatforms])],
|
|
172
|
+
manualPlatforms,
|
|
173
|
+
autoPlatforms,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
export async function collectProjectDependencyGraph(projectRoot) {
|
|
177
|
+
const { normalizedPath, configPath } = await resolveProjectRootPath(projectRoot);
|
|
178
|
+
if (!configPath) {
|
|
179
|
+
throw new Error('只能在项目目录下使用');
|
|
180
|
+
}
|
|
181
|
+
const results = [];
|
|
182
|
+
const seenDeps = new Set();
|
|
183
|
+
const visitedConfigs = new Set();
|
|
184
|
+
const queue = [
|
|
185
|
+
{ configPath, source: 'direct' },
|
|
186
|
+
];
|
|
187
|
+
const submodules = await findSubmoduleConfigs(normalizedPath);
|
|
188
|
+
for (const submodule of submodules) {
|
|
189
|
+
queue.push({ configPath: submodule.configPath, scope: submodule.relativePath, source: 'submodule' });
|
|
190
|
+
}
|
|
191
|
+
while (queue.length > 0) {
|
|
192
|
+
const current = queue.shift();
|
|
193
|
+
if (visitedConfigs.has(current.configPath))
|
|
194
|
+
continue;
|
|
195
|
+
visitedConfigs.add(current.configPath);
|
|
196
|
+
let parsedConfig;
|
|
197
|
+
try {
|
|
198
|
+
parsedConfig = await parseCodepacDep(current.configPath);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
for (const dependency of extractDependencies(parsedConfig)) {
|
|
204
|
+
const key = `${dependency.libName}:${dependency.commit}:${current.scope ?? ''}`;
|
|
205
|
+
if (!seenDeps.has(key)) {
|
|
206
|
+
seenDeps.add(key);
|
|
207
|
+
results.push({ ...dependency, scope: current.scope, source: current.source });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
for (const action of extractActions(parsedConfig)) {
|
|
211
|
+
let parsedAction;
|
|
212
|
+
try {
|
|
213
|
+
parsedAction = parseActionCommand(action.command);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const nestedConfigPath = path.resolve(path.dirname(current.configPath), parsedAction.configDir, 'codepac-dep.json');
|
|
219
|
+
let nested;
|
|
220
|
+
try {
|
|
221
|
+
nested = await extractNestedDependencies(nestedConfigPath, parsedAction.libraries);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
for (const dependency of nested.dependencies) {
|
|
227
|
+
const key = `${dependency.libName}:${dependency.commit}:${current.scope ?? ''}`;
|
|
228
|
+
if (!seenDeps.has(key)) {
|
|
229
|
+
seenDeps.add(key);
|
|
230
|
+
results.push({ ...dependency, scope: current.scope, source: 'nested' });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
queue.push({ configPath: nestedConfigPath, scope: current.scope, source: 'nested' });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return results;
|
|
237
|
+
}
|
|
63
238
|
/**
|
|
64
239
|
* 选择要链接的 submodule
|
|
65
240
|
*/
|
|
@@ -144,7 +319,7 @@ async function linkScope(params) {
|
|
|
144
319
|
blank();
|
|
145
320
|
// 2. 分类依赖
|
|
146
321
|
const scopePath = path.dirname(path.dirname(configPath));
|
|
147
|
-
const classified = await classifyDependencies(dependencies, scopePath, configPath, platforms);
|
|
322
|
+
const classified = await classifyDependencies(dependencies, scopePath, configPath, platforms, configVars);
|
|
148
323
|
const stats = {
|
|
149
324
|
linked: 0, relink: 0, replace: 0, absorb: 0, missing: 0, linkNew: 0,
|
|
150
325
|
};
|
|
@@ -223,13 +398,21 @@ async function linkScope(params) {
|
|
|
223
398
|
const needDownloadItems = [];
|
|
224
399
|
for (const item of classified) {
|
|
225
400
|
const { dependency, status } = item;
|
|
401
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
402
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
226
403
|
if (status === DependencyStatus.MISSING) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
404
|
+
if (requestedPlatforms.length > 0) {
|
|
405
|
+
const { missingRequested } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
406
|
+
if (missingRequested.length === 0) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
needDownloadItems.push({
|
|
410
|
+
libName: dependency.libName, commit: dependency.commit, reason: '缺失',
|
|
411
|
+
});
|
|
412
|
+
}
|
|
230
413
|
}
|
|
231
414
|
else if (status === DependencyStatus.ABSORB) {
|
|
232
|
-
const { missing } = await
|
|
415
|
+
const { missingRequested: missing } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
233
416
|
if (missing.length > 0) {
|
|
234
417
|
needDownloadItems.push({
|
|
235
418
|
libName: dependency.libName, commit: dependency.commit,
|
|
@@ -238,7 +421,7 @@ async function linkScope(params) {
|
|
|
238
421
|
}
|
|
239
422
|
}
|
|
240
423
|
else if (status === DependencyStatus.LINK_NEW) {
|
|
241
|
-
const { missing } = await
|
|
424
|
+
const { missingRequested: missing } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
242
425
|
if (missing.length > 0) {
|
|
243
426
|
needDownloadItems.push({
|
|
244
427
|
libName: dependency.libName, commit: dependency.commit,
|
|
@@ -280,54 +463,62 @@ async function linkScope(params) {
|
|
|
280
463
|
await store.ensureCompatibleStore(storePath, dependency.libName, dependency.commit);
|
|
281
464
|
switch (status) {
|
|
282
465
|
case DependencyStatus.LINKED: {
|
|
283
|
-
const
|
|
466
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
467
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
468
|
+
const isLinkedGeneral = await resolveLibraryGeneralState(dependency);
|
|
284
469
|
if (!isLinkedGeneral) {
|
|
285
470
|
const supplementResult = await supplementMissingPlatforms(dependency, platforms, registry, tx, { vars: configVars });
|
|
286
471
|
await registerNestedLibraries(supplementResult.nestedLibraries, projectHash);
|
|
287
472
|
if (supplementResult.downloaded.length > 0) {
|
|
288
473
|
const linkedCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
289
|
-
const {
|
|
474
|
+
const { actualExisting: allExisting, satisfiedRequested } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
475
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
290
476
|
tx.recordOp('link', localPath, linkedCommitPath);
|
|
291
477
|
await linker.linkLib(localPath, linkedCommitPath, allExisting);
|
|
292
|
-
|
|
293
|
-
const storeKey = registry.getStoreKey(dependency.libName, dependency.commit, platform);
|
|
294
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
295
|
-
}
|
|
478
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, allExisting, projectHash, false);
|
|
296
479
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已补充平台 [${supplementResult.downloaded.join(', ')}]`);
|
|
297
480
|
}
|
|
298
481
|
}
|
|
482
|
+
const { actualExisting: linkedExisting, satisfiedRequested } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
483
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
484
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, isLinkedGeneral ? [GENERAL_PLATFORM] : linkedExisting, projectHash, isLinkedGeneral);
|
|
299
485
|
break;
|
|
300
486
|
}
|
|
301
487
|
case DependencyStatus.RELINK: {
|
|
488
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
489
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
302
490
|
const relinkCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
303
|
-
const isRelinkGeneral = await
|
|
491
|
+
const isRelinkGeneral = await resolveLibraryGeneralState(dependency);
|
|
304
492
|
if (isRelinkGeneral) {
|
|
305
493
|
tx.recordOp('unlink', localPath);
|
|
306
494
|
await linker.unlink(localPath);
|
|
307
495
|
const sharedPath = path.join(relinkCommitPath, '_shared');
|
|
308
496
|
tx.recordOp('link', localPath, sharedPath);
|
|
309
497
|
await linker.linkGeneral(localPath, sharedPath);
|
|
498
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, [GENERAL_PLATFORM], projectHash, true);
|
|
310
499
|
generalLibs.add(dependency.libName);
|
|
311
500
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - General 库,重建链接`);
|
|
312
501
|
}
|
|
313
502
|
else {
|
|
314
503
|
const relinkSupplementResult = await supplementMissingPlatforms(dependency, platforms, registry, tx, { vars: configVars });
|
|
315
504
|
await registerNestedLibraries(relinkSupplementResult.nestedLibraries, projectHash);
|
|
316
|
-
const {
|
|
505
|
+
const { actualExisting: relinkExisting, satisfiedRequested, } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
506
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
317
507
|
if (relinkExisting.length === 0) {
|
|
318
508
|
const { KNOWN_PLATFORM_VALUES } = await import('../core/platform.js');
|
|
319
509
|
const relinkCommitEntries = await fs.readdir(relinkCommitPath, { withFileTypes: true });
|
|
320
510
|
const relinkAvailablePlatforms = relinkCommitEntries
|
|
321
511
|
.filter(e => e.isDirectory() && e.name !== '_shared' && KNOWN_PLATFORM_VALUES.includes(e.name))
|
|
322
512
|
.map(e => e.name);
|
|
323
|
-
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) -
|
|
513
|
+
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已按规则跳过平台 [${platforms.join('/')}], 可用平台 [${relinkAvailablePlatforms.join(', ')}]`);
|
|
324
514
|
const relinkLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
325
515
|
const relinkLib = registry.getLibrary(relinkLibKey);
|
|
326
516
|
if (relinkLib) {
|
|
327
517
|
const unavailable = relinkLib.unavailablePlatforms || [];
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
518
|
+
const missingRequested = resolveRequestedPlatformsByActual(requestedPlatforms, dependency.sparse, relinkAvailablePlatforms, configVars).missingRequested;
|
|
519
|
+
for (const requestedPlatform of missingRequested) {
|
|
520
|
+
if (!unavailable.includes(requestedPlatform))
|
|
521
|
+
unavailable.push(requestedPlatform);
|
|
331
522
|
}
|
|
332
523
|
registry.updateLibrary(relinkLibKey, { unavailablePlatforms: unavailable });
|
|
333
524
|
}
|
|
@@ -337,10 +528,7 @@ async function linkScope(params) {
|
|
|
337
528
|
await linker.unlink(localPath);
|
|
338
529
|
tx.recordOp('link', localPath, relinkCommitPath);
|
|
339
530
|
await linker.linkLib(localPath, relinkCommitPath, relinkExisting);
|
|
340
|
-
|
|
341
|
-
const storeKey = registry.getStoreKey(dependency.libName, dependency.commit, platform);
|
|
342
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
343
|
-
}
|
|
531
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, relinkExisting, projectHash, false);
|
|
344
532
|
if (relinkSupplementResult.downloaded.length > 0) {
|
|
345
533
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 重建链接并补充平台 [${relinkExisting.join(', ')}]`);
|
|
346
534
|
}
|
|
@@ -351,35 +539,40 @@ async function linkScope(params) {
|
|
|
351
539
|
break;
|
|
352
540
|
}
|
|
353
541
|
case DependencyStatus.REPLACE: {
|
|
542
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
543
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
354
544
|
const replaceSize = await getDirSize(localPath);
|
|
355
545
|
const replaceCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
356
|
-
const isReplaceGeneral = await
|
|
546
|
+
const isReplaceGeneral = await resolveLibraryGeneralState(dependency);
|
|
357
547
|
if (isReplaceGeneral) {
|
|
358
548
|
const sharedPath = path.join(replaceCommitPath, '_shared');
|
|
359
549
|
tx.recordOp('replace', localPath, sharedPath);
|
|
360
550
|
await linker.linkGeneral(localPath, sharedPath);
|
|
361
551
|
savedBytes += replaceSize;
|
|
552
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, [GENERAL_PLATFORM], projectHash, true);
|
|
362
553
|
generalLibs.add(dependency.libName);
|
|
363
554
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - General 库,创建链接`);
|
|
364
555
|
}
|
|
365
556
|
else {
|
|
366
557
|
const replaceSupplementResult = await supplementMissingPlatforms(dependency, platforms, registry, tx, { vars: configVars });
|
|
367
558
|
await registerNestedLibraries(replaceSupplementResult.nestedLibraries, projectHash);
|
|
368
|
-
const {
|
|
559
|
+
const { actualExisting: replaceExisting, satisfiedRequested, } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
560
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
369
561
|
if (replaceExisting.length === 0) {
|
|
370
562
|
const { KNOWN_PLATFORM_VALUES } = await import('../core/platform.js');
|
|
371
563
|
const replaceCommitEntries = await fs.readdir(replaceCommitPath, { withFileTypes: true });
|
|
372
564
|
const replaceAvailablePlatforms = replaceCommitEntries
|
|
373
565
|
.filter(e => e.isDirectory() && e.name !== '_shared' && KNOWN_PLATFORM_VALUES.includes(e.name))
|
|
374
566
|
.map(e => e.name);
|
|
375
|
-
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) -
|
|
567
|
+
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已按规则跳过平台 [${platforms.join('/')}], 可用平台 [${replaceAvailablePlatforms.join(', ')}]`);
|
|
376
568
|
const replaceLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
377
569
|
const replaceLib = registry.getLibrary(replaceLibKey);
|
|
378
570
|
if (replaceLib) {
|
|
379
571
|
const unavailable = replaceLib.unavailablePlatforms || [];
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
572
|
+
const missingRequested = resolveRequestedPlatformsByActual(requestedPlatforms, dependency.sparse, replaceAvailablePlatforms, configVars).missingRequested;
|
|
573
|
+
for (const requestedPlatform of missingRequested) {
|
|
574
|
+
if (!unavailable.includes(requestedPlatform))
|
|
575
|
+
unavailable.push(requestedPlatform);
|
|
383
576
|
}
|
|
384
577
|
registry.updateLibrary(replaceLibKey, { unavailablePlatforms: unavailable });
|
|
385
578
|
}
|
|
@@ -388,10 +581,7 @@ async function linkScope(params) {
|
|
|
388
581
|
tx.recordOp('replace', localPath, replaceCommitPath);
|
|
389
582
|
await linker.linkLib(localPath, replaceCommitPath, replaceExisting);
|
|
390
583
|
savedBytes += replaceSize;
|
|
391
|
-
|
|
392
|
-
const storeKey = registry.getStoreKey(dependency.libName, dependency.commit, platform);
|
|
393
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
394
|
-
}
|
|
584
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, replaceExisting, projectHash, false);
|
|
395
585
|
if (replaceSupplementResult.downloaded.length > 0) {
|
|
396
586
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - Store 已有,创建链接并补充平台 [${replaceExisting.join(', ')}]`);
|
|
397
587
|
}
|
|
@@ -402,22 +592,26 @@ async function linkScope(params) {
|
|
|
402
592
|
break;
|
|
403
593
|
}
|
|
404
594
|
case DependencyStatus.ABSORB: {
|
|
595
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
596
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
405
597
|
const storeCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
406
598
|
const { KNOWN_PLATFORM_VALUES } = await import('../core/platform.js');
|
|
407
599
|
const localDirEntries = await fs.readdir(localPath, { withFileTypes: true });
|
|
408
600
|
const localPlatforms = localDirEntries
|
|
409
601
|
.filter(entry => entry.isDirectory() && KNOWN_PLATFORM_VALUES.includes(entry.name))
|
|
410
602
|
.map(entry => entry.name);
|
|
411
|
-
const
|
|
603
|
+
const requestedTargets = [...new Set(requestedPlatforms.flatMap((platform) => getRequestedPlatformTargets(platform, dependency.sparse, configVars)))];
|
|
604
|
+
const finalPlatforms = localPlatforms.filter((platform) => requestedTargets.includes(platform));
|
|
412
605
|
if (finalPlatforms.length === 0 && localPlatforms.length > 0) {
|
|
413
|
-
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) -
|
|
606
|
+
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已按规则跳过平台 [${platforms.join('/')}], 本地有 [${localPlatforms.join(', ')}]`);
|
|
414
607
|
const absorbLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
415
608
|
const absorbLib = registry.getLibrary(absorbLibKey);
|
|
416
609
|
if (absorbLib) {
|
|
417
610
|
const unavailable = absorbLib.unavailablePlatforms || [];
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
611
|
+
const missingRequested = resolveRequestedPlatformsByActual(requestedPlatforms, dependency.sparse, localPlatforms, configVars).missingRequested;
|
|
612
|
+
for (const requestedPlatform of missingRequested) {
|
|
613
|
+
if (!unavailable.includes(requestedPlatform))
|
|
614
|
+
unavailable.push(requestedPlatform);
|
|
421
615
|
}
|
|
422
616
|
registry.updateLibrary(absorbLibKey, { unavailablePlatforms: unavailable });
|
|
423
617
|
}
|
|
@@ -448,6 +642,7 @@ async function linkScope(params) {
|
|
|
448
642
|
registry.addLibrary({
|
|
449
643
|
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
450
644
|
url: dependency.url, platforms: absorbLinkPlatforms, size: absorbSize,
|
|
645
|
+
isGeneral: false,
|
|
451
646
|
referencedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
452
647
|
});
|
|
453
648
|
}
|
|
@@ -511,6 +706,7 @@ async function linkScope(params) {
|
|
|
511
706
|
registry.addLibrary({
|
|
512
707
|
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
513
708
|
url: dependency.url, platforms: [GENERAL_PLATFORM], size: sharedSize,
|
|
709
|
+
isGeneral: true,
|
|
514
710
|
referencedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
515
711
|
});
|
|
516
712
|
}
|
|
@@ -527,7 +723,9 @@ async function linkScope(params) {
|
|
|
527
723
|
break;
|
|
528
724
|
case DependencyStatus.LINK_NEW: {
|
|
529
725
|
const linkNewCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
530
|
-
const
|
|
726
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
727
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
728
|
+
const { missingRequested: missing } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
531
729
|
const linkNewLibId = `${dependency.libName}@${dependency.commit}`;
|
|
532
730
|
if (missing.length > 0 && !skipAllDownloads && downloadConfirmedLibs.has(linkNewLibId)) {
|
|
533
731
|
info(`${dependency.libName} 缺少平台 [${missing.join(', ')}],开始下载...`);
|
|
@@ -552,7 +750,9 @@ async function linkScope(params) {
|
|
|
552
750
|
hint(` 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
553
751
|
}
|
|
554
752
|
try {
|
|
555
|
-
const
|
|
753
|
+
const assessment = assessDownloadResult(missing, dependency.sparse, downloadResult, configVars);
|
|
754
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, assessment.satisfiedRequested);
|
|
755
|
+
const filteredDownloaded = assessment.downloadedRequested;
|
|
556
756
|
if (filteredDownloaded.length > 0) {
|
|
557
757
|
tx.recordOp('absorb', linkNewCommitPath, downloadResult.libDir);
|
|
558
758
|
const linkNewAbsorbResult = await store.absorbLib(downloadResult.libDir, filteredDownloaded, dependency.libName, dependency.commit);
|
|
@@ -563,27 +763,14 @@ async function linkScope(params) {
|
|
|
563
763
|
await fs.rm(downloadResult.tempDir, { recursive: true, force: true }).catch(() => { });
|
|
564
764
|
}
|
|
565
765
|
}
|
|
566
|
-
const {
|
|
567
|
-
|
|
766
|
+
const { actualExisting: linkNewExisting, satisfiedRequested, } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
767
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
768
|
+
const isLinkNewGeneral = await resolveLibraryGeneralState(dependency);
|
|
568
769
|
if (isLinkNewGeneral) {
|
|
569
770
|
const sharedPath = path.join(linkNewCommitPath, '_shared');
|
|
570
771
|
tx.recordOp('link', localPath, sharedPath);
|
|
571
772
|
await linker.linkGeneral(localPath, sharedPath);
|
|
572
|
-
|
|
573
|
-
const existingEntry = registry.getStore(storeKey);
|
|
574
|
-
if (!existingEntry) {
|
|
575
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, GENERAL_PLATFORM);
|
|
576
|
-
registry.addStore({
|
|
577
|
-
libName: dependency.libName, commit: dependency.commit, platform: GENERAL_PLATFORM,
|
|
578
|
-
branch: dependency.branch, url: dependency.url, ...integrity,
|
|
579
|
-
usedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
else if (existingEntry.fileCount == null) {
|
|
583
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, GENERAL_PLATFORM);
|
|
584
|
-
registry.updateStore(storeKey, integrity);
|
|
585
|
-
}
|
|
586
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
773
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, [GENERAL_PLATFORM], projectHash, true);
|
|
587
774
|
generalLibs.add(dependency.libName);
|
|
588
775
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - General 库,创建链接`);
|
|
589
776
|
}
|
|
@@ -598,9 +785,10 @@ async function linkScope(params) {
|
|
|
598
785
|
const lnLib = registry.getLibrary(lnLibKey);
|
|
599
786
|
if (lnLib) {
|
|
600
787
|
const unavailable = lnLib.unavailablePlatforms || [];
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
788
|
+
const missingRequested = resolveRequestedPlatformsByActual(requestedPlatforms, dependency.sparse, availablePlatforms, configVars).missingRequested;
|
|
789
|
+
for (const requestedPlatform of missingRequested) {
|
|
790
|
+
if (!unavailable.includes(requestedPlatform))
|
|
791
|
+
unavailable.push(requestedPlatform);
|
|
604
792
|
}
|
|
605
793
|
registry.updateLibrary(lnLibKey, { unavailablePlatforms: unavailable });
|
|
606
794
|
}
|
|
@@ -609,29 +797,15 @@ async function linkScope(params) {
|
|
|
609
797
|
else {
|
|
610
798
|
tx.recordOp('link', localPath, linkNewCommitPath);
|
|
611
799
|
await linker.linkLib(localPath, linkNewCommitPath, linkNewExisting);
|
|
612
|
-
|
|
613
|
-
const storeKey = registry.getStoreKey(dependency.libName, dependency.commit, platform);
|
|
614
|
-
const existingPlatformEntry = registry.getStore(storeKey);
|
|
615
|
-
if (!existingPlatformEntry) {
|
|
616
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, platform);
|
|
617
|
-
registry.addStore({
|
|
618
|
-
libName: dependency.libName, commit: dependency.commit, platform,
|
|
619
|
-
branch: dependency.branch, url: dependency.url, ...integrity,
|
|
620
|
-
usedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
else if (existingPlatformEntry.fileCount == null) {
|
|
624
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, platform);
|
|
625
|
-
registry.updateStore(storeKey, integrity);
|
|
626
|
-
}
|
|
627
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
628
|
-
}
|
|
629
|
-
await registerSharedStore(dependency.libName, dependency.commit, dependency.branch, dependency.url);
|
|
800
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, linkNewExisting, projectHash, false);
|
|
630
801
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 创建链接 [${linkNewExisting.join(', ')}]`);
|
|
631
802
|
}
|
|
632
803
|
break;
|
|
633
804
|
}
|
|
634
805
|
}
|
|
806
|
+
// 无论当前是跳过、补平台还是重建链接,都要把本地残留的平台目录清理到最终平台集合
|
|
807
|
+
const desiredLocalPlatforms = await resolveStoredPlatforms(dependency.libName, dependency.commit, finalLinkPlatforms);
|
|
808
|
+
await linker.cleanupLocalExtraPlatforms(localPath, desiredLocalPlatforms);
|
|
635
809
|
await tx.save();
|
|
636
810
|
}
|
|
637
811
|
// 8. 并行处理 MISSING 依赖
|
|
@@ -658,47 +832,26 @@ async function linkScope(params) {
|
|
|
658
832
|
};
|
|
659
833
|
try {
|
|
660
834
|
const storeCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
661
|
-
const
|
|
835
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
836
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
837
|
+
const { actualExisting: existing, missingRequested: missing, satisfiedRequested, } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
838
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
662
839
|
if (missing.length === 0) {
|
|
663
840
|
pLog.info(`${dependency.libName} 所有平台已存在,直接链接...`);
|
|
664
841
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
665
|
-
await linker.linkLib(localPath, storeCommitPath,
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, platform);
|
|
670
|
-
registry.addStore({
|
|
671
|
-
libName: dependency.libName, commit: dependency.commit, platform,
|
|
672
|
-
branch: dependency.branch, url: dependency.url, ...integrity,
|
|
673
|
-
usedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
677
|
-
}
|
|
678
|
-
await registerSharedStore(dependency.libName, dependency.commit, dependency.branch, dependency.url);
|
|
679
|
-
const dlLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
680
|
-
if (!registry.getLibrary(dlLibKey)) {
|
|
681
|
-
let totalSize = 0;
|
|
682
|
-
for (const platform of platforms) {
|
|
683
|
-
totalSize += await store.getSize(dependency.libName, dependency.commit, platform);
|
|
684
|
-
}
|
|
685
|
-
registry.addLibrary({
|
|
686
|
-
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
687
|
-
url: dependency.url, platforms, size: totalSize, referencedBy: [],
|
|
688
|
-
createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 链接完成 [${platforms.join(', ')}]`);
|
|
692
|
-
return { success: true, name: dependency.libName, downloadedPlatforms: platforms, skippedPlatforms: [] };
|
|
842
|
+
await linker.linkLib(localPath, storeCommitPath, existing);
|
|
843
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, existing, projectHash, false);
|
|
844
|
+
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 链接完成 [${existing.join(', ')}]`);
|
|
845
|
+
return { success: true, name: dependency.libName, downloadedPlatforms: existing, skippedPlatforms: [] };
|
|
693
846
|
}
|
|
694
847
|
const dlLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
695
848
|
const historyLib = registry.getLibrary(dlLibKey);
|
|
696
|
-
const unavailablePlatforms =
|
|
849
|
+
const unavailablePlatforms = blockedPlatforms;
|
|
697
850
|
const dlToDownload = missing.filter(p => !unavailablePlatforms.includes(p));
|
|
698
851
|
const knownUnavailable = missing.filter(p => unavailablePlatforms.includes(p));
|
|
699
852
|
if (dlToDownload.length === 0) {
|
|
700
853
|
if (knownUnavailable.length > 0) {
|
|
701
|
-
pLog.warn(`${dependency.libName} 平台 [${knownUnavailable.join(', ')}]
|
|
854
|
+
pLog.warn(`${dependency.libName} 平台 [${knownUnavailable.join(', ')}] 已按规则跳过`);
|
|
702
855
|
}
|
|
703
856
|
return { success: false, name: dependency.libName, skipped: true, skippedPlatforms: missing, unsupported: true };
|
|
704
857
|
}
|
|
@@ -725,52 +878,31 @@ async function linkScope(params) {
|
|
|
725
878
|
pLog.hint(` 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
726
879
|
}
|
|
727
880
|
try {
|
|
728
|
-
const
|
|
729
|
-
|
|
881
|
+
const assessment = assessDownloadResult(dlToDownload, dependency.sparse, downloadResult, configVars);
|
|
882
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, assessment.satisfiedRequested);
|
|
883
|
+
if (assessment.isPureGeneral) {
|
|
884
|
+
upsertLibraryAvailability(dependency, {
|
|
885
|
+
platforms: [GENERAL_PLATFORM],
|
|
886
|
+
isGeneral: true,
|
|
887
|
+
});
|
|
730
888
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
731
889
|
await store.absorbGeneral(downloadResult.libDir, dependency.libName, dependency.commit);
|
|
732
890
|
const sharedPath = path.join(storeCommitPath, '_shared');
|
|
733
891
|
tx.recordOp('link', localPath, sharedPath);
|
|
734
892
|
await linker.linkGeneral(localPath, sharedPath);
|
|
735
|
-
|
|
736
|
-
if (!registry.getStore(storeKey)) {
|
|
737
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, GENERAL_PLATFORM);
|
|
738
|
-
registry.addStore({
|
|
739
|
-
libName: dependency.libName, commit: dependency.commit, platform: GENERAL_PLATFORM,
|
|
740
|
-
branch: dependency.branch, url: dependency.url, ...integrity,
|
|
741
|
-
usedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
745
|
-
const genLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
746
|
-
if (!registry.getLibrary(genLibKey)) {
|
|
747
|
-
const sharedSize = await getDirSize(sharedPath);
|
|
748
|
-
registry.addLibrary({
|
|
749
|
-
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
750
|
-
url: dependency.url, platforms: [GENERAL_PLATFORM], size: sharedSize,
|
|
751
|
-
referencedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
752
|
-
});
|
|
753
|
-
}
|
|
893
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, [GENERAL_PLATFORM], projectHash, true);
|
|
754
894
|
generalLibs.add(dependency.libName);
|
|
755
895
|
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - General 库,下载完成`);
|
|
756
896
|
return { success: true, name: dependency.libName, downloadedPlatforms: [GENERAL_PLATFORM], skippedPlatforms: [], isGeneral: true };
|
|
757
897
|
}
|
|
758
|
-
const filteredDownloaded =
|
|
759
|
-
const newUnavailable =
|
|
898
|
+
const filteredDownloaded = assessment.downloadedRequested;
|
|
899
|
+
const newUnavailable = assessment.unavailableRequested;
|
|
760
900
|
if (newUnavailable.length > 0) {
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
}
|
|
766
|
-
else {
|
|
767
|
-
registry.addLibrary({
|
|
768
|
-
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
769
|
-
url: dependency.url, platforms: [], size: 0, referencedBy: [],
|
|
770
|
-
unavailablePlatforms: newUnavailable,
|
|
771
|
-
createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
772
|
-
});
|
|
773
|
-
}
|
|
901
|
+
const updatedUnavailable = [...new Set([...unavailablePlatforms, ...newUnavailable])];
|
|
902
|
+
upsertLibraryAvailability(dependency, {
|
|
903
|
+
unavailablePlatforms: updatedUnavailable,
|
|
904
|
+
isGeneral: false,
|
|
905
|
+
});
|
|
774
906
|
pLog.warn(`${dependency.libName} 平台 [${newUnavailable.join(', ')}] 远程不存在,已记录`);
|
|
775
907
|
}
|
|
776
908
|
if (filteredDownloaded.length > 0) {
|
|
@@ -779,65 +911,18 @@ async function linkScope(params) {
|
|
|
779
911
|
await registerNestedLibraries(downloadAbsorbResult.nestedLibraries, projectHash);
|
|
780
912
|
}
|
|
781
913
|
const linkPlatforms = [...existing, ...filteredDownloaded];
|
|
782
|
-
const isDownloadGeneral = await store.isGeneralLib(dependency.libName, dependency.commit);
|
|
783
|
-
if (isDownloadGeneral) {
|
|
784
|
-
const sharedPath = path.join(storeCommitPath, '_shared');
|
|
785
|
-
tx.recordOp('link', localPath, sharedPath);
|
|
786
|
-
await linker.linkGeneral(localPath, sharedPath);
|
|
787
|
-
const storeKey = registry.getStoreKey(dependency.libName, dependency.commit, GENERAL_PLATFORM);
|
|
788
|
-
if (!registry.getStore(storeKey)) {
|
|
789
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, GENERAL_PLATFORM);
|
|
790
|
-
registry.addStore({
|
|
791
|
-
libName: dependency.libName, commit: dependency.commit, platform: GENERAL_PLATFORM,
|
|
792
|
-
branch: dependency.branch, url: dependency.url, ...integrity,
|
|
793
|
-
usedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
797
|
-
const genLibKey2 = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
798
|
-
if (!registry.getLibrary(genLibKey2)) {
|
|
799
|
-
const sharedSize = await getDirSize(sharedPath);
|
|
800
|
-
registry.addLibrary({
|
|
801
|
-
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
802
|
-
url: dependency.url, platforms: [GENERAL_PLATFORM], size: sharedSize,
|
|
803
|
-
referencedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
804
|
-
});
|
|
805
|
-
}
|
|
806
|
-
generalLibs.add(dependency.libName);
|
|
807
|
-
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - General 库,下载完成`);
|
|
808
|
-
return { success: true, name: dependency.libName, downloadedPlatforms: [GENERAL_PLATFORM], skippedPlatforms: [], isGeneral: true };
|
|
809
|
-
}
|
|
810
914
|
if (linkPlatforms.length === 0) {
|
|
811
|
-
return {
|
|
915
|
+
return {
|
|
916
|
+
success: false,
|
|
917
|
+
name: dependency.libName,
|
|
918
|
+
skipped: true,
|
|
919
|
+
skippedPlatforms: requestedPlatforms,
|
|
920
|
+
};
|
|
812
921
|
}
|
|
813
922
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
814
923
|
await linker.linkLib(localPath, storeCommitPath, linkPlatforms);
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
if (!registry.getStore(storeKey)) {
|
|
818
|
-
const integrity = await store.captureIntegrity(dependency.libName, dependency.commit, platform);
|
|
819
|
-
registry.addStore({
|
|
820
|
-
libName: dependency.libName, commit: dependency.commit, platform,
|
|
821
|
-
branch: dependency.branch, url: dependency.url, ...integrity,
|
|
822
|
-
usedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
823
|
-
});
|
|
824
|
-
}
|
|
825
|
-
registry.addStoreReference(storeKey, projectHash);
|
|
826
|
-
}
|
|
827
|
-
await registerSharedStore(dependency.libName, dependency.commit, dependency.branch, dependency.url);
|
|
828
|
-
const finalLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
829
|
-
if (!registry.getLibrary(finalLibKey)) {
|
|
830
|
-
let totalSize = 0;
|
|
831
|
-
for (const platform of linkPlatforms) {
|
|
832
|
-
totalSize += await store.getSize(dependency.libName, dependency.commit, platform);
|
|
833
|
-
}
|
|
834
|
-
registry.addLibrary({
|
|
835
|
-
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
836
|
-
url: dependency.url, platforms: linkPlatforms, size: totalSize,
|
|
837
|
-
referencedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
|
-
const notLinkedPlatforms = platforms.filter((p) => !linkPlatforms.includes(p));
|
|
924
|
+
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, linkPlatforms, projectHash, false);
|
|
925
|
+
const notLinkedPlatforms = resolveRequestedPlatformsByActual(requestedPlatforms, dependency.sparse, linkPlatforms, configVars).missingRequested;
|
|
841
926
|
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 下载完成 [${linkPlatforms.join(', ')}]`);
|
|
842
927
|
return { success: true, name: dependency.libName, downloadedPlatforms: linkPlatforms, skippedPlatforms: notLinkedPlatforms };
|
|
843
928
|
}
|
|
@@ -902,20 +987,22 @@ async function linkScope(params) {
|
|
|
902
987
|
// 10. 同步 cache 文件
|
|
903
988
|
await syncCacheFile(configPath);
|
|
904
989
|
// 11. 构建返回结果
|
|
905
|
-
const
|
|
906
|
-
const
|
|
907
|
-
.
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
990
|
+
const linkedDeps = [];
|
|
991
|
+
for (const item of classified) {
|
|
992
|
+
if (item.status === DependencyStatus.MISSING && !downloadedLibs.includes(item.dependency.libName)) {
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
const actualPlatforms = generalLibs.has(item.dependency.libName)
|
|
996
|
+
? [GENERAL_PLATFORM]
|
|
997
|
+
: await resolveStoredPlatforms(item.dependency.libName, item.dependency.commit, platforms);
|
|
998
|
+
linkedDeps.push({
|
|
999
|
+
libName: item.dependency.libName,
|
|
1000
|
+
commit: item.dependency.commit,
|
|
1001
|
+
platform: actualPlatforms[0] ?? platforms[0],
|
|
1002
|
+
linkedPath: path.relative(projectRoot, item.localPath),
|
|
1003
|
+
scope,
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
919
1006
|
return {
|
|
920
1007
|
linkedDeps, nestedLinkedDeps, generalLibs, downloadedLibs, savedBytes, finalLinkPlatforms, stats,
|
|
921
1008
|
};
|
|
@@ -929,7 +1016,7 @@ async function linkScope(params) {
|
|
|
929
1016
|
* 执行链接操作
|
|
930
1017
|
*/
|
|
931
1018
|
export async function linkProject(projectPath, options) {
|
|
932
|
-
const absolutePath =
|
|
1019
|
+
const { absolutePath, normalizedPath, configPath: discoveredConfigPath, } = await resolveProjectRootPath(projectPath);
|
|
933
1020
|
// === 阶段 1: 初始化 ===
|
|
934
1021
|
const cfg = await config.load();
|
|
935
1022
|
if (cfg?.logLevel)
|
|
@@ -939,7 +1026,7 @@ export async function linkProject(projectPath, options) {
|
|
|
939
1026
|
const concurrency = cfg?.concurrency ?? 5;
|
|
940
1027
|
const registry = getRegistry();
|
|
941
1028
|
await registry.load();
|
|
942
|
-
const existingProject = registry.getProjectByPath(
|
|
1029
|
+
const existingProject = registry.getProjectByPath(normalizedPath);
|
|
943
1030
|
const rememberedPlatforms = existingProject?.platforms;
|
|
944
1031
|
// 确定平台列表
|
|
945
1032
|
let platforms;
|
|
@@ -976,7 +1063,7 @@ export async function linkProject(projectPath, options) {
|
|
|
976
1063
|
process.exit(EXIT_CODES.NOINPUT);
|
|
977
1064
|
}
|
|
978
1065
|
// 发现可选配置文件
|
|
979
|
-
const thirdpartyDir = path.join(
|
|
1066
|
+
const thirdpartyDir = path.join(normalizedPath, '3rdparty');
|
|
980
1067
|
const configDiscovery = await findAllCodepacConfigs(thirdpartyDir);
|
|
981
1068
|
let selectedOptionalConfigs = [];
|
|
982
1069
|
if (configDiscovery && configDiscovery.optionalConfigs.length > 0) {
|
|
@@ -1016,8 +1103,7 @@ export async function linkProject(projectPath, options) {
|
|
|
1016
1103
|
}
|
|
1017
1104
|
}
|
|
1018
1105
|
// 查找主配置文件
|
|
1019
|
-
const
|
|
1020
|
-
const mainConfigPath = await findCodepacConfig(absolutePath);
|
|
1106
|
+
const mainConfigPath = discoveredConfigPath;
|
|
1021
1107
|
if (!mainConfigPath) {
|
|
1022
1108
|
error(`找不到 codepac-dep.json 配置文件,已搜索: 3rdparty, .`);
|
|
1023
1109
|
process.exit(EXIT_CODES.DATAERR);
|
|
@@ -1025,7 +1111,7 @@ export async function linkProject(projectPath, options) {
|
|
|
1025
1111
|
// === 阶段 2: Submodule 检测 ===
|
|
1026
1112
|
let selectedSubmodules = [];
|
|
1027
1113
|
if (options.submodules !== false) {
|
|
1028
|
-
const submoduleConfigs = await findSubmoduleConfigs(
|
|
1114
|
+
const submoduleConfigs = await findSubmoduleConfigs(normalizedPath);
|
|
1029
1115
|
if (submoduleConfigs.length > 0) {
|
|
1030
1116
|
selectedSubmodules = await selectSubmodules(submoduleConfigs, options, existingProject?.submodules);
|
|
1031
1117
|
// 为选中的 submodule 处理可选配置
|
|
@@ -1041,7 +1127,7 @@ export async function linkProject(projectPath, options) {
|
|
|
1041
1127
|
}
|
|
1042
1128
|
}
|
|
1043
1129
|
// === 阶段 3: 规范化 + 事务准备 ===
|
|
1044
|
-
const normalizedRoot =
|
|
1130
|
+
const normalizedRoot = normalizedPath;
|
|
1045
1131
|
const wasNormalized = normalizedRoot !== absolutePath;
|
|
1046
1132
|
if (wasNormalized) {
|
|
1047
1133
|
info(`项目根目录规范化: ${absolutePath} → ${normalizedRoot}`);
|
|
@@ -1365,6 +1451,95 @@ async function registerSharedStore(libName, commit, branch = '', url = '') {
|
|
|
1365
1451
|
debug(`注册 _shared: ${libName}:${commit.slice(0, 8)} (${formatSize(integrity.size)})`);
|
|
1366
1452
|
return true;
|
|
1367
1453
|
}
|
|
1454
|
+
async function ensureStoreInfo(libName, commit, platform, branch, url, projectHash) {
|
|
1455
|
+
const registry = getRegistry();
|
|
1456
|
+
const storeKey = registry.getStoreKey(libName, commit, platform);
|
|
1457
|
+
const existingEntry = registry.getStore(storeKey);
|
|
1458
|
+
if (!existingEntry) {
|
|
1459
|
+
const integrity = await store.captureIntegrity(libName, commit, platform);
|
|
1460
|
+
registry.addStore({
|
|
1461
|
+
libName,
|
|
1462
|
+
commit,
|
|
1463
|
+
platform,
|
|
1464
|
+
branch,
|
|
1465
|
+
url,
|
|
1466
|
+
...integrity,
|
|
1467
|
+
usedBy: [],
|
|
1468
|
+
createdAt: new Date().toISOString(),
|
|
1469
|
+
lastAccess: new Date().toISOString(),
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
else if (existingEntry.fileCount == null) {
|
|
1473
|
+
const integrity = await store.captureIntegrity(libName, commit, platform);
|
|
1474
|
+
registry.updateStore(storeKey, integrity);
|
|
1475
|
+
}
|
|
1476
|
+
if (projectHash) {
|
|
1477
|
+
registry.addStoreReference(storeKey, projectHash);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
async function syncLibraryInfo(libName, commit, branch, url, platforms, isGeneral) {
|
|
1481
|
+
const registry = getRegistry();
|
|
1482
|
+
const libKey = registry.getLibraryKey(libName, commit);
|
|
1483
|
+
const existingLibrary = registry.getLibrary(libKey);
|
|
1484
|
+
const normalizedPlatforms = [...new Set(platforms)];
|
|
1485
|
+
let totalSize = 0;
|
|
1486
|
+
for (const platform of normalizedPlatforms) {
|
|
1487
|
+
totalSize += await store.getSize(libName, commit, platform);
|
|
1488
|
+
}
|
|
1489
|
+
if (!existingLibrary) {
|
|
1490
|
+
registry.addLibrary({
|
|
1491
|
+
libName,
|
|
1492
|
+
commit,
|
|
1493
|
+
branch,
|
|
1494
|
+
url,
|
|
1495
|
+
platforms: normalizedPlatforms,
|
|
1496
|
+
size: totalSize,
|
|
1497
|
+
isGeneral,
|
|
1498
|
+
referencedBy: [],
|
|
1499
|
+
createdAt: new Date().toISOString(),
|
|
1500
|
+
lastAccess: new Date().toISOString(),
|
|
1501
|
+
});
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
registry.updateLibrary(libKey, {
|
|
1505
|
+
branch: branch || existingLibrary.branch,
|
|
1506
|
+
url: url || existingLibrary.url,
|
|
1507
|
+
platforms: normalizedPlatforms,
|
|
1508
|
+
size: totalSize,
|
|
1509
|
+
isGeneral,
|
|
1510
|
+
lastAccess: new Date().toISOString(),
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
async function resolveStoredPlatforms(libName, commit, fallbackPlatforms) {
|
|
1514
|
+
const storePath = await config.getStorePath();
|
|
1515
|
+
if (!storePath) {
|
|
1516
|
+
return [...new Set(fallbackPlatforms)];
|
|
1517
|
+
}
|
|
1518
|
+
const commitPath = path.join(storePath, libName, commit);
|
|
1519
|
+
try {
|
|
1520
|
+
const entries = await fs.readdir(commitPath, { withFileTypes: true });
|
|
1521
|
+
const storedPlatforms = entries
|
|
1522
|
+
.filter(entry => entry.isDirectory() && KNOWN_PLATFORM_VALUES.includes(entry.name))
|
|
1523
|
+
.map(entry => entry.name);
|
|
1524
|
+
return storedPlatforms.length > 0 ? storedPlatforms : [...new Set(fallbackPlatforms)];
|
|
1525
|
+
}
|
|
1526
|
+
catch {
|
|
1527
|
+
return [...new Set(fallbackPlatforms)];
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
async function ensureLinkedRegistryState(libName, commit, branch, url, platforms, projectHash, isGeneral) {
|
|
1531
|
+
const linkedPlatforms = isGeneral ? [GENERAL_PLATFORM] : [...new Set(platforms)];
|
|
1532
|
+
const libraryPlatforms = isGeneral
|
|
1533
|
+
? [GENERAL_PLATFORM]
|
|
1534
|
+
: await resolveStoredPlatforms(libName, commit, linkedPlatforms);
|
|
1535
|
+
for (const platform of linkedPlatforms) {
|
|
1536
|
+
await ensureStoreInfo(libName, commit, platform, branch, url, projectHash);
|
|
1537
|
+
}
|
|
1538
|
+
if (!isGeneral) {
|
|
1539
|
+
await registerSharedStore(libName, commit, branch, url);
|
|
1540
|
+
}
|
|
1541
|
+
await syncLibraryInfo(libName, commit, branch, url, libraryPlatforms, isGeneral);
|
|
1542
|
+
}
|
|
1368
1543
|
/**
|
|
1369
1544
|
* 注册嵌套依赖到 Registry
|
|
1370
1545
|
* absorbLib 递归吸收嵌套依赖时只做文件操作,此函数负责 Registry 注册
|
|
@@ -1405,6 +1580,7 @@ async function registerNestedLibraries(nestedLibraries, projectHash) {
|
|
|
1405
1580
|
url: '',
|
|
1406
1581
|
platforms: [GENERAL_PLATFORM],
|
|
1407
1582
|
size: nested.size,
|
|
1583
|
+
isGeneral: true,
|
|
1408
1584
|
referencedBy: [],
|
|
1409
1585
|
createdAt: new Date().toISOString(),
|
|
1410
1586
|
lastAccess: new Date().toISOString(),
|
|
@@ -1443,6 +1619,7 @@ async function registerNestedLibraries(nestedLibraries, projectHash) {
|
|
|
1443
1619
|
url: '',
|
|
1444
1620
|
platforms: nested.platforms,
|
|
1445
1621
|
size: nested.size,
|
|
1622
|
+
isGeneral: false,
|
|
1446
1623
|
referencedBy: [],
|
|
1447
1624
|
createdAt: new Date().toISOString(),
|
|
1448
1625
|
lastAccess: new Date().toISOString(),
|
|
@@ -1507,7 +1684,7 @@ export async function classifyLinkStatus(localPath, storeCommitPath, isGeneral,
|
|
|
1507
1684
|
* @param configPath 配置文件路径
|
|
1508
1685
|
* @param platforms 请求的平台列表
|
|
1509
1686
|
*/
|
|
1510
|
-
async function classifyDependencies(dependencies, projectPath, configPath, platforms) {
|
|
1687
|
+
async function classifyDependencies(dependencies, projectPath, configPath, platforms, vars) {
|
|
1511
1688
|
const result = [];
|
|
1512
1689
|
const thirdPartyDir = path.dirname(configPath);
|
|
1513
1690
|
const storePath = await store.getStorePath();
|
|
@@ -1518,8 +1695,10 @@ async function classifyDependencies(dependencies, projectPath, configPath, platf
|
|
|
1518
1695
|
for (const dep of dependencies) {
|
|
1519
1696
|
const localPath = path.join(thirdPartyDir, dep.libName);
|
|
1520
1697
|
const storeLibPath = store.getLibraryPath(storePath, dep.libName, dep.commit, primaryPlatform);
|
|
1521
|
-
|
|
1522
|
-
const
|
|
1698
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(getRegistry(), dep, platforms, vars);
|
|
1699
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
1700
|
+
// 检查 Store 中是否有任意请求的平台(支持 sparse 承载目录)
|
|
1701
|
+
const { actualExisting: rawExisting, satisfiedRequested, } = await resolveRequestedStoreState(dep, requestedPlatforms, vars);
|
|
1523
1702
|
// 完整性校验:验证 existing 平台的文件完整性
|
|
1524
1703
|
const { valid: verifiedExisting, corrupted } = await verifyExistingPlatforms(dep.libName, dep.commit, rawExisting);
|
|
1525
1704
|
// 清除损坏的平台数据
|
|
@@ -1534,8 +1713,11 @@ async function classifyDependencies(dependencies, projectPath, configPath, platf
|
|
|
1534
1713
|
}
|
|
1535
1714
|
const existing = verifiedExisting;
|
|
1536
1715
|
// 也检查是否为 General 库(有 _shared 且有内容)
|
|
1537
|
-
const isGeneral = await
|
|
1716
|
+
const isGeneral = await resolveLibraryGeneralState(dep);
|
|
1538
1717
|
const inStore = existing.length > 0 || isGeneral;
|
|
1718
|
+
if (satisfiedRequested.length > 0) {
|
|
1719
|
+
clearSatisfiedAutoUnavailablePlatforms(getRegistry(), dep, satisfiedRequested);
|
|
1720
|
+
}
|
|
1539
1721
|
// 用于非 inStore 情况的本地路径状态检查
|
|
1540
1722
|
const expectedTarget = isGeneral
|
|
1541
1723
|
? path.join(storePath, dep.libName, dep.commit, '_shared')
|
|
@@ -1617,15 +1799,17 @@ async function classifyDependencies(dependencies, projectPath, configPath, platf
|
|
|
1617
1799
|
}
|
|
1618
1800
|
async function supplementMissingPlatforms(dependency, platforms, registry, tx, options = {}) {
|
|
1619
1801
|
const result = { downloaded: [], unavailable: [], nestedLibraries: [] };
|
|
1802
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, options.vars);
|
|
1803
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
1620
1804
|
// 1. 检查平台完整性
|
|
1621
|
-
const {
|
|
1805
|
+
const { missingRequested, satisfiedRequested } = await resolveRequestedStoreState(dependency, requestedPlatforms, options.vars);
|
|
1806
|
+
const missing = missingRequested;
|
|
1622
1807
|
if (missing.length === 0) {
|
|
1808
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
1623
1809
|
return result;
|
|
1624
1810
|
}
|
|
1625
1811
|
// 2. 获取已知不可用平台
|
|
1626
|
-
const
|
|
1627
|
-
const libInfo = registry.getLibrary(libKey);
|
|
1628
|
-
const unavailablePlatforms = libInfo?.unavailablePlatforms || [];
|
|
1812
|
+
const unavailablePlatforms = blockedPlatforms;
|
|
1629
1813
|
// 3. 计算需要下载的平台(排除已知不可用的,除非强制下载)
|
|
1630
1814
|
const toDownload = options.forceDownload
|
|
1631
1815
|
? missing
|
|
@@ -1633,7 +1817,7 @@ async function supplementMissingPlatforms(dependency, platforms, registry, tx, o
|
|
|
1633
1817
|
if (toDownload.length === 0) {
|
|
1634
1818
|
// 所有缺失平台都是已知不可用的
|
|
1635
1819
|
if (missing.length > 0) {
|
|
1636
|
-
hint(`${dependency.libName} 平台 [${missing.join(', ')}]
|
|
1820
|
+
hint(`${dependency.libName} 平台 [${missing.join(', ')}] 已按规则跳过`);
|
|
1637
1821
|
}
|
|
1638
1822
|
result.unavailable = missing.filter((p) => unavailablePlatforms.includes(p));
|
|
1639
1823
|
return result;
|
|
@@ -1655,18 +1839,20 @@ async function supplementMissingPlatforms(dependency, platforms, registry, tx, o
|
|
|
1655
1839
|
hint(` 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
1656
1840
|
}
|
|
1657
1841
|
try {
|
|
1658
|
-
// 5.
|
|
1659
|
-
const
|
|
1842
|
+
// 5. 解释下载结果
|
|
1843
|
+
const assessment = assessDownloadResult(toDownload, dependency.sparse, downloadResult, options.vars);
|
|
1844
|
+
const downloaded = assessment.downloadedRequested;
|
|
1660
1845
|
result.downloaded = downloaded;
|
|
1846
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, assessment.satisfiedRequested);
|
|
1661
1847
|
// 6. 记录新发现的不可用平台
|
|
1662
|
-
const notFound =
|
|
1848
|
+
const notFound = assessment.unavailableRequested;
|
|
1663
1849
|
if (notFound.length > 0) {
|
|
1664
1850
|
result.unavailable = notFound;
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
}
|
|
1851
|
+
const newUnavailable = [...new Set([...unavailablePlatforms, ...notFound])];
|
|
1852
|
+
upsertLibraryAvailability(dependency, {
|
|
1853
|
+
unavailablePlatforms: newUnavailable,
|
|
1854
|
+
isGeneral: false,
|
|
1855
|
+
});
|
|
1670
1856
|
warn(`${dependency.libName} 平台 [${notFound.join(', ')}] 远程不存在,已记录`);
|
|
1671
1857
|
}
|
|
1672
1858
|
// 7. 吸收下载的内容到 Store(不做链接,由调用者负责)
|
|
@@ -1919,7 +2105,6 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
1919
2105
|
const nestedTargetDir = path.join(thirdPartyDir, targetDir);
|
|
1920
2106
|
const { tx, registry, projectHash, projectRoot, dryRun, download, generalLibs, downloadedLibs, nestedLinkedDeps } = options;
|
|
1921
2107
|
const { platforms, vars } = context;
|
|
1922
|
-
const primaryPlatform = platforms[0];
|
|
1923
2108
|
for (const dep of dependencies) {
|
|
1924
2109
|
const localPath = path.join(nestedTargetDir, dep.libName);
|
|
1925
2110
|
const storePath = await store.getStorePath();
|
|
@@ -1938,18 +2123,18 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
1938
2123
|
// 检查 Store 状态和历史记录
|
|
1939
2124
|
const libKey = registry.getLibraryKey(dep.libName, dep.commit);
|
|
1940
2125
|
const historyLib = registry.getLibrary(libKey);
|
|
1941
|
-
const unavailablePlatforms =
|
|
2126
|
+
const unavailablePlatforms = getBlockedRequestedPlatforms(registry, dep, platforms, vars);
|
|
1942
2127
|
// 过滤掉已知不可用的平台
|
|
1943
2128
|
const availablePlatforms = platforms.filter(p => !unavailablePlatforms.includes(p));
|
|
1944
2129
|
const knownUnavailable = platforms.filter(p => unavailablePlatforms.includes(p));
|
|
1945
2130
|
let storeHas = false;
|
|
1946
2131
|
const existingPlatforms = [];
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
}
|
|
2132
|
+
const initialStoreState = await resolveRequestedStoreState(dep, availablePlatforms, vars);
|
|
2133
|
+
existingPlatforms.push(...initialStoreState.actualExisting);
|
|
2134
|
+
if (initialStoreState.satisfiedRequested.length > 0) {
|
|
2135
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dep, initialStoreState.satisfiedRequested);
|
|
1952
2136
|
}
|
|
2137
|
+
storeHas = existingPlatforms.length > 0;
|
|
1953
2138
|
// 完整性校验:验证 existing 平台的文件完整性(与 classifyDependencies 同逻辑)
|
|
1954
2139
|
if (existingPlatforms.length > 0) {
|
|
1955
2140
|
const { valid: verifiedPlatforms, corrupted } = await verifyExistingPlatforms(dep.libName, dep.commit, existingPlatforms);
|
|
@@ -1963,10 +2148,10 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
1963
2148
|
storeHas = verifiedPlatforms.length > 0;
|
|
1964
2149
|
}
|
|
1965
2150
|
}
|
|
1966
|
-
let isGeneral = await
|
|
2151
|
+
let isGeneral = await resolveLibraryGeneralState(dep);
|
|
1967
2152
|
// 如果所有平台都已知不可用,跳过
|
|
1968
2153
|
if (availablePlatforms.length === 0 && knownUnavailable.length > 0 && !isGeneral) {
|
|
1969
|
-
warn(`${indent} ${dep.libName} - 平台 [${knownUnavailable.join(', ')}]
|
|
2154
|
+
warn(`${indent} ${dep.libName} - 平台 [${knownUnavailable.join(', ')}] 已按规则跳过`);
|
|
1970
2155
|
continue;
|
|
1971
2156
|
}
|
|
1972
2157
|
// Store 没有,但本地是目录时,验证 commit 并尝试 absorb
|
|
@@ -2003,14 +2188,16 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2003
2188
|
sparse: dep.sparse,
|
|
2004
2189
|
vars,
|
|
2005
2190
|
});
|
|
2006
|
-
|
|
2191
|
+
const assessment = assessDownloadResult(availablePlatforms, dep.sparse, downloadResult, vars);
|
|
2192
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dep, assessment.satisfiedRequested);
|
|
2193
|
+
if (assessment.downloadedRequested.length > 0) {
|
|
2007
2194
|
// 有平台内容 → 吸收平台目录,重新分类为平台库
|
|
2008
2195
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
2009
|
-
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir,
|
|
2196
|
+
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir, assessment.downloadedRequested, dep.libName, dep.commit);
|
|
2010
2197
|
await registerNestedLibraries(nestedAbsorbResult.nestedLibraries, projectHash);
|
|
2011
|
-
existingPlatforms.push(...
|
|
2198
|
+
existingPlatforms.push(...assessment.downloadedRequested);
|
|
2012
2199
|
isGeneral = false;
|
|
2013
|
-
info(`${indent} ${dep.libName} - 补充平台内容 [${
|
|
2200
|
+
info(`${indent} ${dep.libName} - 补充平台内容 [${assessment.downloadedRequested.join(', ')}]`);
|
|
2014
2201
|
}
|
|
2015
2202
|
if (downloadResult.cleanedPlatforms.length > 0) {
|
|
2016
2203
|
hint(`${indent} 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
@@ -2036,6 +2223,7 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2036
2223
|
if (localExists && (storeHas || isGeneral)) {
|
|
2037
2224
|
const linkStatus = await classifyLinkStatus(localPath, storeCommitPath, isGeneral, existingPlatforms);
|
|
2038
2225
|
if (linkStatus === 'linked') {
|
|
2226
|
+
let linkedPlatforms = isGeneral ? [GENERAL_PLATFORM] : [...existingPlatforms];
|
|
2039
2227
|
// 已链接,但需要检查是否需要补充缺失平台(与顶层依赖逻辑一致)
|
|
2040
2228
|
if (!isGeneral) {
|
|
2041
2229
|
const supplementResult = await supplementMissingPlatforms(dep, platforms, registry, tx, { vars });
|
|
@@ -2052,6 +2240,7 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2052
2240
|
}
|
|
2053
2241
|
// 合并所有平台并重新链接
|
|
2054
2242
|
const allPlatforms = [...existingPlatforms, ...supplementResult.downloaded];
|
|
2243
|
+
linkedPlatforms = allPlatforms;
|
|
2055
2244
|
if (!dryRun) {
|
|
2056
2245
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
2057
2246
|
await linker.linkLib(localPath, storeCommitPath, allPlatforms);
|
|
@@ -2059,10 +2248,11 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2059
2248
|
success(`${indent} ${dep.libName} - 重新链接完成 [${allPlatforms.join(', ')}]`);
|
|
2060
2249
|
}
|
|
2061
2250
|
}
|
|
2251
|
+
await ensureLinkedRegistryState(dep.libName, dep.commit, dep.branch, dep.url, linkedPlatforms, projectHash, isGeneral);
|
|
2062
2252
|
nestedLinkedDeps.push({
|
|
2063
2253
|
libName: dep.libName,
|
|
2064
2254
|
commit: dep.commit,
|
|
2065
|
-
platform: isGeneral ? GENERAL_PLATFORM :
|
|
2255
|
+
platform: isGeneral ? GENERAL_PLATFORM : (linkedPlatforms[0] ?? availablePlatforms[0]),
|
|
2066
2256
|
linkedPath: path.relative(projectRoot, localPath),
|
|
2067
2257
|
});
|
|
2068
2258
|
if (!isGeneral) {
|
|
@@ -2094,6 +2284,7 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2094
2284
|
const sharedPath = path.join(storeCommitPath, '_shared');
|
|
2095
2285
|
tx.recordOp('link', localPath, sharedPath);
|
|
2096
2286
|
await linker.linkGeneral(localPath, sharedPath);
|
|
2287
|
+
await ensureLinkedRegistryState(dep.libName, dep.commit, dep.branch, dep.url, [GENERAL_PLATFORM], projectHash, true);
|
|
2097
2288
|
generalLibs.add(dep.libName);
|
|
2098
2289
|
// 记录到 nestedLinkedDeps
|
|
2099
2290
|
nestedLinkedDeps.push({
|
|
@@ -2119,11 +2310,12 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2119
2310
|
}
|
|
2120
2311
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
2121
2312
|
await linker.linkLib(localPath, storeCommitPath, allPlatforms);
|
|
2313
|
+
await ensureLinkedRegistryState(dep.libName, dep.commit, dep.branch, dep.url, allPlatforms, projectHash, false);
|
|
2122
2314
|
// 记录到 nestedLinkedDeps
|
|
2123
2315
|
nestedLinkedDeps.push({
|
|
2124
2316
|
libName: dep.libName,
|
|
2125
2317
|
commit: dep.commit,
|
|
2126
|
-
platform:
|
|
2318
|
+
platform: allPlatforms[0],
|
|
2127
2319
|
linkedPath: path.relative(projectRoot, localPath),
|
|
2128
2320
|
});
|
|
2129
2321
|
success(`${indent} ${dep.libName} - 链接完成 [${allPlatforms.join(', ')}]`);
|
|
@@ -2165,15 +2357,20 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2165
2357
|
if (downloadResult.cleanedPlatforms.length > 0) {
|
|
2166
2358
|
hint(`${indent} 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
2167
2359
|
}
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
if (
|
|
2360
|
+
const assessment = assessDownloadResult(availablePlatforms, dep.sparse, downloadResult, vars);
|
|
2361
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dep, assessment.satisfiedRequested);
|
|
2362
|
+
if (assessment.isPureGeneral) {
|
|
2171
2363
|
// General 库处理
|
|
2364
|
+
upsertLibraryAvailability(dep, {
|
|
2365
|
+
platforms: [GENERAL_PLATFORM],
|
|
2366
|
+
isGeneral: true,
|
|
2367
|
+
});
|
|
2172
2368
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
2173
2369
|
await store.absorbGeneral(downloadResult.libDir, dep.libName, dep.commit);
|
|
2174
2370
|
const sharedPath = path.join(storeCommitPath, '_shared');
|
|
2175
2371
|
tx.recordOp('link', localPath, sharedPath);
|
|
2176
2372
|
await linker.linkGeneral(localPath, sharedPath);
|
|
2373
|
+
await ensureLinkedRegistryState(dep.libName, dep.commit, dep.branch, dep.url, [GENERAL_PLATFORM], projectHash, true);
|
|
2177
2374
|
generalLibs.add(dep.libName);
|
|
2178
2375
|
downloadedLibs.push(dep.libName);
|
|
2179
2376
|
// 记录到 nestedLinkedDeps
|
|
@@ -2185,66 +2382,42 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2185
2382
|
});
|
|
2186
2383
|
success(`${indent} ${dep.libName} - 下载完成 (General)`);
|
|
2187
2384
|
}
|
|
2188
|
-
else if (
|
|
2385
|
+
else if (assessment.downloadedRequested.length > 0) {
|
|
2189
2386
|
// 平台库处理
|
|
2190
2387
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
2191
|
-
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir,
|
|
2388
|
+
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir, assessment.downloadedRequested, dep.libName, dep.commit);
|
|
2192
2389
|
await registerNestedLibraries(nestedAbsorbResult.nestedLibraries, projectHash);
|
|
2193
2390
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
2194
|
-
await linker.linkLib(localPath, storeCommitPath,
|
|
2391
|
+
await linker.linkLib(localPath, storeCommitPath, assessment.downloadedRequested);
|
|
2392
|
+
await ensureLinkedRegistryState(dep.libName, dep.commit, dep.branch, dep.url, assessment.downloadedRequested, projectHash, false);
|
|
2195
2393
|
downloadedLibs.push(dep.libName);
|
|
2196
2394
|
// 记录到 nestedLinkedDeps
|
|
2197
2395
|
nestedLinkedDeps.push({
|
|
2198
2396
|
libName: dep.libName,
|
|
2199
2397
|
commit: dep.commit,
|
|
2200
|
-
platform:
|
|
2398
|
+
platform: assessment.downloadedRequested[0],
|
|
2201
2399
|
linkedPath: path.relative(projectRoot, localPath),
|
|
2202
2400
|
});
|
|
2203
2401
|
// 检查并记录新发现的不可用平台
|
|
2204
|
-
const newUnavailable =
|
|
2402
|
+
const newUnavailable = assessment.unavailableRequested;
|
|
2205
2403
|
if (newUnavailable.length > 0) {
|
|
2206
2404
|
const updatedUnavailable = [...new Set([...unavailablePlatforms, ...newUnavailable])];
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
libName: dep.libName,
|
|
2213
|
-
commit: dep.commit,
|
|
2214
|
-
branch: dep.branch,
|
|
2215
|
-
url: dep.url,
|
|
2216
|
-
platforms: downloadResult.platformDirs,
|
|
2217
|
-
size: 0,
|
|
2218
|
-
referencedBy: [],
|
|
2219
|
-
unavailablePlatforms: newUnavailable,
|
|
2220
|
-
createdAt: new Date().toISOString(),
|
|
2221
|
-
lastAccess: new Date().toISOString(),
|
|
2222
|
-
});
|
|
2223
|
-
}
|
|
2405
|
+
upsertLibraryAvailability(dep, {
|
|
2406
|
+
unavailablePlatforms: updatedUnavailable,
|
|
2407
|
+
platforms: assessment.downloadedRequested,
|
|
2408
|
+
isGeneral: false,
|
|
2409
|
+
});
|
|
2224
2410
|
warn(`${indent} ${dep.libName} 平台 [${newUnavailable.join(', ')}] 远程不存在,已记录`);
|
|
2225
2411
|
}
|
|
2226
|
-
success(`${indent} ${dep.libName} - 下载完成 [${
|
|
2412
|
+
success(`${indent} ${dep.libName} - 下载完成 [${assessment.downloadedRequested.join(', ')}]`);
|
|
2227
2413
|
}
|
|
2228
2414
|
else {
|
|
2229
2415
|
// 所有请求的平台都不可用,记录到 registry
|
|
2230
2416
|
const newUnavailable = [...new Set([...unavailablePlatforms, ...availablePlatforms])];
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
registry.addLibrary({
|
|
2236
|
-
libName: dep.libName,
|
|
2237
|
-
commit: dep.commit,
|
|
2238
|
-
branch: dep.branch,
|
|
2239
|
-
url: dep.url,
|
|
2240
|
-
platforms: [],
|
|
2241
|
-
size: 0,
|
|
2242
|
-
referencedBy: [],
|
|
2243
|
-
unavailablePlatforms: newUnavailable,
|
|
2244
|
-
createdAt: new Date().toISOString(),
|
|
2245
|
-
lastAccess: new Date().toISOString(),
|
|
2246
|
-
});
|
|
2247
|
-
}
|
|
2417
|
+
upsertLibraryAvailability(dep, {
|
|
2418
|
+
unavailablePlatforms: newUnavailable,
|
|
2419
|
+
isGeneral: false,
|
|
2420
|
+
});
|
|
2248
2421
|
warn(`${indent} ${dep.libName} - 下载成功但平台 [${availablePlatforms.join(', ')}] 不可用,已记录`);
|
|
2249
2422
|
}
|
|
2250
2423
|
// 清理临时目录
|