@git.zone/tsrust 1.8.0 → 1.9.0
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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +3 -1
- package/dist_ts/mod_artifact/classes.artifactassembler.d.ts +48 -0
- package/dist_ts/mod_artifact/classes.artifactassembler.js +842 -0
- package/dist_ts/mod_artifact/index.d.ts +1 -0
- package/dist_ts/mod_artifact/index.js +2 -0
- package/dist_ts/mod_cli/classes.tsrustcli.d.ts +5 -2
- package/dist_ts/mod_cli/classes.tsrustcli.js +110 -75
- package/dist_ts/mod_cli/helpers.targets.d.ts +20 -0
- package/dist_ts/mod_cli/helpers.targets.js +106 -0
- package/dist_ts/mod_cli/index.d.ts +1 -0
- package/dist_ts/mod_cli/index.js +2 -1
- package/dist_ts/mod_elf/classes.provenance.d.ts +2 -1
- package/dist_ts/mod_elf/classes.provenance.js +0 -0
- package/dist_ts/mod_provenance/classes.gitstate.d.ts +7 -0
- package/dist_ts/mod_provenance/classes.gitstate.js +34 -0
- package/dist_ts/mod_provenance/classes.provenancestore.d.ts +11 -0
- package/dist_ts/mod_provenance/classes.provenancestore.js +184 -0
- package/dist_ts/mod_provenance/helpers.owneridentity.d.ts +2 -0
- package/dist_ts/mod_provenance/helpers.owneridentity.js +57 -0
- package/dist_ts/mod_provenance/index.d.ts +3 -0
- package/dist_ts/mod_provenance/index.js +4 -0
- package/package.json +3 -3
- package/readme.hints.md +6 -3
- package/readme.md +77 -5
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +2 -0
- package/ts/mod_artifact/classes.artifactassembler.ts +1028 -0
- package/ts/mod_artifact/index.ts +6 -0
- package/ts/mod_cli/classes.tsrustcli.ts +162 -95
- package/ts/mod_cli/helpers.targets.ts +141 -0
- package/ts/mod_cli/index.ts +10 -0
- package/ts/mod_elf/classes.provenance.ts +0 -0
- package/ts/mod_provenance/classes.gitstate.ts +49 -0
- package/ts/mod_provenance/classes.provenancestore.ts +194 -0
- package/ts/mod_provenance/helpers.owneridentity.ts +57 -0
- package/ts/mod_provenance/index.ts +10 -0
|
@@ -0,0 +1,842 @@
|
|
|
1
|
+
import * as crypto from 'crypto';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { captureGitSnapshot, getHostIdentity, isLocalProcessRunning, PROVENANCE_SIDECAR_SUFFIX, ProvenanceStore, } from '../mod_provenance/index.js';
|
|
6
|
+
const TRANSACTION_FORMAT = 'tsrust.artifact-assembly.v1';
|
|
7
|
+
const LOCK_FORMAT = 'tsrust.artifact-assembly-lock.v1';
|
|
8
|
+
const RECOVERY_CLAIM_FORMAT = 'tsrust.artifact-assembly-recovery.v1';
|
|
9
|
+
const TRANSACTION_DIRECTORY = 'tsrust-assembly';
|
|
10
|
+
const activeOwnerTokens = new Set();
|
|
11
|
+
const processOwnerTokens = new Set();
|
|
12
|
+
function isSameOrWithin(parentArg, candidateArg) {
|
|
13
|
+
const relative = path.relative(parentArg, candidateArg);
|
|
14
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
15
|
+
}
|
|
16
|
+
async function lstatOptional(filePathArg) {
|
|
17
|
+
try {
|
|
18
|
+
return await fs.promises.lstat(filePathArg);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error.code === 'ENOENT')
|
|
22
|
+
return undefined;
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function syncFile(filePathArg) {
|
|
27
|
+
const handle = await fs.promises.open(filePathArg, 'r');
|
|
28
|
+
try {
|
|
29
|
+
await handle.sync();
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
await handle.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function syncDirectory(directoryPathArg) {
|
|
36
|
+
const handle = await fs.promises.open(directoryPathArg, 'r');
|
|
37
|
+
try {
|
|
38
|
+
await handle.sync();
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
await handle.close();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function assertArtifactName(nameArg, labelArg) {
|
|
45
|
+
if (!nameArg || nameArg.length > 255 || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(nameArg)) {
|
|
46
|
+
throw new Error(`Invalid ${labelArg}: ${JSON.stringify(nameArg)}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function isProvenanceTemporaryFile(nameArg) {
|
|
50
|
+
return /\.tsrust-build\.json\.[a-f0-9]{64}\.\d+\.[a-f0-9-]{36}\.tmp$/.test(nameArg);
|
|
51
|
+
}
|
|
52
|
+
function isTransactionState(valueArg) {
|
|
53
|
+
if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg))
|
|
54
|
+
return false;
|
|
55
|
+
const value = valueArg;
|
|
56
|
+
return (value.format === TRANSACTION_FORMAT &&
|
|
57
|
+
typeof value.pid === 'number' &&
|
|
58
|
+
typeof value.hostname === 'string' &&
|
|
59
|
+
typeof value.hostIdentity === 'string' &&
|
|
60
|
+
/^[a-f0-9]{64}$/.test(value.hostIdentity) &&
|
|
61
|
+
typeof value.ownerToken === 'string' &&
|
|
62
|
+
/^[a-f0-9-]{36}$/.test(value.ownerToken) &&
|
|
63
|
+
typeof value.startedAt === 'string' &&
|
|
64
|
+
[
|
|
65
|
+
'preparing',
|
|
66
|
+
'prepared',
|
|
67
|
+
'movingOld',
|
|
68
|
+
'oldMoved',
|
|
69
|
+
'publishing',
|
|
70
|
+
'published',
|
|
71
|
+
'committing',
|
|
72
|
+
'committed',
|
|
73
|
+
].includes(String(value.phase)) &&
|
|
74
|
+
typeof value.hadExistingOutput === 'boolean');
|
|
75
|
+
}
|
|
76
|
+
function isLockOwner(valueArg) {
|
|
77
|
+
if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg))
|
|
78
|
+
return false;
|
|
79
|
+
const value = valueArg;
|
|
80
|
+
return (value.format === LOCK_FORMAT &&
|
|
81
|
+
typeof value.pid === 'number' &&
|
|
82
|
+
typeof value.hostname === 'string' &&
|
|
83
|
+
typeof value.hostIdentity === 'string' &&
|
|
84
|
+
/^[a-f0-9]{64}$/.test(value.hostIdentity) &&
|
|
85
|
+
typeof value.ownerToken === 'string' &&
|
|
86
|
+
/^[a-f0-9-]{36}$/.test(value.ownerToken) &&
|
|
87
|
+
typeof value.startedAt === 'string');
|
|
88
|
+
}
|
|
89
|
+
function isRecoveryClaim(valueArg) {
|
|
90
|
+
if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg))
|
|
91
|
+
return false;
|
|
92
|
+
const value = valueArg;
|
|
93
|
+
return (value.format === RECOVERY_CLAIM_FORMAT &&
|
|
94
|
+
typeof value.pid === 'number' &&
|
|
95
|
+
typeof value.hostname === 'string' &&
|
|
96
|
+
typeof value.hostIdentity === 'string' &&
|
|
97
|
+
/^[a-f0-9]{64}$/.test(value.hostIdentity) &&
|
|
98
|
+
typeof value.ownerToken === 'string' &&
|
|
99
|
+
/^[a-f0-9-]{36}$/.test(value.ownerToken) &&
|
|
100
|
+
typeof value.startedAt === 'string' &&
|
|
101
|
+
typeof value.targetOwnerToken === 'string' &&
|
|
102
|
+
/^[a-f0-9-]{36}$/.test(value.targetOwnerToken));
|
|
103
|
+
}
|
|
104
|
+
export class ArtifactAssembler {
|
|
105
|
+
options;
|
|
106
|
+
constructor(optionsArg) {
|
|
107
|
+
this.options = optionsArg;
|
|
108
|
+
}
|
|
109
|
+
async assemble() {
|
|
110
|
+
const ownerToken = crypto.randomUUID();
|
|
111
|
+
const paths = this.createPaths(ownerToken);
|
|
112
|
+
const sourceDirectories = this.options.sourceDirectories.map((sourceDirectory) => path.resolve(paths.workspace, sourceDirectory));
|
|
113
|
+
this.validateOptions(paths, sourceDirectories);
|
|
114
|
+
let state = {
|
|
115
|
+
format: TRANSACTION_FORMAT,
|
|
116
|
+
pid: process.pid,
|
|
117
|
+
hostname: os.hostname(),
|
|
118
|
+
hostIdentity: getHostIdentity(),
|
|
119
|
+
ownerToken,
|
|
120
|
+
startedAt: new Date().toISOString(),
|
|
121
|
+
phase: 'preparing',
|
|
122
|
+
hadExistingOutput: false,
|
|
123
|
+
};
|
|
124
|
+
await this.ensureTransactionParent(paths);
|
|
125
|
+
processOwnerTokens.add(ownerToken);
|
|
126
|
+
try {
|
|
127
|
+
await this.acquireTransaction(paths, state);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
try {
|
|
131
|
+
const lockOwner = await this.readLock(paths);
|
|
132
|
+
if (lockOwner?.ownerToken !== ownerToken)
|
|
133
|
+
processOwnerTokens.delete(ownerToken);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Retain the token only when lock ownership cannot be determined safely.
|
|
137
|
+
}
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
let commitReached = false;
|
|
141
|
+
let retainOwnerToken = false;
|
|
142
|
+
activeOwnerTokens.add(ownerToken);
|
|
143
|
+
try {
|
|
144
|
+
const output = await lstatOptional(paths.outputDirectory);
|
|
145
|
+
if (output && (!output.isDirectory() || output.isSymbolicLink())) {
|
|
146
|
+
throw new Error(`Assembly output is not a regular directory: ${paths.outputDirectory}`);
|
|
147
|
+
}
|
|
148
|
+
state.hadExistingOutput = !!output;
|
|
149
|
+
await this.writeState(paths, state);
|
|
150
|
+
const candidates = await this.collectCandidates(sourceDirectories);
|
|
151
|
+
await fs.promises.mkdir(paths.stagingDirectory, { mode: 0o700 });
|
|
152
|
+
for (const candidate of candidates) {
|
|
153
|
+
const destinationBinary = path.join(paths.stagingDirectory, candidate.destinationName);
|
|
154
|
+
const destinationSidecar = ProvenanceStore.sidecarPath(destinationBinary);
|
|
155
|
+
await fs.promises.copyFile(candidate.binaryPath, destinationBinary, fs.constants.COPYFILE_EXCL);
|
|
156
|
+
await fs.promises.copyFile(candidate.sidecarPath, destinationSidecar, fs.constants.COPYFILE_EXCL);
|
|
157
|
+
await syncFile(destinationBinary);
|
|
158
|
+
await syncFile(destinationSidecar);
|
|
159
|
+
const copiedBuildInfo = await ProvenanceStore.readSidecar(destinationBinary);
|
|
160
|
+
if (JSON.stringify(copiedBuildInfo) !== JSON.stringify(candidate.buildInfo)) {
|
|
161
|
+
throw new Error(`Artifact provenance changed while copying ${candidate.binaryPath}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
await fs.promises.chmod(paths.stagingDirectory, 0o755);
|
|
165
|
+
await syncDirectory(paths.stagingDirectory);
|
|
166
|
+
state = { ...state, phase: 'prepared' };
|
|
167
|
+
await this.writeState(paths, state);
|
|
168
|
+
await this.assertAssemblySourceUnchanged(paths.workspace);
|
|
169
|
+
if (state.hadExistingOutput) {
|
|
170
|
+
state = { ...state, phase: 'movingOld' };
|
|
171
|
+
await this.writeState(paths, state);
|
|
172
|
+
await fs.promises.rename(paths.outputDirectory, paths.backupDirectory);
|
|
173
|
+
await syncDirectory(paths.workspace);
|
|
174
|
+
state = { ...state, phase: 'oldMoved' };
|
|
175
|
+
await this.writeState(paths, state);
|
|
176
|
+
}
|
|
177
|
+
state = { ...state, phase: 'publishing' };
|
|
178
|
+
await this.writeState(paths, state);
|
|
179
|
+
state = { ...state, phase: 'committing' };
|
|
180
|
+
try {
|
|
181
|
+
await this.writeState(paths, state);
|
|
182
|
+
commitReached = true;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
let persistedState;
|
|
186
|
+
try {
|
|
187
|
+
persistedState = await this.readState(paths);
|
|
188
|
+
}
|
|
189
|
+
catch (stateError) {
|
|
190
|
+
commitReached = true;
|
|
191
|
+
throw new AggregateError([error, stateError], `Artifact commit state is unreadable in ${paths.transactionDirectory}`);
|
|
192
|
+
}
|
|
193
|
+
if (persistedState?.ownerToken === ownerToken &&
|
|
194
|
+
persistedState.phase === 'publishing') {
|
|
195
|
+
state = persistedState;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
// Recovery follows whichever commit phase reached state.json; do not
|
|
199
|
+
// make a second, potentially contradictory decision here.
|
|
200
|
+
commitReached = true;
|
|
201
|
+
}
|
|
202
|
+
throw new Error(commitReached
|
|
203
|
+
? `Artifact commit intent is pending in ${paths.transactionDirectory}`
|
|
204
|
+
: 'Failed to persist artifact commit intent', { cause: error });
|
|
205
|
+
}
|
|
206
|
+
const cleanupPending = await this.completeCommittedTransaction(paths, state);
|
|
207
|
+
retainOwnerToken = cleanupPending;
|
|
208
|
+
return {
|
|
209
|
+
outputDirectory: paths.outputDirectory,
|
|
210
|
+
artifactCount: candidates.length,
|
|
211
|
+
binaries: [...this.options.expectedBinaries].sort(),
|
|
212
|
+
targets: this.options.expectedTargets.map((target) => target.friendly).sort(),
|
|
213
|
+
cleanupPending,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
if (!commitReached) {
|
|
218
|
+
try {
|
|
219
|
+
await this.rollbackTransaction(paths, state);
|
|
220
|
+
}
|
|
221
|
+
catch (rollbackError) {
|
|
222
|
+
retainOwnerToken = true;
|
|
223
|
+
throw new AggregateError([error, rollbackError], `Artifact assembly failed and rollback is pending in ${paths.transactionDirectory}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
retainOwnerToken = true;
|
|
228
|
+
}
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
activeOwnerTokens.delete(ownerToken);
|
|
233
|
+
if (!retainOwnerToken) {
|
|
234
|
+
processOwnerTokens.delete(ownerToken);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
try {
|
|
238
|
+
if (!(await lstatOptional(paths.lockPath))) {
|
|
239
|
+
processOwnerTokens.delete(ownerToken);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Keep the token so a same-process retry can recover the transaction.
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
createPaths(ownerTokenArg) {
|
|
249
|
+
const workspace = path.resolve(this.options.workspace);
|
|
250
|
+
const transactionParent = path.join(workspace, '.nogit');
|
|
251
|
+
const transactionDirectory = path.join(transactionParent, TRANSACTION_DIRECTORY);
|
|
252
|
+
return {
|
|
253
|
+
workspace,
|
|
254
|
+
outputDirectory: path.join(workspace, 'dist_rust'),
|
|
255
|
+
transactionParent,
|
|
256
|
+
transactionDirectory,
|
|
257
|
+
lockPath: path.join(transactionParent, 'tsrust-assembly.lock'),
|
|
258
|
+
lockSourcePath: path.join(transactionParent, `.tsrust-assembly-owner.${ownerTokenArg}.tmp`),
|
|
259
|
+
recoveryClaimPath: path.join(transactionParent, 'tsrust-assembly.recovery.lock'),
|
|
260
|
+
statePath: path.join(transactionDirectory, 'state.json'),
|
|
261
|
+
stateTemporaryPath: path.join(transactionDirectory, 'state.json.tmp'),
|
|
262
|
+
stagingDirectory: path.join(transactionDirectory, 'staging'),
|
|
263
|
+
backupDirectory: path.join(transactionDirectory, 'backup'),
|
|
264
|
+
failedDirectory: path.join(transactionDirectory, 'failed'),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
validateOptions(pathsArg, sourceDirectoriesArg) {
|
|
268
|
+
if (sourceDirectoriesArg.length === 0) {
|
|
269
|
+
throw new Error('Artifact assembly requires at least one source directory');
|
|
270
|
+
}
|
|
271
|
+
if (new Set(sourceDirectoriesArg).size !== sourceDirectoriesArg.length) {
|
|
272
|
+
throw new Error('Artifact assembly source directories must be unique');
|
|
273
|
+
}
|
|
274
|
+
if (this.options.expectedTargets.length === 0) {
|
|
275
|
+
throw new Error('Artifact assembly requires at least one expected target');
|
|
276
|
+
}
|
|
277
|
+
if (this.options.expectedBinaries.length === 0) {
|
|
278
|
+
throw new Error('Artifact assembly requires at least one expected binary');
|
|
279
|
+
}
|
|
280
|
+
for (const binary of this.options.expectedBinaries) {
|
|
281
|
+
assertArtifactName(binary, 'binary name');
|
|
282
|
+
}
|
|
283
|
+
if (new Set(this.options.expectedBinaries).size !== this.options.expectedBinaries.length) {
|
|
284
|
+
throw new Error('Expected artifact binary names must be unique');
|
|
285
|
+
}
|
|
286
|
+
const targetNames = this.options.expectedTargets.map((target) => target.friendly);
|
|
287
|
+
const targetTriples = this.options.expectedTargets.map((target) => target.triple);
|
|
288
|
+
if (new Set(targetNames).size !== targetNames.length ||
|
|
289
|
+
new Set(targetTriples).size !== targetTriples.length) {
|
|
290
|
+
throw new Error('Expected artifact targets must be unique');
|
|
291
|
+
}
|
|
292
|
+
if (!/^[a-f0-9]{40}([a-f0-9]{24})?$/.test(this.options.expectedGitCommit)) {
|
|
293
|
+
throw new Error('Artifact assembly requires an exact Git commit');
|
|
294
|
+
}
|
|
295
|
+
for (const target of this.options.expectedTargets) {
|
|
296
|
+
assertArtifactName(target.friendly, 'target name');
|
|
297
|
+
assertArtifactName(target.triple, 'target triple');
|
|
298
|
+
}
|
|
299
|
+
for (const sourceDirectory of sourceDirectoriesArg) {
|
|
300
|
+
if (isSameOrWithin(sourceDirectory, pathsArg.outputDirectory) ||
|
|
301
|
+
isSameOrWithin(pathsArg.outputDirectory, sourceDirectory) ||
|
|
302
|
+
isSameOrWithin(sourceDirectory, pathsArg.transactionDirectory) ||
|
|
303
|
+
isSameOrWithin(pathsArg.transactionDirectory, sourceDirectory)) {
|
|
304
|
+
throw new Error(`Artifact source overlaps tsrust-owned output: ${sourceDirectory}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async ensureTransactionParent(pathsArg) {
|
|
309
|
+
const existing = await lstatOptional(pathsArg.transactionParent);
|
|
310
|
+
if (existing) {
|
|
311
|
+
if (!existing.isDirectory() || existing.isSymbolicLink()) {
|
|
312
|
+
throw new Error(`tsrust state path is not a regular directory: ${pathsArg.transactionParent}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
await fs.promises.mkdir(pathsArg.transactionParent, { mode: 0o700 });
|
|
317
|
+
}
|
|
318
|
+
const workspace = await fs.promises.stat(pathsArg.workspace);
|
|
319
|
+
const transactionParent = await fs.promises.stat(pathsArg.transactionParent);
|
|
320
|
+
if (workspace.dev !== transactionParent.dev) {
|
|
321
|
+
throw new Error('tsrust assembly state and dist_rust must be on the same filesystem');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async acquireTransaction(pathsArg, stateArg) {
|
|
325
|
+
await this.cleanupAbandonedLockSources(pathsArg);
|
|
326
|
+
if ((await lstatOptional(pathsArg.transactionDirectory)) &&
|
|
327
|
+
!(await lstatOptional(pathsArg.lockPath))) {
|
|
328
|
+
throw new Error(`Assembly data exists without its owner lock: ${pathsArg.transactionDirectory}`);
|
|
329
|
+
}
|
|
330
|
+
const owner = this.lockOwnerFromState(stateArg);
|
|
331
|
+
await this.writeLockSource(pathsArg, owner);
|
|
332
|
+
let ownsLock = false;
|
|
333
|
+
let transactionCreated = false;
|
|
334
|
+
try {
|
|
335
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
336
|
+
await this.clearAbandonedRecoveryClaim(pathsArg);
|
|
337
|
+
try {
|
|
338
|
+
await fs.promises.link(pathsArg.lockSourcePath, pathsArg.lockPath);
|
|
339
|
+
ownsLock = true;
|
|
340
|
+
await syncDirectory(pathsArg.transactionParent);
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
if (error.code !== 'EEXIST')
|
|
345
|
+
throw error;
|
|
346
|
+
if (attempt > 0) {
|
|
347
|
+
throw new Error(`Unable to clear stale assembly lock: ${pathsArg.lockPath}`);
|
|
348
|
+
}
|
|
349
|
+
await this.recoverExistingTransaction(pathsArg);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
await fs.promises.unlink(pathsArg.lockSourcePath);
|
|
353
|
+
await fs.promises.mkdir(pathsArg.transactionDirectory, { mode: 0o700 });
|
|
354
|
+
transactionCreated = true;
|
|
355
|
+
await syncDirectory(pathsArg.transactionParent);
|
|
356
|
+
await this.writeState(pathsArg, stateArg);
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
if (transactionCreated) {
|
|
360
|
+
await fs.promises.rm(pathsArg.transactionDirectory, { recursive: true, force: true });
|
|
361
|
+
}
|
|
362
|
+
if (ownsLock) {
|
|
363
|
+
await this.releaseLock(pathsArg, owner.ownerToken);
|
|
364
|
+
}
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
await Promise.allSettled([fs.promises.rm(pathsArg.lockSourcePath, { force: true })]);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
lockOwnerFromState(stateArg) {
|
|
372
|
+
return {
|
|
373
|
+
format: LOCK_FORMAT,
|
|
374
|
+
pid: stateArg.pid,
|
|
375
|
+
hostname: stateArg.hostname,
|
|
376
|
+
hostIdentity: stateArg.hostIdentity,
|
|
377
|
+
ownerToken: stateArg.ownerToken,
|
|
378
|
+
startedAt: stateArg.startedAt,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
async writeLockSource(pathsArg, ownerArg) {
|
|
382
|
+
const lockSource = await fs.promises.open(pathsArg.lockSourcePath, 'wx', 0o600);
|
|
383
|
+
try {
|
|
384
|
+
await lockSource.writeFile(`${JSON.stringify(ownerArg, null, 2)}\n`, 'utf8');
|
|
385
|
+
await lockSource.sync();
|
|
386
|
+
}
|
|
387
|
+
finally {
|
|
388
|
+
await lockSource.close();
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async cleanupAbandonedLockSources(pathsArg) {
|
|
392
|
+
const entries = await fs.promises.readdir(pathsArg.transactionParent, {
|
|
393
|
+
withFileTypes: true,
|
|
394
|
+
});
|
|
395
|
+
for (const entry of entries) {
|
|
396
|
+
if (!entry.isFile() ||
|
|
397
|
+
(!entry.name.startsWith('.tsrust-assembly-owner.') &&
|
|
398
|
+
!entry.name.startsWith('.tsrust-assembly-recovery.')) ||
|
|
399
|
+
!entry.name.endsWith('.tmp')) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
const filePath = path.join(pathsArg.transactionParent, entry.name);
|
|
403
|
+
let owner;
|
|
404
|
+
try {
|
|
405
|
+
const parsed = JSON.parse(await fs.promises.readFile(filePath, 'utf8'));
|
|
406
|
+
if (isLockOwner(parsed) || isRecoveryClaim(parsed)) {
|
|
407
|
+
owner = parsed;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
if (error.code === 'ENOENT')
|
|
415
|
+
continue;
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (activeOwnerTokens.has(owner.ownerToken) ||
|
|
419
|
+
processOwnerTokens.has(owner.ownerToken) ||
|
|
420
|
+
owner.hostIdentity !== getHostIdentity() ||
|
|
421
|
+
isLocalProcessRunning(owner.pid)) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
await fs.promises.rm(filePath, { force: true });
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async readLock(pathsArg) {
|
|
428
|
+
const lock = await lstatOptional(pathsArg.lockPath);
|
|
429
|
+
if (!lock)
|
|
430
|
+
return undefined;
|
|
431
|
+
if (!lock.isFile() || lock.isSymbolicLink()) {
|
|
432
|
+
throw new Error(`Assembly lock is not a regular file: ${pathsArg.lockPath}`);
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
const parsed = JSON.parse(await fs.promises.readFile(pathsArg.lockPath, 'utf8'));
|
|
436
|
+
if (!isLockOwner(parsed)) {
|
|
437
|
+
throw new Error(`Assembly lock has an invalid shape: ${pathsArg.lockPath}`);
|
|
438
|
+
}
|
|
439
|
+
return parsed;
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
if (error instanceof SyntaxError) {
|
|
443
|
+
throw new Error(`Assembly lock is invalid JSON: ${pathsArg.lockPath}`);
|
|
444
|
+
}
|
|
445
|
+
throw error;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async readRecoveryClaim(pathsArg) {
|
|
449
|
+
const claim = await lstatOptional(pathsArg.recoveryClaimPath);
|
|
450
|
+
if (!claim)
|
|
451
|
+
return undefined;
|
|
452
|
+
if (!claim.isFile() || claim.isSymbolicLink()) {
|
|
453
|
+
throw new Error(`Assembly recovery claim is not a regular file: ${pathsArg.recoveryClaimPath}`);
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const parsed = JSON.parse(await fs.promises.readFile(pathsArg.recoveryClaimPath, 'utf8'));
|
|
457
|
+
if (!isRecoveryClaim(parsed)) {
|
|
458
|
+
throw new Error(`Assembly recovery claim has an invalid shape: ${pathsArg.recoveryClaimPath}`);
|
|
459
|
+
}
|
|
460
|
+
return parsed;
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
if (error instanceof SyntaxError) {
|
|
464
|
+
throw new Error(`Assembly recovery claim is invalid JSON: ${pathsArg.recoveryClaimPath}`);
|
|
465
|
+
}
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
async clearAbandonedRecoveryClaim(pathsArg) {
|
|
470
|
+
const claim = await this.readRecoveryClaim(pathsArg);
|
|
471
|
+
if (!claim)
|
|
472
|
+
return;
|
|
473
|
+
const targetOwner = await this.readLock(pathsArg);
|
|
474
|
+
if (targetOwner?.ownerToken === claim.targetOwnerToken) {
|
|
475
|
+
this.assertOwnerCanRecover(claim);
|
|
476
|
+
}
|
|
477
|
+
await this.releaseRecoveryClaim(pathsArg, claim.ownerToken);
|
|
478
|
+
processOwnerTokens.delete(claim.ownerToken);
|
|
479
|
+
}
|
|
480
|
+
async acquireRecoveryClaim(pathsArg, targetOwnerArg) {
|
|
481
|
+
const claim = {
|
|
482
|
+
format: RECOVERY_CLAIM_FORMAT,
|
|
483
|
+
pid: process.pid,
|
|
484
|
+
hostname: os.hostname(),
|
|
485
|
+
hostIdentity: getHostIdentity(),
|
|
486
|
+
ownerToken: crypto.randomUUID(),
|
|
487
|
+
startedAt: new Date().toISOString(),
|
|
488
|
+
targetOwnerToken: targetOwnerArg.ownerToken,
|
|
489
|
+
};
|
|
490
|
+
const sourcePath = path.join(pathsArg.transactionParent, `.tsrust-assembly-recovery.${claim.ownerToken}.tmp`);
|
|
491
|
+
let source;
|
|
492
|
+
let claimAcquired = false;
|
|
493
|
+
try {
|
|
494
|
+
source = await fs.promises.open(sourcePath, 'wx', 0o600);
|
|
495
|
+
await source.writeFile(`${JSON.stringify(claim, null, 2)}\n`, 'utf8');
|
|
496
|
+
await source.sync();
|
|
497
|
+
await source.close();
|
|
498
|
+
source = undefined;
|
|
499
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
500
|
+
try {
|
|
501
|
+
await fs.promises.link(sourcePath, pathsArg.recoveryClaimPath);
|
|
502
|
+
claimAcquired = true;
|
|
503
|
+
processOwnerTokens.add(claim.ownerToken);
|
|
504
|
+
activeOwnerTokens.add(claim.ownerToken);
|
|
505
|
+
await syncDirectory(pathsArg.transactionParent);
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
if (error.code !== 'EEXIST')
|
|
510
|
+
throw error;
|
|
511
|
+
if (attempt > 0) {
|
|
512
|
+
throw new Error(`Unable to acquire assembly recovery claim: ${pathsArg.recoveryClaimPath}`);
|
|
513
|
+
}
|
|
514
|
+
await this.clearAbandonedRecoveryClaim(pathsArg);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
const currentOwner = await this.readLock(pathsArg);
|
|
518
|
+
if (currentOwner?.ownerToken !== targetOwnerArg.ownerToken) {
|
|
519
|
+
await this.releaseRecoveryClaim(pathsArg, claim.ownerToken);
|
|
520
|
+
claimAcquired = false;
|
|
521
|
+
activeOwnerTokens.delete(claim.ownerToken);
|
|
522
|
+
processOwnerTokens.delete(claim.ownerToken);
|
|
523
|
+
throw new Error('Assembly owner changed while recovery was being claimed');
|
|
524
|
+
}
|
|
525
|
+
return claim;
|
|
526
|
+
}
|
|
527
|
+
catch (error) {
|
|
528
|
+
if (claimAcquired) {
|
|
529
|
+
try {
|
|
530
|
+
await this.releaseRecoveryClaim(pathsArg, claim.ownerToken);
|
|
531
|
+
}
|
|
532
|
+
finally {
|
|
533
|
+
activeOwnerTokens.delete(claim.ownerToken);
|
|
534
|
+
if (!(await lstatOptional(pathsArg.recoveryClaimPath))) {
|
|
535
|
+
processOwnerTokens.delete(claim.ownerToken);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
throw error;
|
|
540
|
+
}
|
|
541
|
+
finally {
|
|
542
|
+
await Promise.allSettled([
|
|
543
|
+
source?.close() || Promise.resolve(),
|
|
544
|
+
fs.promises.rm(sourcePath, { force: true }),
|
|
545
|
+
]);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
async releaseRecoveryClaim(pathsArg, ownerTokenArg) {
|
|
549
|
+
const claim = await this.readRecoveryClaim(pathsArg);
|
|
550
|
+
if (!claim)
|
|
551
|
+
return;
|
|
552
|
+
if (claim.ownerToken !== ownerTokenArg) {
|
|
553
|
+
throw new Error('Assembly recovery claim ownership changed before release');
|
|
554
|
+
}
|
|
555
|
+
await fs.promises.unlink(pathsArg.recoveryClaimPath);
|
|
556
|
+
await syncDirectory(pathsArg.transactionParent);
|
|
557
|
+
}
|
|
558
|
+
assertOwnerCanRecover(ownerArg) {
|
|
559
|
+
if (activeOwnerTokens.has(ownerArg.ownerToken)) {
|
|
560
|
+
throw new Error(`Artifact assembly is already active on ${ownerArg.hostname} with pid ${ownerArg.pid}`);
|
|
561
|
+
}
|
|
562
|
+
if (processOwnerTokens.has(ownerArg.ownerToken))
|
|
563
|
+
return;
|
|
564
|
+
if (ownerArg.hostIdentity !== getHostIdentity()) {
|
|
565
|
+
throw new Error(`Assembly transaction belongs to another host (${ownerArg.hostname}); refusing automatic recovery`);
|
|
566
|
+
}
|
|
567
|
+
if (isLocalProcessRunning(ownerArg.pid)) {
|
|
568
|
+
throw new Error(`Artifact assembly owner is still running on ${ownerArg.hostname} with pid ${ownerArg.pid}`);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
async recoverExistingTransaction(pathsArg) {
|
|
572
|
+
const owner = await this.readLock(pathsArg);
|
|
573
|
+
if (!owner)
|
|
574
|
+
return;
|
|
575
|
+
this.assertOwnerCanRecover(owner);
|
|
576
|
+
const claim = await this.acquireRecoveryClaim(pathsArg, owner);
|
|
577
|
+
try {
|
|
578
|
+
const currentOwner = await this.readLock(pathsArg);
|
|
579
|
+
if (currentOwner?.ownerToken !== owner.ownerToken) {
|
|
580
|
+
throw new Error('Assembly owner changed after recovery was claimed');
|
|
581
|
+
}
|
|
582
|
+
const transaction = await lstatOptional(pathsArg.transactionDirectory);
|
|
583
|
+
if (!transaction) {
|
|
584
|
+
await this.releaseLock(pathsArg, owner.ownerToken);
|
|
585
|
+
processOwnerTokens.delete(owner.ownerToken);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (!transaction.isDirectory() || transaction.isSymbolicLink()) {
|
|
589
|
+
throw new Error(`Assembly transaction path is not a regular directory: ${pathsArg.transactionDirectory}`);
|
|
590
|
+
}
|
|
591
|
+
const state = await this.readState(pathsArg);
|
|
592
|
+
if (!state) {
|
|
593
|
+
await fs.promises.rm(pathsArg.transactionDirectory, { recursive: true });
|
|
594
|
+
await this.releaseLock(pathsArg, owner.ownerToken);
|
|
595
|
+
processOwnerTokens.delete(owner.ownerToken);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (state.ownerToken !== owner.ownerToken ||
|
|
599
|
+
state.hostIdentity !== owner.hostIdentity ||
|
|
600
|
+
state.pid !== owner.pid) {
|
|
601
|
+
throw new Error('Assembly lock and transaction state have different owners');
|
|
602
|
+
}
|
|
603
|
+
if (state.phase === 'committing' ||
|
|
604
|
+
state.phase === 'published' ||
|
|
605
|
+
state.phase === 'committed') {
|
|
606
|
+
const cleanupPending = await this.completeCommittedTransaction(pathsArg, state);
|
|
607
|
+
if (cleanupPending) {
|
|
608
|
+
throw new Error(`Unable to clean committed assembly state: ${pathsArg.transactionDirectory}`);
|
|
609
|
+
}
|
|
610
|
+
processOwnerTokens.delete(state.ownerToken);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
await this.rollbackTransaction(pathsArg, state);
|
|
614
|
+
processOwnerTokens.delete(state.ownerToken);
|
|
615
|
+
}
|
|
616
|
+
finally {
|
|
617
|
+
activeOwnerTokens.delete(claim.ownerToken);
|
|
618
|
+
try {
|
|
619
|
+
await this.releaseRecoveryClaim(pathsArg, claim.ownerToken);
|
|
620
|
+
}
|
|
621
|
+
finally {
|
|
622
|
+
if (!(await lstatOptional(pathsArg.recoveryClaimPath))) {
|
|
623
|
+
processOwnerTokens.delete(claim.ownerToken);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
async releaseLock(pathsArg, ownerTokenArg) {
|
|
629
|
+
const owner = await this.readLock(pathsArg);
|
|
630
|
+
if (!owner)
|
|
631
|
+
return;
|
|
632
|
+
if (owner.ownerToken !== ownerTokenArg) {
|
|
633
|
+
throw new Error('Assembly lock ownership changed before release');
|
|
634
|
+
}
|
|
635
|
+
await fs.promises.unlink(pathsArg.lockPath);
|
|
636
|
+
await syncDirectory(pathsArg.transactionParent);
|
|
637
|
+
}
|
|
638
|
+
async readState(pathsArg) {
|
|
639
|
+
const state = await lstatOptional(pathsArg.statePath);
|
|
640
|
+
if (!state)
|
|
641
|
+
return undefined;
|
|
642
|
+
if (!state.isFile() || state.isSymbolicLink()) {
|
|
643
|
+
throw new Error(`Assembly state is not a regular file: ${pathsArg.statePath}`);
|
|
644
|
+
}
|
|
645
|
+
try {
|
|
646
|
+
const parsed = JSON.parse(await fs.promises.readFile(pathsArg.statePath, 'utf8'));
|
|
647
|
+
if (!isTransactionState(parsed)) {
|
|
648
|
+
throw new Error(`Assembly state has an invalid shape: ${pathsArg.statePath}`);
|
|
649
|
+
}
|
|
650
|
+
return parsed;
|
|
651
|
+
}
|
|
652
|
+
catch (error) {
|
|
653
|
+
if (error instanceof SyntaxError) {
|
|
654
|
+
throw new Error(`Assembly state is invalid JSON: ${pathsArg.statePath}`);
|
|
655
|
+
}
|
|
656
|
+
throw error;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async writeState(pathsArg, stateArg) {
|
|
660
|
+
const temporary = await fs.promises.open(pathsArg.stateTemporaryPath, 'w', 0o600);
|
|
661
|
+
try {
|
|
662
|
+
await temporary.writeFile(`${JSON.stringify(stateArg, null, 2)}\n`, 'utf8');
|
|
663
|
+
await temporary.sync();
|
|
664
|
+
}
|
|
665
|
+
finally {
|
|
666
|
+
await temporary.close();
|
|
667
|
+
}
|
|
668
|
+
await fs.promises.rename(pathsArg.stateTemporaryPath, pathsArg.statePath);
|
|
669
|
+
await syncDirectory(pathsArg.transactionDirectory);
|
|
670
|
+
}
|
|
671
|
+
async assertAssemblySourceUnchanged(workspaceArg) {
|
|
672
|
+
const snapshot = await captureGitSnapshot(workspaceArg);
|
|
673
|
+
if (!snapshot.available ||
|
|
674
|
+
snapshot.commit !== this.options.expectedGitCommit ||
|
|
675
|
+
snapshot.status.length > 0) {
|
|
676
|
+
throw new Error('Git source state changed before artifact publication');
|
|
677
|
+
}
|
|
678
|
+
let projectName = 'unknown';
|
|
679
|
+
let projectVersion = 'unknown';
|
|
680
|
+
try {
|
|
681
|
+
const packageJson = JSON.parse(await fs.promises.readFile(path.join(workspaceArg, 'package.json'), 'utf8'));
|
|
682
|
+
projectName = packageJson.name || projectName;
|
|
683
|
+
projectVersion = packageJson.version || projectVersion;
|
|
684
|
+
}
|
|
685
|
+
catch {
|
|
686
|
+
// package.json is optional for pure Rust workspaces.
|
|
687
|
+
}
|
|
688
|
+
if (projectName !== this.options.expectedProjectName ||
|
|
689
|
+
projectVersion !== this.options.expectedProjectVersion) {
|
|
690
|
+
throw new Error('Project package identity changed before artifact publication');
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
async rollbackTransaction(pathsArg, stateArg) {
|
|
694
|
+
const backup = await lstatOptional(pathsArg.backupDirectory);
|
|
695
|
+
if (backup) {
|
|
696
|
+
if (!backup.isDirectory() || backup.isSymbolicLink()) {
|
|
697
|
+
throw new Error(`Assembly backup is not a regular directory: ${pathsArg.backupDirectory}`);
|
|
698
|
+
}
|
|
699
|
+
const output = await lstatOptional(pathsArg.outputDirectory);
|
|
700
|
+
if (output) {
|
|
701
|
+
await fs.promises.rm(pathsArg.failedDirectory, { recursive: true, force: true });
|
|
702
|
+
await fs.promises.rename(pathsArg.outputDirectory, pathsArg.failedDirectory);
|
|
703
|
+
}
|
|
704
|
+
await fs.promises.rename(pathsArg.backupDirectory, pathsArg.outputDirectory);
|
|
705
|
+
await syncDirectory(pathsArg.workspace);
|
|
706
|
+
await fs.promises.rm(pathsArg.failedDirectory, { recursive: true, force: true });
|
|
707
|
+
}
|
|
708
|
+
else if (!stateArg.hadExistingOutput &&
|
|
709
|
+
(stateArg.phase === 'publishing' ||
|
|
710
|
+
stateArg.phase === 'published' ||
|
|
711
|
+
stateArg.phase === 'committing')) {
|
|
712
|
+
await fs.promises.rm(pathsArg.outputDirectory, { recursive: true, force: true });
|
|
713
|
+
await syncDirectory(pathsArg.workspace);
|
|
714
|
+
}
|
|
715
|
+
await fs.promises.rm(pathsArg.stagingDirectory, { recursive: true, force: true });
|
|
716
|
+
await fs.promises.rm(pathsArg.stateTemporaryPath, { force: true });
|
|
717
|
+
await fs.promises.rm(pathsArg.transactionDirectory, { recursive: true });
|
|
718
|
+
await this.releaseLock(pathsArg, stateArg.ownerToken);
|
|
719
|
+
}
|
|
720
|
+
async completeCommittedTransaction(pathsArg, stateArg) {
|
|
721
|
+
const output = await lstatOptional(pathsArg.outputDirectory);
|
|
722
|
+
const staging = await lstatOptional(pathsArg.stagingDirectory);
|
|
723
|
+
if (!output) {
|
|
724
|
+
if (!staging || !staging.isDirectory() || staging.isSymbolicLink()) {
|
|
725
|
+
throw new Error(`Committed artifact publication is incomplete: ${pathsArg.transactionDirectory}`);
|
|
726
|
+
}
|
|
727
|
+
await fs.promises.rename(pathsArg.stagingDirectory, pathsArg.outputDirectory);
|
|
728
|
+
await syncDirectory(pathsArg.workspace);
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
if (!output.isDirectory() || output.isSymbolicLink()) {
|
|
732
|
+
throw new Error(`Committed assembly output is not a regular directory: ${pathsArg.outputDirectory}`);
|
|
733
|
+
}
|
|
734
|
+
if (staging) {
|
|
735
|
+
throw new Error(`Committed assembly has both staging and output directories: ${pathsArg.transactionDirectory}`);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return this.cleanupCommittedTransaction(pathsArg, { ...stateArg, phase: 'published' });
|
|
739
|
+
}
|
|
740
|
+
async cleanupCommittedTransaction(pathsArg, stateArg) {
|
|
741
|
+
try {
|
|
742
|
+
const output = await fs.promises.lstat(pathsArg.outputDirectory);
|
|
743
|
+
if (!output.isDirectory() || output.isSymbolicLink()) {
|
|
744
|
+
throw new Error(`Committed assembly output is not a regular directory: ${pathsArg.outputDirectory}`);
|
|
745
|
+
}
|
|
746
|
+
await fs.promises.rm(pathsArg.backupDirectory, { recursive: true, force: true });
|
|
747
|
+
await fs.promises.rm(pathsArg.stagingDirectory, { recursive: true, force: true });
|
|
748
|
+
await fs.promises.rm(pathsArg.failedDirectory, { recursive: true, force: true });
|
|
749
|
+
await this.writeState(pathsArg, { ...stateArg, phase: 'committed' });
|
|
750
|
+
await fs.promises.rm(pathsArg.transactionDirectory, { recursive: true });
|
|
751
|
+
await this.releaseLock(pathsArg, stateArg.ownerToken);
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
catch {
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
async collectCandidates(sourceDirectoriesArg) {
|
|
759
|
+
const expectedTargets = new Map(this.options.expectedTargets.map((target) => [target.friendly, target]));
|
|
760
|
+
const expectedBinaries = new Set(this.options.expectedBinaries);
|
|
761
|
+
const candidates = new Map();
|
|
762
|
+
for (const sourceDirectory of sourceDirectoriesArg) {
|
|
763
|
+
const source = await fs.promises.lstat(sourceDirectory);
|
|
764
|
+
if (!source.isDirectory() || source.isSymbolicLink()) {
|
|
765
|
+
throw new Error(`Artifact source is not a regular directory: ${sourceDirectory}`);
|
|
766
|
+
}
|
|
767
|
+
const entries = await fs.promises.readdir(sourceDirectory, { withFileTypes: true });
|
|
768
|
+
const entryNames = new Set(entries.map((entry) => entry.name));
|
|
769
|
+
const usedSidecars = new Set();
|
|
770
|
+
for (const entry of entries) {
|
|
771
|
+
const entryPath = path.join(sourceDirectory, entry.name);
|
|
772
|
+
if (entry.isSymbolicLink() || !entry.isFile()) {
|
|
773
|
+
throw new Error(`Artifact source contains a non-regular entry: ${entryPath}`);
|
|
774
|
+
}
|
|
775
|
+
if (isProvenanceTemporaryFile(entry.name))
|
|
776
|
+
continue;
|
|
777
|
+
if (entry.name.endsWith(PROVENANCE_SIDECAR_SUFFIX))
|
|
778
|
+
continue;
|
|
779
|
+
const sidecarName = `${entry.name}${PROVENANCE_SIDECAR_SUFFIX}`;
|
|
780
|
+
if (!entryNames.has(sidecarName)) {
|
|
781
|
+
throw new Error(`Artifact is missing its provenance sidecar: ${entryPath}`);
|
|
782
|
+
}
|
|
783
|
+
const binary = await fs.promises.lstat(entryPath);
|
|
784
|
+
if ((binary.mode & 0o111) === 0) {
|
|
785
|
+
throw new Error(`Artifact is not executable: ${entryPath}`);
|
|
786
|
+
}
|
|
787
|
+
const buildInfo = await ProvenanceStore.readSidecar(entryPath);
|
|
788
|
+
assertArtifactName(buildInfo.binary, 'provenance binary name');
|
|
789
|
+
assertArtifactName(buildInfo.target, 'provenance target name');
|
|
790
|
+
if (buildInfo.gitDirty !== false) {
|
|
791
|
+
throw new Error(`Artifact was not built from a clean Git worktree: ${entryPath}`);
|
|
792
|
+
}
|
|
793
|
+
if (buildInfo.projectName !== this.options.expectedProjectName ||
|
|
794
|
+
buildInfo.projectVersion !== this.options.expectedProjectVersion ||
|
|
795
|
+
buildInfo.gitCommit !== this.options.expectedGitCommit) {
|
|
796
|
+
throw new Error(`Artifact provenance does not match the assembly source: ${entryPath}`);
|
|
797
|
+
}
|
|
798
|
+
if (buildInfo.tsrustVersion !== this.options.expectedTsrustVersion) {
|
|
799
|
+
throw new Error(`Artifact was built with a different tsrust version: ${entryPath}`);
|
|
800
|
+
}
|
|
801
|
+
const target = expectedTargets.get(buildInfo.target);
|
|
802
|
+
if (!target) {
|
|
803
|
+
throw new Error(`Artifact has an unexpected target ${buildInfo.target}: ${entryPath}`);
|
|
804
|
+
}
|
|
805
|
+
if (!expectedBinaries.has(buildInfo.binary)) {
|
|
806
|
+
throw new Error(`Artifact has an unexpected binary ${buildInfo.binary}: ${entryPath}`);
|
|
807
|
+
}
|
|
808
|
+
const destinationName = `${buildInfo.binary}_${target.friendly}`;
|
|
809
|
+
if (entry.name !== destinationName) {
|
|
810
|
+
throw new Error(`Artifact filename ${entry.name} does not match provenance name ${destinationName}`);
|
|
811
|
+
}
|
|
812
|
+
const key = `${buildInfo.binary}\u0000${target.friendly}`;
|
|
813
|
+
if (candidates.has(key)) {
|
|
814
|
+
throw new Error(`Artifact inputs contain a duplicate ${destinationName}`);
|
|
815
|
+
}
|
|
816
|
+
const sidecarPath = path.join(sourceDirectory, sidecarName);
|
|
817
|
+
candidates.set(key, {
|
|
818
|
+
binaryPath: entryPath,
|
|
819
|
+
sidecarPath,
|
|
820
|
+
destinationName,
|
|
821
|
+
buildInfo,
|
|
822
|
+
});
|
|
823
|
+
usedSidecars.add(sidecarName);
|
|
824
|
+
}
|
|
825
|
+
for (const entry of entries) {
|
|
826
|
+
if (entry.name.endsWith(PROVENANCE_SIDECAR_SUFFIX) && !usedSidecars.has(entry.name)) {
|
|
827
|
+
throw new Error(`Artifact source contains an orphan provenance sidecar: ${entry.name}`);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
for (const binary of expectedBinaries) {
|
|
832
|
+
for (const target of expectedTargets.keys()) {
|
|
833
|
+
const key = `${binary}\u0000${target}`;
|
|
834
|
+
if (!candidates.has(key)) {
|
|
835
|
+
throw new Error(`Artifact assembly is missing ${binary}_${target}`);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return [...candidates.values()].sort((a, b) => a.destinationName.localeCompare(b.destinationName));
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hcnRpZmFjdGFzc2VtYmxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL21vZF9hcnRpZmFjdC9jbGFzc2VzLmFydGlmYWN0YXNzZW1ibGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQ2pDLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3pCLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3pCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRTdCLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsZUFBZSxFQUNmLHFCQUFxQixFQUNyQix5QkFBeUIsRUFDekIsZUFBZSxHQUNoQixNQUFNLDRCQUE0QixDQUFDO0FBRXBDLE1BQU0sa0JBQWtCLEdBQUcsNkJBQTZCLENBQUM7QUFDekQsTUFBTSxXQUFXLEdBQUcsa0NBQWtDLENBQUM7QUFDdkQsTUFBTSxxQkFBcUIsR0FBRyxzQ0FBc0MsQ0FBQztBQUNyRSxNQUFNLHFCQUFxQixHQUFHLGlCQUFpQixDQUFDO0FBQ2hELE1BQU0saUJBQWlCLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztBQUM1QyxNQUFNLGtCQUFrQixHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7QUFzRjdDLFNBQVMsY0FBYyxDQUFDLFNBQWlCLEVBQUUsWUFBb0I7SUFDN0QsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDeEQsT0FBTyxRQUFRLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0FBQ3ZGLENBQUM7QUFFRCxLQUFLLFVBQVUsYUFBYSxDQUFDLFdBQW1CO0lBQzlDLElBQUksQ0FBQztR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
|