tanmi-dock 0.9.1 → 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 +362 -163
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +28 -0
- 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/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/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 +8 -0
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/registry.js +46 -1
- package/dist/core/registry.js.map +1 -1
- package/dist/index.js +2 -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
|
@@ -13,7 +13,7 @@ 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 { getPlatformHelpText, GENERAL_PLATFORM, SHARED_PLATFORM, pathsEqual, isSparseOnlyCommon, KNOWN_PLATFORM_VALUES } from '../core/platform.js';
|
|
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,25 +463,32 @@ 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
478
|
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, allExisting, projectHash, false);
|
|
293
479
|
success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已补充平台 [${supplementResult.downloaded.join(', ')}]`);
|
|
294
480
|
}
|
|
295
481
|
}
|
|
296
|
-
|
|
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);
|
|
297
485
|
break;
|
|
298
486
|
}
|
|
299
487
|
case DependencyStatus.RELINK: {
|
|
488
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
489
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
300
490
|
const relinkCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
301
|
-
const isRelinkGeneral = await
|
|
491
|
+
const isRelinkGeneral = await resolveLibraryGeneralState(dependency);
|
|
302
492
|
if (isRelinkGeneral) {
|
|
303
493
|
tx.recordOp('unlink', localPath);
|
|
304
494
|
await linker.unlink(localPath);
|
|
@@ -312,21 +502,23 @@ async function linkScope(params) {
|
|
|
312
502
|
else {
|
|
313
503
|
const relinkSupplementResult = await supplementMissingPlatforms(dependency, platforms, registry, tx, { vars: configVars });
|
|
314
504
|
await registerNestedLibraries(relinkSupplementResult.nestedLibraries, projectHash);
|
|
315
|
-
const {
|
|
505
|
+
const { actualExisting: relinkExisting, satisfiedRequested, } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
506
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
316
507
|
if (relinkExisting.length === 0) {
|
|
317
508
|
const { KNOWN_PLATFORM_VALUES } = await import('../core/platform.js');
|
|
318
509
|
const relinkCommitEntries = await fs.readdir(relinkCommitPath, { withFileTypes: true });
|
|
319
510
|
const relinkAvailablePlatforms = relinkCommitEntries
|
|
320
511
|
.filter(e => e.isDirectory() && e.name !== '_shared' && KNOWN_PLATFORM_VALUES.includes(e.name))
|
|
321
512
|
.map(e => e.name);
|
|
322
|
-
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) -
|
|
513
|
+
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已按规则跳过平台 [${platforms.join('/')}], 可用平台 [${relinkAvailablePlatforms.join(', ')}]`);
|
|
323
514
|
const relinkLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
324
515
|
const relinkLib = registry.getLibrary(relinkLibKey);
|
|
325
516
|
if (relinkLib) {
|
|
326
517
|
const unavailable = relinkLib.unavailablePlatforms || [];
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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);
|
|
330
522
|
}
|
|
331
523
|
registry.updateLibrary(relinkLibKey, { unavailablePlatforms: unavailable });
|
|
332
524
|
}
|
|
@@ -347,9 +539,11 @@ async function linkScope(params) {
|
|
|
347
539
|
break;
|
|
348
540
|
}
|
|
349
541
|
case DependencyStatus.REPLACE: {
|
|
542
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
543
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
350
544
|
const replaceSize = await getDirSize(localPath);
|
|
351
545
|
const replaceCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
352
|
-
const isReplaceGeneral = await
|
|
546
|
+
const isReplaceGeneral = await resolveLibraryGeneralState(dependency);
|
|
353
547
|
if (isReplaceGeneral) {
|
|
354
548
|
const sharedPath = path.join(replaceCommitPath, '_shared');
|
|
355
549
|
tx.recordOp('replace', localPath, sharedPath);
|
|
@@ -362,21 +556,23 @@ async function linkScope(params) {
|
|
|
362
556
|
else {
|
|
363
557
|
const replaceSupplementResult = await supplementMissingPlatforms(dependency, platforms, registry, tx, { vars: configVars });
|
|
364
558
|
await registerNestedLibraries(replaceSupplementResult.nestedLibraries, projectHash);
|
|
365
|
-
const {
|
|
559
|
+
const { actualExisting: replaceExisting, satisfiedRequested, } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
560
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
366
561
|
if (replaceExisting.length === 0) {
|
|
367
562
|
const { KNOWN_PLATFORM_VALUES } = await import('../core/platform.js');
|
|
368
563
|
const replaceCommitEntries = await fs.readdir(replaceCommitPath, { withFileTypes: true });
|
|
369
564
|
const replaceAvailablePlatforms = replaceCommitEntries
|
|
370
565
|
.filter(e => e.isDirectory() && e.name !== '_shared' && KNOWN_PLATFORM_VALUES.includes(e.name))
|
|
371
566
|
.map(e => e.name);
|
|
372
|
-
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) -
|
|
567
|
+
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已按规则跳过平台 [${platforms.join('/')}], 可用平台 [${replaceAvailablePlatforms.join(', ')}]`);
|
|
373
568
|
const replaceLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
374
569
|
const replaceLib = registry.getLibrary(replaceLibKey);
|
|
375
570
|
if (replaceLib) {
|
|
376
571
|
const unavailable = replaceLib.unavailablePlatforms || [];
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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);
|
|
380
576
|
}
|
|
381
577
|
registry.updateLibrary(replaceLibKey, { unavailablePlatforms: unavailable });
|
|
382
578
|
}
|
|
@@ -396,22 +592,26 @@ async function linkScope(params) {
|
|
|
396
592
|
break;
|
|
397
593
|
}
|
|
398
594
|
case DependencyStatus.ABSORB: {
|
|
595
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, configVars);
|
|
596
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
399
597
|
const storeCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
400
598
|
const { KNOWN_PLATFORM_VALUES } = await import('../core/platform.js');
|
|
401
599
|
const localDirEntries = await fs.readdir(localPath, { withFileTypes: true });
|
|
402
600
|
const localPlatforms = localDirEntries
|
|
403
601
|
.filter(entry => entry.isDirectory() && KNOWN_PLATFORM_VALUES.includes(entry.name))
|
|
404
602
|
.map(entry => entry.name);
|
|
405
|
-
const
|
|
603
|
+
const requestedTargets = [...new Set(requestedPlatforms.flatMap((platform) => getRequestedPlatformTargets(platform, dependency.sparse, configVars)))];
|
|
604
|
+
const finalPlatforms = localPlatforms.filter((platform) => requestedTargets.includes(platform));
|
|
406
605
|
if (finalPlatforms.length === 0 && localPlatforms.length > 0) {
|
|
407
|
-
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) -
|
|
606
|
+
warn(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 已按规则跳过平台 [${platforms.join('/')}], 本地有 [${localPlatforms.join(', ')}]`);
|
|
408
607
|
const absorbLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
409
608
|
const absorbLib = registry.getLibrary(absorbLibKey);
|
|
410
609
|
if (absorbLib) {
|
|
411
610
|
const unavailable = absorbLib.unavailablePlatforms || [];
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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);
|
|
415
615
|
}
|
|
416
616
|
registry.updateLibrary(absorbLibKey, { unavailablePlatforms: unavailable });
|
|
417
617
|
}
|
|
@@ -442,6 +642,7 @@ async function linkScope(params) {
|
|
|
442
642
|
registry.addLibrary({
|
|
443
643
|
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
444
644
|
url: dependency.url, platforms: absorbLinkPlatforms, size: absorbSize,
|
|
645
|
+
isGeneral: false,
|
|
445
646
|
referencedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
446
647
|
});
|
|
447
648
|
}
|
|
@@ -505,6 +706,7 @@ async function linkScope(params) {
|
|
|
505
706
|
registry.addLibrary({
|
|
506
707
|
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
507
708
|
url: dependency.url, platforms: [GENERAL_PLATFORM], size: sharedSize,
|
|
709
|
+
isGeneral: true,
|
|
508
710
|
referencedBy: [], createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
509
711
|
});
|
|
510
712
|
}
|
|
@@ -521,7 +723,9 @@ async function linkScope(params) {
|
|
|
521
723
|
break;
|
|
522
724
|
case DependencyStatus.LINK_NEW: {
|
|
523
725
|
const linkNewCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
524
|
-
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);
|
|
525
729
|
const linkNewLibId = `${dependency.libName}@${dependency.commit}`;
|
|
526
730
|
if (missing.length > 0 && !skipAllDownloads && downloadConfirmedLibs.has(linkNewLibId)) {
|
|
527
731
|
info(`${dependency.libName} 缺少平台 [${missing.join(', ')}],开始下载...`);
|
|
@@ -546,7 +750,9 @@ async function linkScope(params) {
|
|
|
546
750
|
hint(` 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
547
751
|
}
|
|
548
752
|
try {
|
|
549
|
-
const
|
|
753
|
+
const assessment = assessDownloadResult(missing, dependency.sparse, downloadResult, configVars);
|
|
754
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, assessment.satisfiedRequested);
|
|
755
|
+
const filteredDownloaded = assessment.downloadedRequested;
|
|
550
756
|
if (filteredDownloaded.length > 0) {
|
|
551
757
|
tx.recordOp('absorb', linkNewCommitPath, downloadResult.libDir);
|
|
552
758
|
const linkNewAbsorbResult = await store.absorbLib(downloadResult.libDir, filteredDownloaded, dependency.libName, dependency.commit);
|
|
@@ -557,8 +763,9 @@ async function linkScope(params) {
|
|
|
557
763
|
await fs.rm(downloadResult.tempDir, { recursive: true, force: true }).catch(() => { });
|
|
558
764
|
}
|
|
559
765
|
}
|
|
560
|
-
const {
|
|
561
|
-
|
|
766
|
+
const { actualExisting: linkNewExisting, satisfiedRequested, } = await resolveRequestedStoreState(dependency, requestedPlatforms, configVars);
|
|
767
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
768
|
+
const isLinkNewGeneral = await resolveLibraryGeneralState(dependency);
|
|
562
769
|
if (isLinkNewGeneral) {
|
|
563
770
|
const sharedPath = path.join(linkNewCommitPath, '_shared');
|
|
564
771
|
tx.recordOp('link', localPath, sharedPath);
|
|
@@ -578,9 +785,10 @@ async function linkScope(params) {
|
|
|
578
785
|
const lnLib = registry.getLibrary(lnLibKey);
|
|
579
786
|
if (lnLib) {
|
|
580
787
|
const unavailable = lnLib.unavailablePlatforms || [];
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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);
|
|
584
792
|
}
|
|
585
793
|
registry.updateLibrary(lnLibKey, { unavailablePlatforms: unavailable });
|
|
586
794
|
}
|
|
@@ -596,7 +804,8 @@ async function linkScope(params) {
|
|
|
596
804
|
}
|
|
597
805
|
}
|
|
598
806
|
// 无论当前是跳过、补平台还是重建链接,都要把本地残留的平台目录清理到最终平台集合
|
|
599
|
-
await
|
|
807
|
+
const desiredLocalPlatforms = await resolveStoredPlatforms(dependency.libName, dependency.commit, finalLinkPlatforms);
|
|
808
|
+
await linker.cleanupLocalExtraPlatforms(localPath, desiredLocalPlatforms);
|
|
600
809
|
await tx.save();
|
|
601
810
|
}
|
|
602
811
|
// 8. 并行处理 MISSING 依赖
|
|
@@ -623,23 +832,26 @@ async function linkScope(params) {
|
|
|
623
832
|
};
|
|
624
833
|
try {
|
|
625
834
|
const storeCommitPath = path.join(storePath, dependency.libName, dependency.commit);
|
|
626
|
-
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);
|
|
627
839
|
if (missing.length === 0) {
|
|
628
840
|
pLog.info(`${dependency.libName} 所有平台已存在,直接链接...`);
|
|
629
841
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
630
|
-
await linker.linkLib(localPath, storeCommitPath,
|
|
631
|
-
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url,
|
|
632
|
-
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 链接完成 [${
|
|
633
|
-
return { success: true, name: dependency.libName, downloadedPlatforms:
|
|
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: [] };
|
|
634
846
|
}
|
|
635
847
|
const dlLibKey = registry.getLibraryKey(dependency.libName, dependency.commit);
|
|
636
848
|
const historyLib = registry.getLibrary(dlLibKey);
|
|
637
|
-
const unavailablePlatforms =
|
|
849
|
+
const unavailablePlatforms = blockedPlatforms;
|
|
638
850
|
const dlToDownload = missing.filter(p => !unavailablePlatforms.includes(p));
|
|
639
851
|
const knownUnavailable = missing.filter(p => unavailablePlatforms.includes(p));
|
|
640
852
|
if (dlToDownload.length === 0) {
|
|
641
853
|
if (knownUnavailable.length > 0) {
|
|
642
|
-
pLog.warn(`${dependency.libName} 平台 [${knownUnavailable.join(', ')}]
|
|
854
|
+
pLog.warn(`${dependency.libName} 平台 [${knownUnavailable.join(', ')}] 已按规则跳过`);
|
|
643
855
|
}
|
|
644
856
|
return { success: false, name: dependency.libName, skipped: true, skippedPlatforms: missing, unsupported: true };
|
|
645
857
|
}
|
|
@@ -666,8 +878,13 @@ async function linkScope(params) {
|
|
|
666
878
|
pLog.hint(` 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
667
879
|
}
|
|
668
880
|
try {
|
|
669
|
-
const
|
|
670
|
-
|
|
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
|
+
});
|
|
671
888
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
672
889
|
await store.absorbGeneral(downloadResult.libDir, dependency.libName, dependency.commit);
|
|
673
890
|
const sharedPath = path.join(storeCommitPath, '_shared');
|
|
@@ -678,22 +895,14 @@ async function linkScope(params) {
|
|
|
678
895
|
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - General 库,下载完成`);
|
|
679
896
|
return { success: true, name: dependency.libName, downloadedPlatforms: [GENERAL_PLATFORM], skippedPlatforms: [], isGeneral: true };
|
|
680
897
|
}
|
|
681
|
-
const filteredDownloaded =
|
|
682
|
-
const newUnavailable =
|
|
898
|
+
const filteredDownloaded = assessment.downloadedRequested;
|
|
899
|
+
const newUnavailable = assessment.unavailableRequested;
|
|
683
900
|
if (newUnavailable.length > 0) {
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
}
|
|
689
|
-
else {
|
|
690
|
-
registry.addLibrary({
|
|
691
|
-
libName: dependency.libName, commit: dependency.commit, branch: dependency.branch,
|
|
692
|
-
url: dependency.url, platforms: [], size: 0, referencedBy: [],
|
|
693
|
-
unavailablePlatforms: newUnavailable,
|
|
694
|
-
createdAt: new Date().toISOString(), lastAccess: new Date().toISOString(),
|
|
695
|
-
});
|
|
696
|
-
}
|
|
901
|
+
const updatedUnavailable = [...new Set([...unavailablePlatforms, ...newUnavailable])];
|
|
902
|
+
upsertLibraryAvailability(dependency, {
|
|
903
|
+
unavailablePlatforms: updatedUnavailable,
|
|
904
|
+
isGeneral: false,
|
|
905
|
+
});
|
|
697
906
|
pLog.warn(`${dependency.libName} 平台 [${newUnavailable.join(', ')}] 远程不存在,已记录`);
|
|
698
907
|
}
|
|
699
908
|
if (filteredDownloaded.length > 0) {
|
|
@@ -702,23 +911,18 @@ async function linkScope(params) {
|
|
|
702
911
|
await registerNestedLibraries(downloadAbsorbResult.nestedLibraries, projectHash);
|
|
703
912
|
}
|
|
704
913
|
const linkPlatforms = [...existing, ...filteredDownloaded];
|
|
705
|
-
const isDownloadGeneral = await store.isGeneralLib(dependency.libName, dependency.commit);
|
|
706
|
-
if (isDownloadGeneral) {
|
|
707
|
-
const sharedPath = path.join(storeCommitPath, '_shared');
|
|
708
|
-
tx.recordOp('link', localPath, sharedPath);
|
|
709
|
-
await linker.linkGeneral(localPath, sharedPath);
|
|
710
|
-
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, [GENERAL_PLATFORM], projectHash, true);
|
|
711
|
-
generalLibs.add(dependency.libName);
|
|
712
|
-
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - General 库,下载完成`);
|
|
713
|
-
return { success: true, name: dependency.libName, downloadedPlatforms: [GENERAL_PLATFORM], skippedPlatforms: [], isGeneral: true };
|
|
714
|
-
}
|
|
715
914
|
if (linkPlatforms.length === 0) {
|
|
716
|
-
return {
|
|
915
|
+
return {
|
|
916
|
+
success: false,
|
|
917
|
+
name: dependency.libName,
|
|
918
|
+
skipped: true,
|
|
919
|
+
skippedPlatforms: requestedPlatforms,
|
|
920
|
+
};
|
|
717
921
|
}
|
|
718
922
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
719
923
|
await linker.linkLib(localPath, storeCommitPath, linkPlatforms);
|
|
720
924
|
await ensureLinkedRegistryState(dependency.libName, dependency.commit, dependency.branch, dependency.url, linkPlatforms, projectHash, false);
|
|
721
|
-
const notLinkedPlatforms =
|
|
925
|
+
const notLinkedPlatforms = resolveRequestedPlatformsByActual(requestedPlatforms, dependency.sparse, linkPlatforms, configVars).missingRequested;
|
|
722
926
|
pLog.success(`${dependency.libName} (${dependency.commit.slice(0, 7)}) - 下载完成 [${linkPlatforms.join(', ')}]`);
|
|
723
927
|
return { success: true, name: dependency.libName, downloadedPlatforms: linkPlatforms, skippedPlatforms: notLinkedPlatforms };
|
|
724
928
|
}
|
|
@@ -783,20 +987,22 @@ async function linkScope(params) {
|
|
|
783
987
|
// 10. 同步 cache 文件
|
|
784
988
|
await syncCacheFile(configPath);
|
|
785
989
|
// 11. 构建返回结果
|
|
786
|
-
const
|
|
787
|
-
const
|
|
788
|
-
.
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
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
|
+
}
|
|
800
1006
|
return {
|
|
801
1007
|
linkedDeps, nestedLinkedDeps, generalLibs, downloadedLibs, savedBytes, finalLinkPlatforms, stats,
|
|
802
1008
|
};
|
|
@@ -1271,7 +1477,7 @@ async function ensureStoreInfo(libName, commit, platform, branch, url, projectHa
|
|
|
1271
1477
|
registry.addStoreReference(storeKey, projectHash);
|
|
1272
1478
|
}
|
|
1273
1479
|
}
|
|
1274
|
-
async function syncLibraryInfo(libName, commit, branch, url, platforms) {
|
|
1480
|
+
async function syncLibraryInfo(libName, commit, branch, url, platforms, isGeneral) {
|
|
1275
1481
|
const registry = getRegistry();
|
|
1276
1482
|
const libKey = registry.getLibraryKey(libName, commit);
|
|
1277
1483
|
const existingLibrary = registry.getLibrary(libKey);
|
|
@@ -1288,6 +1494,7 @@ async function syncLibraryInfo(libName, commit, branch, url, platforms) {
|
|
|
1288
1494
|
url,
|
|
1289
1495
|
platforms: normalizedPlatforms,
|
|
1290
1496
|
size: totalSize,
|
|
1497
|
+
isGeneral,
|
|
1291
1498
|
referencedBy: [],
|
|
1292
1499
|
createdAt: new Date().toISOString(),
|
|
1293
1500
|
lastAccess: new Date().toISOString(),
|
|
@@ -1299,6 +1506,7 @@ async function syncLibraryInfo(libName, commit, branch, url, platforms) {
|
|
|
1299
1506
|
url: url || existingLibrary.url,
|
|
1300
1507
|
platforms: normalizedPlatforms,
|
|
1301
1508
|
size: totalSize,
|
|
1509
|
+
isGeneral,
|
|
1302
1510
|
lastAccess: new Date().toISOString(),
|
|
1303
1511
|
});
|
|
1304
1512
|
}
|
|
@@ -1330,7 +1538,7 @@ async function ensureLinkedRegistryState(libName, commit, branch, url, platforms
|
|
|
1330
1538
|
if (!isGeneral) {
|
|
1331
1539
|
await registerSharedStore(libName, commit, branch, url);
|
|
1332
1540
|
}
|
|
1333
|
-
await syncLibraryInfo(libName, commit, branch, url, libraryPlatforms);
|
|
1541
|
+
await syncLibraryInfo(libName, commit, branch, url, libraryPlatforms, isGeneral);
|
|
1334
1542
|
}
|
|
1335
1543
|
/**
|
|
1336
1544
|
* 注册嵌套依赖到 Registry
|
|
@@ -1372,6 +1580,7 @@ async function registerNestedLibraries(nestedLibraries, projectHash) {
|
|
|
1372
1580
|
url: '',
|
|
1373
1581
|
platforms: [GENERAL_PLATFORM],
|
|
1374
1582
|
size: nested.size,
|
|
1583
|
+
isGeneral: true,
|
|
1375
1584
|
referencedBy: [],
|
|
1376
1585
|
createdAt: new Date().toISOString(),
|
|
1377
1586
|
lastAccess: new Date().toISOString(),
|
|
@@ -1410,6 +1619,7 @@ async function registerNestedLibraries(nestedLibraries, projectHash) {
|
|
|
1410
1619
|
url: '',
|
|
1411
1620
|
platforms: nested.platforms,
|
|
1412
1621
|
size: nested.size,
|
|
1622
|
+
isGeneral: false,
|
|
1413
1623
|
referencedBy: [],
|
|
1414
1624
|
createdAt: new Date().toISOString(),
|
|
1415
1625
|
lastAccess: new Date().toISOString(),
|
|
@@ -1474,7 +1684,7 @@ export async function classifyLinkStatus(localPath, storeCommitPath, isGeneral,
|
|
|
1474
1684
|
* @param configPath 配置文件路径
|
|
1475
1685
|
* @param platforms 请求的平台列表
|
|
1476
1686
|
*/
|
|
1477
|
-
async function classifyDependencies(dependencies, projectPath, configPath, platforms) {
|
|
1687
|
+
async function classifyDependencies(dependencies, projectPath, configPath, platforms, vars) {
|
|
1478
1688
|
const result = [];
|
|
1479
1689
|
const thirdPartyDir = path.dirname(configPath);
|
|
1480
1690
|
const storePath = await store.getStorePath();
|
|
@@ -1485,8 +1695,10 @@ async function classifyDependencies(dependencies, projectPath, configPath, platf
|
|
|
1485
1695
|
for (const dep of dependencies) {
|
|
1486
1696
|
const localPath = path.join(thirdPartyDir, dep.libName);
|
|
1487
1697
|
const storeLibPath = store.getLibraryPath(storePath, dep.libName, dep.commit, primaryPlatform);
|
|
1488
|
-
|
|
1489
|
-
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);
|
|
1490
1702
|
// 完整性校验:验证 existing 平台的文件完整性
|
|
1491
1703
|
const { valid: verifiedExisting, corrupted } = await verifyExistingPlatforms(dep.libName, dep.commit, rawExisting);
|
|
1492
1704
|
// 清除损坏的平台数据
|
|
@@ -1501,8 +1713,11 @@ async function classifyDependencies(dependencies, projectPath, configPath, platf
|
|
|
1501
1713
|
}
|
|
1502
1714
|
const existing = verifiedExisting;
|
|
1503
1715
|
// 也检查是否为 General 库(有 _shared 且有内容)
|
|
1504
|
-
const isGeneral = await
|
|
1716
|
+
const isGeneral = await resolveLibraryGeneralState(dep);
|
|
1505
1717
|
const inStore = existing.length > 0 || isGeneral;
|
|
1718
|
+
if (satisfiedRequested.length > 0) {
|
|
1719
|
+
clearSatisfiedAutoUnavailablePlatforms(getRegistry(), dep, satisfiedRequested);
|
|
1720
|
+
}
|
|
1506
1721
|
// 用于非 inStore 情况的本地路径状态检查
|
|
1507
1722
|
const expectedTarget = isGeneral
|
|
1508
1723
|
? path.join(storePath, dep.libName, dep.commit, '_shared')
|
|
@@ -1584,15 +1799,17 @@ async function classifyDependencies(dependencies, projectPath, configPath, platf
|
|
|
1584
1799
|
}
|
|
1585
1800
|
async function supplementMissingPlatforms(dependency, platforms, registry, tx, options = {}) {
|
|
1586
1801
|
const result = { downloaded: [], unavailable: [], nestedLibraries: [] };
|
|
1802
|
+
const blockedPlatforms = getBlockedRequestedPlatforms(registry, dependency, platforms, options.vars);
|
|
1803
|
+
const requestedPlatforms = platforms.filter((platform) => !blockedPlatforms.includes(platform));
|
|
1587
1804
|
// 1. 检查平台完整性
|
|
1588
|
-
const {
|
|
1805
|
+
const { missingRequested, satisfiedRequested } = await resolveRequestedStoreState(dependency, requestedPlatforms, options.vars);
|
|
1806
|
+
const missing = missingRequested;
|
|
1589
1807
|
if (missing.length === 0) {
|
|
1808
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, satisfiedRequested);
|
|
1590
1809
|
return result;
|
|
1591
1810
|
}
|
|
1592
1811
|
// 2. 获取已知不可用平台
|
|
1593
|
-
const
|
|
1594
|
-
const libInfo = registry.getLibrary(libKey);
|
|
1595
|
-
const unavailablePlatforms = libInfo?.unavailablePlatforms || [];
|
|
1812
|
+
const unavailablePlatforms = blockedPlatforms;
|
|
1596
1813
|
// 3. 计算需要下载的平台(排除已知不可用的,除非强制下载)
|
|
1597
1814
|
const toDownload = options.forceDownload
|
|
1598
1815
|
? missing
|
|
@@ -1600,7 +1817,7 @@ async function supplementMissingPlatforms(dependency, platforms, registry, tx, o
|
|
|
1600
1817
|
if (toDownload.length === 0) {
|
|
1601
1818
|
// 所有缺失平台都是已知不可用的
|
|
1602
1819
|
if (missing.length > 0) {
|
|
1603
|
-
hint(`${dependency.libName} 平台 [${missing.join(', ')}]
|
|
1820
|
+
hint(`${dependency.libName} 平台 [${missing.join(', ')}] 已按规则跳过`);
|
|
1604
1821
|
}
|
|
1605
1822
|
result.unavailable = missing.filter((p) => unavailablePlatforms.includes(p));
|
|
1606
1823
|
return result;
|
|
@@ -1622,18 +1839,20 @@ async function supplementMissingPlatforms(dependency, platforms, registry, tx, o
|
|
|
1622
1839
|
hint(` 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
1623
1840
|
}
|
|
1624
1841
|
try {
|
|
1625
|
-
// 5.
|
|
1626
|
-
const
|
|
1842
|
+
// 5. 解释下载结果
|
|
1843
|
+
const assessment = assessDownloadResult(toDownload, dependency.sparse, downloadResult, options.vars);
|
|
1844
|
+
const downloaded = assessment.downloadedRequested;
|
|
1627
1845
|
result.downloaded = downloaded;
|
|
1846
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dependency, assessment.satisfiedRequested);
|
|
1628
1847
|
// 6. 记录新发现的不可用平台
|
|
1629
|
-
const notFound =
|
|
1848
|
+
const notFound = assessment.unavailableRequested;
|
|
1630
1849
|
if (notFound.length > 0) {
|
|
1631
1850
|
result.unavailable = notFound;
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
}
|
|
1851
|
+
const newUnavailable = [...new Set([...unavailablePlatforms, ...notFound])];
|
|
1852
|
+
upsertLibraryAvailability(dependency, {
|
|
1853
|
+
unavailablePlatforms: newUnavailable,
|
|
1854
|
+
isGeneral: false,
|
|
1855
|
+
});
|
|
1637
1856
|
warn(`${dependency.libName} 平台 [${notFound.join(', ')}] 远程不存在,已记录`);
|
|
1638
1857
|
}
|
|
1639
1858
|
// 7. 吸收下载的内容到 Store(不做链接,由调用者负责)
|
|
@@ -1886,7 +2105,6 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
1886
2105
|
const nestedTargetDir = path.join(thirdPartyDir, targetDir);
|
|
1887
2106
|
const { tx, registry, projectHash, projectRoot, dryRun, download, generalLibs, downloadedLibs, nestedLinkedDeps } = options;
|
|
1888
2107
|
const { platforms, vars } = context;
|
|
1889
|
-
const primaryPlatform = platforms[0];
|
|
1890
2108
|
for (const dep of dependencies) {
|
|
1891
2109
|
const localPath = path.join(nestedTargetDir, dep.libName);
|
|
1892
2110
|
const storePath = await store.getStorePath();
|
|
@@ -1905,18 +2123,18 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
1905
2123
|
// 检查 Store 状态和历史记录
|
|
1906
2124
|
const libKey = registry.getLibraryKey(dep.libName, dep.commit);
|
|
1907
2125
|
const historyLib = registry.getLibrary(libKey);
|
|
1908
|
-
const unavailablePlatforms =
|
|
2126
|
+
const unavailablePlatforms = getBlockedRequestedPlatforms(registry, dep, platforms, vars);
|
|
1909
2127
|
// 过滤掉已知不可用的平台
|
|
1910
2128
|
const availablePlatforms = platforms.filter(p => !unavailablePlatforms.includes(p));
|
|
1911
2129
|
const knownUnavailable = platforms.filter(p => unavailablePlatforms.includes(p));
|
|
1912
2130
|
let storeHas = false;
|
|
1913
2131
|
const existingPlatforms = [];
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
}
|
|
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);
|
|
1919
2136
|
}
|
|
2137
|
+
storeHas = existingPlatforms.length > 0;
|
|
1920
2138
|
// 完整性校验:验证 existing 平台的文件完整性(与 classifyDependencies 同逻辑)
|
|
1921
2139
|
if (existingPlatforms.length > 0) {
|
|
1922
2140
|
const { valid: verifiedPlatforms, corrupted } = await verifyExistingPlatforms(dep.libName, dep.commit, existingPlatforms);
|
|
@@ -1930,10 +2148,10 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
1930
2148
|
storeHas = verifiedPlatforms.length > 0;
|
|
1931
2149
|
}
|
|
1932
2150
|
}
|
|
1933
|
-
let isGeneral = await
|
|
2151
|
+
let isGeneral = await resolveLibraryGeneralState(dep);
|
|
1934
2152
|
// 如果所有平台都已知不可用,跳过
|
|
1935
2153
|
if (availablePlatforms.length === 0 && knownUnavailable.length > 0 && !isGeneral) {
|
|
1936
|
-
warn(`${indent} ${dep.libName} - 平台 [${knownUnavailable.join(', ')}]
|
|
2154
|
+
warn(`${indent} ${dep.libName} - 平台 [${knownUnavailable.join(', ')}] 已按规则跳过`);
|
|
1937
2155
|
continue;
|
|
1938
2156
|
}
|
|
1939
2157
|
// Store 没有,但本地是目录时,验证 commit 并尝试 absorb
|
|
@@ -1970,14 +2188,16 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
1970
2188
|
sparse: dep.sparse,
|
|
1971
2189
|
vars,
|
|
1972
2190
|
});
|
|
1973
|
-
|
|
2191
|
+
const assessment = assessDownloadResult(availablePlatforms, dep.sparse, downloadResult, vars);
|
|
2192
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dep, assessment.satisfiedRequested);
|
|
2193
|
+
if (assessment.downloadedRequested.length > 0) {
|
|
1974
2194
|
// 有平台内容 → 吸收平台目录,重新分类为平台库
|
|
1975
2195
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
1976
|
-
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir,
|
|
2196
|
+
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir, assessment.downloadedRequested, dep.libName, dep.commit);
|
|
1977
2197
|
await registerNestedLibraries(nestedAbsorbResult.nestedLibraries, projectHash);
|
|
1978
|
-
existingPlatforms.push(...
|
|
2198
|
+
existingPlatforms.push(...assessment.downloadedRequested);
|
|
1979
2199
|
isGeneral = false;
|
|
1980
|
-
info(`${indent} ${dep.libName} - 补充平台内容 [${
|
|
2200
|
+
info(`${indent} ${dep.libName} - 补充平台内容 [${assessment.downloadedRequested.join(', ')}]`);
|
|
1981
2201
|
}
|
|
1982
2202
|
if (downloadResult.cleanedPlatforms.length > 0) {
|
|
1983
2203
|
hint(`${indent} 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
@@ -2032,7 +2252,7 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2032
2252
|
nestedLinkedDeps.push({
|
|
2033
2253
|
libName: dep.libName,
|
|
2034
2254
|
commit: dep.commit,
|
|
2035
|
-
platform: isGeneral ? GENERAL_PLATFORM :
|
|
2255
|
+
platform: isGeneral ? GENERAL_PLATFORM : (linkedPlatforms[0] ?? availablePlatforms[0]),
|
|
2036
2256
|
linkedPath: path.relative(projectRoot, localPath),
|
|
2037
2257
|
});
|
|
2038
2258
|
if (!isGeneral) {
|
|
@@ -2095,7 +2315,7 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2095
2315
|
nestedLinkedDeps.push({
|
|
2096
2316
|
libName: dep.libName,
|
|
2097
2317
|
commit: dep.commit,
|
|
2098
|
-
platform:
|
|
2318
|
+
platform: allPlatforms[0],
|
|
2099
2319
|
linkedPath: path.relative(projectRoot, localPath),
|
|
2100
2320
|
});
|
|
2101
2321
|
success(`${indent} ${dep.libName} - 链接完成 [${allPlatforms.join(', ')}]`);
|
|
@@ -2137,10 +2357,14 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2137
2357
|
if (downloadResult.cleanedPlatforms.length > 0) {
|
|
2138
2358
|
hint(`${indent} 已过滤: ${downloadResult.cleanedPlatforms.join(', ')}`);
|
|
2139
2359
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
if (
|
|
2360
|
+
const assessment = assessDownloadResult(availablePlatforms, dep.sparse, downloadResult, vars);
|
|
2361
|
+
clearSatisfiedAutoUnavailablePlatforms(registry, dep, assessment.satisfiedRequested);
|
|
2362
|
+
if (assessment.isPureGeneral) {
|
|
2143
2363
|
// General 库处理
|
|
2364
|
+
upsertLibraryAvailability(dep, {
|
|
2365
|
+
platforms: [GENERAL_PLATFORM],
|
|
2366
|
+
isGeneral: true,
|
|
2367
|
+
});
|
|
2144
2368
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
2145
2369
|
await store.absorbGeneral(downloadResult.libDir, dep.libName, dep.commit);
|
|
2146
2370
|
const sharedPath = path.join(storeCommitPath, '_shared');
|
|
@@ -2158,67 +2382,42 @@ async function linkNestedDependencies(dependencies, params) {
|
|
|
2158
2382
|
});
|
|
2159
2383
|
success(`${indent} ${dep.libName} - 下载完成 (General)`);
|
|
2160
2384
|
}
|
|
2161
|
-
else if (
|
|
2385
|
+
else if (assessment.downloadedRequested.length > 0) {
|
|
2162
2386
|
// 平台库处理
|
|
2163
2387
|
tx.recordOp('absorb', storeCommitPath, downloadResult.libDir);
|
|
2164
|
-
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir,
|
|
2388
|
+
const nestedAbsorbResult = await store.absorbLib(downloadResult.libDir, assessment.downloadedRequested, dep.libName, dep.commit);
|
|
2165
2389
|
await registerNestedLibraries(nestedAbsorbResult.nestedLibraries, projectHash);
|
|
2166
2390
|
tx.recordOp('link', localPath, storeCommitPath);
|
|
2167
|
-
await linker.linkLib(localPath, storeCommitPath,
|
|
2168
|
-
await ensureLinkedRegistryState(dep.libName, dep.commit, dep.branch, dep.url,
|
|
2391
|
+
await linker.linkLib(localPath, storeCommitPath, assessment.downloadedRequested);
|
|
2392
|
+
await ensureLinkedRegistryState(dep.libName, dep.commit, dep.branch, dep.url, assessment.downloadedRequested, projectHash, false);
|
|
2169
2393
|
downloadedLibs.push(dep.libName);
|
|
2170
2394
|
// 记录到 nestedLinkedDeps
|
|
2171
2395
|
nestedLinkedDeps.push({
|
|
2172
2396
|
libName: dep.libName,
|
|
2173
2397
|
commit: dep.commit,
|
|
2174
|
-
platform:
|
|
2398
|
+
platform: assessment.downloadedRequested[0],
|
|
2175
2399
|
linkedPath: path.relative(projectRoot, localPath),
|
|
2176
2400
|
});
|
|
2177
2401
|
// 检查并记录新发现的不可用平台
|
|
2178
|
-
const newUnavailable =
|
|
2402
|
+
const newUnavailable = assessment.unavailableRequested;
|
|
2179
2403
|
if (newUnavailable.length > 0) {
|
|
2180
2404
|
const updatedUnavailable = [...new Set([...unavailablePlatforms, ...newUnavailable])];
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
libName: dep.libName,
|
|
2187
|
-
commit: dep.commit,
|
|
2188
|
-
branch: dep.branch,
|
|
2189
|
-
url: dep.url,
|
|
2190
|
-
platforms: downloadResult.platformDirs,
|
|
2191
|
-
size: 0,
|
|
2192
|
-
referencedBy: [],
|
|
2193
|
-
unavailablePlatforms: newUnavailable,
|
|
2194
|
-
createdAt: new Date().toISOString(),
|
|
2195
|
-
lastAccess: new Date().toISOString(),
|
|
2196
|
-
});
|
|
2197
|
-
}
|
|
2405
|
+
upsertLibraryAvailability(dep, {
|
|
2406
|
+
unavailablePlatforms: updatedUnavailable,
|
|
2407
|
+
platforms: assessment.downloadedRequested,
|
|
2408
|
+
isGeneral: false,
|
|
2409
|
+
});
|
|
2198
2410
|
warn(`${indent} ${dep.libName} 平台 [${newUnavailable.join(', ')}] 远程不存在,已记录`);
|
|
2199
2411
|
}
|
|
2200
|
-
success(`${indent} ${dep.libName} - 下载完成 [${
|
|
2412
|
+
success(`${indent} ${dep.libName} - 下载完成 [${assessment.downloadedRequested.join(', ')}]`);
|
|
2201
2413
|
}
|
|
2202
2414
|
else {
|
|
2203
2415
|
// 所有请求的平台都不可用,记录到 registry
|
|
2204
2416
|
const newUnavailable = [...new Set([...unavailablePlatforms, ...availablePlatforms])];
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
registry.addLibrary({
|
|
2210
|
-
libName: dep.libName,
|
|
2211
|
-
commit: dep.commit,
|
|
2212
|
-
branch: dep.branch,
|
|
2213
|
-
url: dep.url,
|
|
2214
|
-
platforms: [],
|
|
2215
|
-
size: 0,
|
|
2216
|
-
referencedBy: [],
|
|
2217
|
-
unavailablePlatforms: newUnavailable,
|
|
2218
|
-
createdAt: new Date().toISOString(),
|
|
2219
|
-
lastAccess: new Date().toISOString(),
|
|
2220
|
-
});
|
|
2221
|
-
}
|
|
2417
|
+
upsertLibraryAvailability(dep, {
|
|
2418
|
+
unavailablePlatforms: newUnavailable,
|
|
2419
|
+
isGeneral: false,
|
|
2420
|
+
});
|
|
2222
2421
|
warn(`${indent} ${dep.libName} - 下载成功但平台 [${availablePlatforms.join(', ')}] 不可用,已记录`);
|
|
2223
2422
|
}
|
|
2224
2423
|
// 清理临时目录
|