@visulima/task-runner 1.0.0-alpha.8 → 1.0.0-alpha.9
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/CHANGELOG.md +31 -0
- package/README.md +3 -1
- package/dist/index.d.ts +791 -205
- package/dist/index.js +28 -20
- package/dist/packem_chunks/index.js +5593 -0
- package/dist/packem_shared/{Cache-CWaX_c8U.js → Cache-CbhoA268.js} +151 -10
- package/dist/packem_shared/{FileAccessTracker-CQ5Ot7Hd.js → FileAccessTracker-D8zIURPU.js} +1 -1
- package/dist/packem_shared/{FingerprintManager-CV7U4f4f.js → FingerprintManager-78DjwWQ4.js} +1 -1
- package/dist/packem_shared/HttpRemoteCache-BTXUBH7t.js +290 -0
- package/dist/packem_shared/INPUT_URI_SCHEMES-DRm76YI5.js +69 -0
- package/dist/packem_shared/{IncrementalFileHasher-BRS76-mb.js → IncrementalFileHasher-BBhVK491.js} +1 -1
- package/dist/packem_shared/ReapiRemoteCache-vgRxDMmu.js +1012 -0
- package/dist/packem_shared/{TaskOrchestrator-UCMHCx8c.js → TaskOrchestrator-CdRaQhTO.js} +34 -11
- package/dist/packem_shared/{TrackedTaskExecutor-CFPpQfXF.js → TrackedTaskExecutor-CWSMfHAW.js} +2 -2
- package/dist/packem_shared/V2_ROOT-DKBLxKo4.js +14 -0
- package/dist/packem_shared/actionDigestForTaskHash-BRE-9MT6.js +121 -0
- package/dist/packem_shared/archive-CnggHWb-.js +152 -0
- package/dist/packem_shared/{collectFiles-ClXHnHhg.js → collectFiles-cc1gokGU.js} +2 -1
- package/dist/packem_shared/{computeTaskHash-B5APHW7e.js → computeTaskHash-DHoBJ_-V.js} +10 -4
- package/dist/packem_shared/containsBlob-CwGB0a_q.js +125 -0
- package/dist/packem_shared/{createTaskGraph-B5YrfAMx.js → createTaskGraph-Bwl4hwAf.js} +17 -0
- package/dist/packem_shared/{defaultTaskRunner-DzR0ld8F.js → defaultTaskRunner-BaX4ZbFv.js} +24 -13
- package/dist/packem_shared/{detectFrameworks-CeFzKE6J.js → detectFrameworks-D7nyTc-o.js} +1 -1
- package/dist/packem_shared/{detectScriptShell-CR-xXKA4.js → detectScriptShell-CzxCM9-t.js} +1 -1
- package/dist/packem_shared/digestBuffer-CPdI2E1d.js +48 -0
- package/dist/packem_shared/{expandArguments-0AwD2BIA.js → expandArguments-Ba-hHYff.js} +2 -1
- package/dist/packem_shared/{expandTokensInString-C03AGAjh.js → expandTokensInString-Bb7nYehP.js} +2 -1
- package/dist/packem_shared/{extractPackageName-CbVNW-dr.js → extractPackageName-CMHjqGj_.js} +1 -1
- package/dist/packem_shared/{generateRunSummary-BE1jnQ3H.js → generateRunSummary-Bah7CFay.js} +1 -1
- package/dist/packem_shared/{getCurrentBranch-DsKPDoVj.js → getCurrentBranch-DVNikt0P.js} +11 -8
- package/dist/packem_shared/getMainWorktreeRoot-iBqToQJ4.js +114 -0
- package/dist/packem_shared/{parseCommands-CJ16ohOB.js → parseCommands-DDdIxaH5.js} +3 -3
- package/dist/packem_shared/resolveCacheMode-CsmHT_0o.js +21 -0
- package/dist/packem_shared/{runConcurrently-CmfC4r-f.js → runConcurrently-BCGQ9fJl.js} +1 -1
- package/dist/packem_shared/shell-quote-DWJJbt21.js +3 -0
- package/dist/packem_shared/{utils-zO0ZRgtf.js → utils-Bmnj-H2J.js} +4 -1
- package/index.js +52 -52
- package/package.json +23 -10
- package/dist/packem_shared/RemoteCache-DSU3lc87.js +0 -219
- package/dist/packem_shared/archive-UQHAnZUa.js +0 -102
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { d as resolveTaskCwd, a as createFailureResult, e as createXxh3Hasher } from './utils-
|
|
1
|
+
import { d as resolveTaskCwd, a as createFailureResult, e as createXxh3Hasher } from './utils-Bmnj-H2J.js';
|
|
2
2
|
import { resolve, join } from '@visulima/path';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { retrieveByTaskHash, storeByTaskHash } from './actionDigestForTaskHash-BRE-9MT6.js';
|
|
4
|
+
import { FingerprintManager } from './FingerprintManager-78DjwWQ4.js';
|
|
5
|
+
import { generateRunSummary, writeLastRunSummary, writeRunSummary } from './generateRunSummary-Bah7CFay.js';
|
|
6
|
+
import { computeTaskHash } from './computeTaskHash-DHoBJ_-V.js';
|
|
7
|
+
import { TrackedTaskExecutor } from './TrackedTaskExecutor-CWSMfHAW.js';
|
|
8
|
+
import { getCurrentBranch, evaluateWhen, explainWhen } from './getCurrentBranch-DVNikt0P.js';
|
|
8
9
|
|
|
9
10
|
const hashFingerprint = (fingerprint) => {
|
|
10
11
|
const hash = createXxh3Hasher();
|
|
@@ -26,6 +27,20 @@ const hashFingerprint = (fingerprint) => {
|
|
|
26
27
|
}
|
|
27
28
|
return hash.digest();
|
|
28
29
|
};
|
|
30
|
+
const detectWarnings = (patterns, output) => {
|
|
31
|
+
if (!patterns || patterns.length === 0 || !output) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
for (const source of patterns) {
|
|
35
|
+
try {
|
|
36
|
+
if (new RegExp(source).test(output)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
};
|
|
29
44
|
const createDeferred = () => {
|
|
30
45
|
let resolve2;
|
|
31
46
|
const promise = new Promise((r) => {
|
|
@@ -50,6 +65,7 @@ class TaskOrchestrator {
|
|
|
50
65
|
#cacheDiagnostics;
|
|
51
66
|
#resolveCommand;
|
|
52
67
|
#remoteCache;
|
|
68
|
+
#onRemoteUploadError;
|
|
53
69
|
#dryRun;
|
|
54
70
|
#summarize;
|
|
55
71
|
#taskGraph;
|
|
@@ -77,6 +93,7 @@ class TaskOrchestrator {
|
|
|
77
93
|
this.#cacheDiagnostics = options.cacheDiagnostics ?? false;
|
|
78
94
|
this.#resolveCommand = options.resolveCommand ?? void 0;
|
|
79
95
|
this.#remoteCache = options.remoteCache ?? void 0;
|
|
96
|
+
this.#onRemoteUploadError = options.onRemoteUploadError ?? void 0;
|
|
80
97
|
this.#dryRun = options.dryRun ?? false;
|
|
81
98
|
this.#summarize = options.summarize ?? false;
|
|
82
99
|
this.#taskGraph = options.taskGraph ?? void 0;
|
|
@@ -214,7 +231,7 @@ class TaskOrchestrator {
|
|
|
214
231
|
return this.#applyCachedResult(task, cachedResult, startTime);
|
|
215
232
|
}
|
|
216
233
|
if (this.#remoteCache) {
|
|
217
|
-
const retrieved = await this.#remoteCache
|
|
234
|
+
const retrieved = await retrieveByTaskHash(this.#remoteCache, hash, this.#cache.cacheDirectory);
|
|
218
235
|
if (retrieved) {
|
|
219
236
|
const remoteCached = await this.#cache.get(hash);
|
|
220
237
|
if (remoteCached) {
|
|
@@ -227,7 +244,7 @@ class TaskOrchestrator {
|
|
|
227
244
|
}
|
|
228
245
|
const result = await this.#executeTask(task, startTime);
|
|
229
246
|
if (result.code === 0 && task.cache !== false && task.hash && this.#remoteCache) {
|
|
230
|
-
this.#remoteCache
|
|
247
|
+
storeByTaskHash(this.#remoteCache, task.hash, this.#cache.cacheDirectory, this.#onRemoteUploadError).catch(() => {
|
|
231
248
|
});
|
|
232
249
|
}
|
|
233
250
|
return result;
|
|
@@ -262,7 +279,7 @@ class TaskOrchestrator {
|
|
|
262
279
|
return this.#executeTaskWithTracking(task, startTime);
|
|
263
280
|
}
|
|
264
281
|
async #applyCachedResult(task, cachedResult, startTime) {
|
|
265
|
-
const restored = await this.#cache.restoreOutputs(cachedResult.hash, task.outputs);
|
|
282
|
+
const restored = await this.#cache.restoreOutputs(cachedResult.hash, task.outputs, task.cacheRestore);
|
|
266
283
|
const status = restored ? "local-cache" : "local-cache-kept-existing";
|
|
267
284
|
const result = {
|
|
268
285
|
code: cachedResult.code,
|
|
@@ -281,16 +298,19 @@ class TaskOrchestrator {
|
|
|
281
298
|
captureOutput: this.#captureOutput,
|
|
282
299
|
cwd: resolveTaskCwd(this.#workspaceRoot, task)
|
|
283
300
|
});
|
|
301
|
+
const hadWarnings = code === 0 && detectWarnings(task.warningPattern, terminalOutput);
|
|
284
302
|
const result = {
|
|
285
303
|
code,
|
|
286
304
|
endTime: Date.now(),
|
|
305
|
+
hadWarnings: hadWarnings || void 0,
|
|
287
306
|
startTime,
|
|
288
307
|
status: code === 0 ? "success" : "failure",
|
|
289
308
|
task,
|
|
290
309
|
terminalOutput
|
|
291
310
|
};
|
|
292
311
|
this.#results.set(task.id, result);
|
|
293
|
-
|
|
312
|
+
const skipCacheOnWarning = hadWarnings && task.cacheOnWarning === false;
|
|
313
|
+
if (code === 0 && task.cache !== false && task.hash && !skipCacheOnWarning) {
|
|
294
314
|
const modified = await this.#detectSelfModifiedInputs(task);
|
|
295
315
|
if (modified.length > 0) {
|
|
296
316
|
result.selfModified = true;
|
|
@@ -381,16 +401,19 @@ class TaskOrchestrator {
|
|
|
381
401
|
this.#untrackedEnvVars
|
|
382
402
|
);
|
|
383
403
|
}
|
|
404
|
+
const hadWarnings = code === 0 && detectWarnings(task.warningPattern, terminalOutput);
|
|
384
405
|
const result = {
|
|
385
406
|
code,
|
|
386
407
|
endTime: Date.now(),
|
|
408
|
+
hadWarnings: hadWarnings || void 0,
|
|
387
409
|
startTime,
|
|
388
410
|
status: code === 0 ? "success" : "failure",
|
|
389
411
|
task,
|
|
390
412
|
terminalOutput
|
|
391
413
|
};
|
|
392
414
|
this.#results.set(task.id, result);
|
|
393
|
-
|
|
415
|
+
const skipCacheOnWarning = hadWarnings && task.cacheOnWarning === false;
|
|
416
|
+
if (code === 0 && task.cache !== false && fingerprint && !skipCacheOnWarning) {
|
|
394
417
|
const modified = this.#detectSelfModifiedFingerprint(fingerprint);
|
|
395
418
|
const emptyFingerprintReason = this.#describeEmptyFingerprint(fingerprint, usedRealTracker, trackerAccessCount);
|
|
396
419
|
if (modified.length > 0) {
|
package/dist/packem_shared/{TrackedTaskExecutor-CFPpQfXF.js → TrackedTaskExecutor-CWSMfHAW.js}
RENAMED
|
@@ -27,8 +27,8 @@ const {
|
|
|
27
27
|
rm
|
|
28
28
|
} = __cjs_getBuiltinModule("node:fs/promises");
|
|
29
29
|
import { join } from '@visulima/path';
|
|
30
|
-
import { FileAccessTracker, generatePreloadScript } from './FileAccessTracker-
|
|
31
|
-
import { u as uniqueId } from './utils-
|
|
30
|
+
import { FileAccessTracker, generatePreloadScript } from './FileAccessTracker-D8zIURPU.js';
|
|
31
|
+
import { u as uniqueId } from './utils-Bmnj-H2J.js';
|
|
32
32
|
|
|
33
33
|
class TrackedTaskExecutor {
|
|
34
34
|
#tracker;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { join } from '@visulima/path';
|
|
2
|
+
|
|
3
|
+
const V2_ROOT = "v2";
|
|
4
|
+
const V2_CAS = "cas";
|
|
5
|
+
const V2_AC = "ac";
|
|
6
|
+
const V2_INDEX = "task-hash-index";
|
|
7
|
+
const V2_TMP = "tmp";
|
|
8
|
+
const shard = (hash) => hash.slice(0, 2);
|
|
9
|
+
const casBlobPath = (root, hash) => join(root, V2_ROOT, V2_CAS, shard(hash), hash);
|
|
10
|
+
const acEntryPath = (root, actionHash) => join(root, V2_ROOT, V2_AC, shard(actionHash), `${actionHash}.json`);
|
|
11
|
+
const taskHashIndexPath = (root, taskHash) => join(root, V2_ROOT, V2_INDEX, shard(taskHash), taskHash);
|
|
12
|
+
const tmpDirectory = (root) => join(root, V2_ROOT, V2_TMP);
|
|
13
|
+
|
|
14
|
+
export { V2_AC, V2_CAS, V2_INDEX, V2_ROOT, V2_TMP, acEntryPath, casBlobPath, shard, taskHashIndexPath, tmpDirectory };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { createRequire as __cjs_createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
const __cjs_require = __cjs_createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
|
|
6
|
+
|
|
7
|
+
const __cjs_getBuiltinModule = (module) => {
|
|
8
|
+
// Check if we're in Node.js and version supports getBuiltinModule
|
|
9
|
+
if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
|
|
10
|
+
const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
|
|
11
|
+
// Node.js 20.16.0+ and 22.3.0+
|
|
12
|
+
if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
|
|
13
|
+
return __cjs_getProcess.getBuiltinModule(module);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Fallback to createRequire
|
|
17
|
+
return __cjs_require(module);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
createHash,
|
|
22
|
+
randomUUID
|
|
23
|
+
} = __cjs_getBuiltinModule("node:crypto");
|
|
24
|
+
const {
|
|
25
|
+
createReadStream
|
|
26
|
+
} = __cjs_getBuiltinModule("node:fs");
|
|
27
|
+
const {
|
|
28
|
+
mkdir,
|
|
29
|
+
rm,
|
|
30
|
+
stat
|
|
31
|
+
} = __cjs_getBuiltinModule("node:fs/promises");
|
|
32
|
+
import { join } from '@visulima/path';
|
|
33
|
+
import { e as extractTarGz, c as createTarGz } from './archive-CnggHWb-.js';
|
|
34
|
+
|
|
35
|
+
const TARBALL_OUTPUT_PATH = "vis-entry.tar.gz";
|
|
36
|
+
const actionDigestForTaskHash = (taskHash) => {
|
|
37
|
+
const key = `vis-task:${taskHash}`;
|
|
38
|
+
return {
|
|
39
|
+
hash: createHash("sha256").update(Buffer.from(key, "utf8")).digest("hex"),
|
|
40
|
+
sizeBytes: 0
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
const containsByTaskHash = async (backend, taskHash) => {
|
|
44
|
+
try {
|
|
45
|
+
return await backend.containsAction(actionDigestForTaskHash(taskHash));
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const retrieveByTaskHash = async (backend, taskHash, localCacheDirectory) => {
|
|
51
|
+
const action = await backend.retrieveAction(actionDigestForTaskHash(taskHash));
|
|
52
|
+
if (action === null || action.outputFiles.length === 0) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const tarballEntry = action.outputFiles[0];
|
|
56
|
+
if (!tarballEntry) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const entryDirectory = join(localCacheDirectory, taskHash);
|
|
60
|
+
const archivePath = join(localCacheDirectory, `.download-${taskHash}-${randomUUID()}.tar.gz`);
|
|
61
|
+
try {
|
|
62
|
+
await mkdir(localCacheDirectory, { recursive: true });
|
|
63
|
+
const fetched = await backend.fetchBlob(tarballEntry.digest, archivePath);
|
|
64
|
+
if (!fetched) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
await mkdir(entryDirectory, { recursive: true });
|
|
68
|
+
await extractTarGz(archivePath, entryDirectory);
|
|
69
|
+
return true;
|
|
70
|
+
} catch {
|
|
71
|
+
await rm(entryDirectory, { force: true, recursive: true }).catch(() => {
|
|
72
|
+
});
|
|
73
|
+
return false;
|
|
74
|
+
} finally {
|
|
75
|
+
await rm(archivePath, { force: true }).catch(() => {
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const storeByTaskHash = async (backend, taskHash, localCacheDirectory, onUploadError) => {
|
|
80
|
+
const entryDirectory = join(localCacheDirectory, taskHash);
|
|
81
|
+
const archivePath = join(localCacheDirectory, `.upload-${taskHash}-${randomUUID()}.tar.gz`);
|
|
82
|
+
try {
|
|
83
|
+
try {
|
|
84
|
+
await stat(join(entryDirectory, ".commit"));
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await createTarGz(entryDirectory, archivePath);
|
|
90
|
+
const blobDigest = await digestFile(archivePath);
|
|
91
|
+
const result = {
|
|
92
|
+
exitCode: 0,
|
|
93
|
+
outputDirectories: [],
|
|
94
|
+
outputFiles: [{ digest: blobDigest, isExecutable: false, path: TARBALL_OUTPUT_PATH }]
|
|
95
|
+
};
|
|
96
|
+
const blob = {
|
|
97
|
+
digest: blobDigest,
|
|
98
|
+
open: () => Promise.resolve(createReadStream(archivePath))
|
|
99
|
+
};
|
|
100
|
+
return await backend.storeAction(actionDigestForTaskHash(taskHash), result, [blob]);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
onUploadError?.(taskHash, error);
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
} finally {
|
|
106
|
+
await rm(archivePath, { force: true }).catch(() => {
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const digestFile = async (path) => {
|
|
111
|
+
const hash = createHash("sha256");
|
|
112
|
+
let sizeBytes = 0;
|
|
113
|
+
for await (const chunk of createReadStream(path)) {
|
|
114
|
+
const buffer = chunk;
|
|
115
|
+
hash.update(buffer);
|
|
116
|
+
sizeBytes += buffer.byteLength;
|
|
117
|
+
}
|
|
118
|
+
return { hash: hash.digest("hex"), sizeBytes };
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export { actionDigestForTaskHash, containsByTaskHash, retrieveByTaskHash, storeByTaskHash };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createRequire as __cjs_createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
const __cjs_require = __cjs_createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
|
|
6
|
+
|
|
7
|
+
const __cjs_getBuiltinModule = (module) => {
|
|
8
|
+
// Check if we're in Node.js and version supports getBuiltinModule
|
|
9
|
+
if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
|
|
10
|
+
const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
|
|
11
|
+
// Node.js 20.16.0+ and 22.3.0+
|
|
12
|
+
if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
|
|
13
|
+
return __cjs_getProcess.getBuiltinModule(module);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Fallback to createRequire
|
|
17
|
+
return __cjs_require(module);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
mkdir,
|
|
22
|
+
writeFile,
|
|
23
|
+
utimes,
|
|
24
|
+
readdir,
|
|
25
|
+
readFile,
|
|
26
|
+
stat
|
|
27
|
+
} = __cjs_getBuiltinModule("node:fs/promises");
|
|
28
|
+
const {
|
|
29
|
+
Readable
|
|
30
|
+
} = __cjs_getBuiltinModule("node:stream");
|
|
31
|
+
const {
|
|
32
|
+
pipeline
|
|
33
|
+
} = __cjs_getBuiltinModule("node:stream/promises");
|
|
34
|
+
const {
|
|
35
|
+
createGunzip,
|
|
36
|
+
createGzip,
|
|
37
|
+
createBrotliDecompress,
|
|
38
|
+
createBrotliCompress,
|
|
39
|
+
constants
|
|
40
|
+
} = __cjs_getBuiltinModule("node:zlib");
|
|
41
|
+
import { join, resolve, sep } from '@visulima/path';
|
|
42
|
+
import { parseTar, createTar } from 'nanotar';
|
|
43
|
+
|
|
44
|
+
const BROTLI_COMPRESS_OPTIONS = {
|
|
45
|
+
params: {
|
|
46
|
+
[constants.BROTLI_PARAM_MODE]: constants.BROTLI_MODE_TEXT,
|
|
47
|
+
[constants.BROTLI_PARAM_QUALITY]: 4
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const collectEntries = async (sourceDirectory) => {
|
|
51
|
+
const entries = [];
|
|
52
|
+
const root = resolve(sourceDirectory);
|
|
53
|
+
const walk = async (absolute, relative) => {
|
|
54
|
+
const items = await readdir(absolute, { withFileTypes: true });
|
|
55
|
+
items.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
56
|
+
for (const item of items) {
|
|
57
|
+
const childAbsolute = join(absolute, item.name);
|
|
58
|
+
const childRelative = relative === "" ? item.name : `${relative}/${item.name}`;
|
|
59
|
+
if (item.isDirectory()) {
|
|
60
|
+
await walk(childAbsolute, childRelative);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (!item.isFile()) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const [data, info] = await Promise.all([readFile(childAbsolute), stat(childAbsolute)]);
|
|
67
|
+
entries.push({
|
|
68
|
+
attrs: {
|
|
69
|
+
// eslint-disable-next-line no-bitwise -- POSIX file modes encode the rwx triplet in the low 12 bits; bitmask is the canonical extraction
|
|
70
|
+
mode: (info.mode & 4095).toString(8),
|
|
71
|
+
mtime: Math.floor(info.mtimeMs)
|
|
72
|
+
},
|
|
73
|
+
data,
|
|
74
|
+
name: childRelative
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
await walk(root, "");
|
|
79
|
+
return entries;
|
|
80
|
+
};
|
|
81
|
+
const safeJoinForExtract = (destinationDirectory, entryName) => {
|
|
82
|
+
if (entryName === "" || entryName === "." || entryName === "./") {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (entryName.startsWith("/") || entryName.startsWith("\\") || /^[a-z]:[\\/]/i.test(entryName)) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const resolvedDestination = resolve(destinationDirectory);
|
|
89
|
+
const resolvedEntry = resolve(resolvedDestination, entryName);
|
|
90
|
+
const prefix = resolvedDestination.endsWith(sep) ? resolvedDestination : `${resolvedDestination}${sep}`;
|
|
91
|
+
if (resolvedEntry !== resolvedDestination && !resolvedEntry.startsWith(prefix)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return resolvedEntry;
|
|
95
|
+
};
|
|
96
|
+
const writeTarEntries = async (entries, destinationDirectory, options = {}) => {
|
|
97
|
+
const preserveMtime = options.preserveMtime ?? true;
|
|
98
|
+
const preservePerms = options.preservePerms ?? true;
|
|
99
|
+
await mkdir(destinationDirectory, { recursive: true });
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
if (entry.data === void 0) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const writePath = safeJoinForExtract(destinationDirectory, entry.name);
|
|
105
|
+
if (writePath === null) {
|
|
106
|
+
throw new Error(`[task-runner] refusing to extract tar entry with unsafe path: ${entry.name}`);
|
|
107
|
+
}
|
|
108
|
+
await mkdir(join(writePath, ".."), { recursive: true });
|
|
109
|
+
const mode = preservePerms && entry.attrs?.mode !== void 0 ? Number.parseInt(entry.attrs.mode, 8) : void 0;
|
|
110
|
+
await writeFile(writePath, entry.data, mode === void 0 ? void 0 : { mode });
|
|
111
|
+
if (preserveMtime && entry.attrs?.mtime !== void 0) {
|
|
112
|
+
const mtime = new Date(entry.attrs.mtime * 1e3);
|
|
113
|
+
await utimes(writePath, mtime, mtime);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const compressBuffer = async (buffer, transform, outputPath) => {
|
|
118
|
+
const { createWriteStream } = await import('node:fs');
|
|
119
|
+
await pipeline(Readable.from(Buffer.from(buffer)), transform, createWriteStream(outputPath));
|
|
120
|
+
};
|
|
121
|
+
const decompressBuffer = async (sourcePath, transform) => {
|
|
122
|
+
const { createReadStream } = await import('node:fs');
|
|
123
|
+
const chunks = [];
|
|
124
|
+
await pipeline(createReadStream(sourcePath), transform, async (source) => {
|
|
125
|
+
for await (const chunk of source) {
|
|
126
|
+
chunks.push(chunk);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
return Buffer.concat(chunks);
|
|
130
|
+
};
|
|
131
|
+
const createTarGz = async (sourceDirectory, outputPath) => {
|
|
132
|
+
const entries = await collectEntries(sourceDirectory);
|
|
133
|
+
const tarBytes = createTar(entries);
|
|
134
|
+
await compressBuffer(tarBytes, createGzip(), outputPath);
|
|
135
|
+
};
|
|
136
|
+
const extractTarGz = async (archivePath, destinationDirectory, options) => {
|
|
137
|
+
const tarBuffer = await decompressBuffer(archivePath, createGunzip());
|
|
138
|
+
const entries = parseTar(tarBuffer);
|
|
139
|
+
await writeTarEntries(entries, destinationDirectory, options);
|
|
140
|
+
};
|
|
141
|
+
const createTarBrotli = async (sourceDirectory, outputPath) => {
|
|
142
|
+
const entries = await collectEntries(sourceDirectory);
|
|
143
|
+
const tarBytes = createTar(entries);
|
|
144
|
+
await compressBuffer(tarBytes, createBrotliCompress(BROTLI_COMPRESS_OPTIONS), outputPath);
|
|
145
|
+
};
|
|
146
|
+
const extractTarBrotli = async (archivePath, destinationDirectory, options) => {
|
|
147
|
+
const tarBuffer = await decompressBuffer(archivePath, createBrotliDecompress());
|
|
148
|
+
const entries = parseTar(tarBuffer);
|
|
149
|
+
await writeTarEntries(entries, destinationDirectory, options);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export { extractTarBrotli as a, createTarBrotli as b, createTarGz as c, extractTarGz as e };
|
|
@@ -18,5 +18,6 @@ const __cjs_getBuiltinModule = (module) => {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
export { c as collectFiles, a as createFailureResult, h as hashFile, b as hashStrings, r as readPackageDeps, d as resolveTaskCwd, s as sortObjectKeys, u as uniqueId } from './utils-Bmnj-H2J.js';
|
|
22
23
|
import '@visulima/path';
|
|
@@ -24,11 +24,12 @@ const {
|
|
|
24
24
|
stat,
|
|
25
25
|
readFile
|
|
26
26
|
} = __cjs_getBuiltinModule("node:fs/promises");
|
|
27
|
-
import { b as hashStrings, s as sortObjectKeys, c as collectFiles, x as xxh3Hash, e as createXxh3Hasher } from './utils-
|
|
27
|
+
import { b as hashStrings, s as sortObjectKeys, c as collectFiles, x as xxh3Hash, e as createXxh3Hasher } from './utils-Bmnj-H2J.js';
|
|
28
28
|
import { join, resolve, relative } from '@visulima/path';
|
|
29
|
-
import { getFrameworkEnvVariables } from './detectFrameworks-
|
|
30
|
-
import { LockfileHasher } from './extractPackageName-
|
|
29
|
+
import { getFrameworkEnvVariables } from './detectFrameworks-D7nyTc-o.js';
|
|
30
|
+
import { LockfileHasher } from './extractPackageName-CMHjqGj_.js';
|
|
31
31
|
import { loadNativeBindings } from './isNativeAvailable-BpD28A6Z.js';
|
|
32
|
+
import { looksLikeInputUri, parseInputUri } from './INPUT_URI_SCHEMES-DRm76YI5.js';
|
|
32
33
|
|
|
33
34
|
const DEFAULT_GLOBAL_INPUTS = ["package-lock.json", "pnpm-lock.yaml", "yarn.lock", "tsconfig.base.json", "tsconfig.json", ".env"];
|
|
34
35
|
const IGNORED_DIRS = /* @__PURE__ */ new Set([".git", "coverage", "dist", "node_modules"]);
|
|
@@ -254,7 +255,12 @@ class InProcessTaskHasher {
|
|
|
254
255
|
const seen = /* @__PURE__ */ new Set();
|
|
255
256
|
for (const input of inputs) {
|
|
256
257
|
if (typeof input === "string") {
|
|
257
|
-
if (
|
|
258
|
+
if (looksLikeInputUri(input)) {
|
|
259
|
+
const parsed = parseInputUri(input);
|
|
260
|
+
if (parsed) {
|
|
261
|
+
result.push(parsed);
|
|
262
|
+
}
|
|
263
|
+
} else if (input.startsWith("{") || input.startsWith("!{")) {
|
|
258
264
|
result.push({ fileset: input });
|
|
259
265
|
} else if (input.startsWith("^")) {
|
|
260
266
|
continue;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createRequire as __cjs_createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
const __cjs_require = __cjs_createRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
|
|
6
|
+
|
|
7
|
+
const __cjs_getBuiltinModule = (module) => {
|
|
8
|
+
// Check if we're in Node.js and version supports getBuiltinModule
|
|
9
|
+
if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
|
|
10
|
+
const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
|
|
11
|
+
// Node.js 20.16.0+ and 22.3.0+
|
|
12
|
+
if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
|
|
13
|
+
return __cjs_getProcess.getBuiltinModule(module);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Fallback to createRequire
|
|
17
|
+
return __cjs_require(module);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
createReadStream,
|
|
22
|
+
createWriteStream
|
|
23
|
+
} = __cjs_getBuiltinModule("node:fs");
|
|
24
|
+
const {
|
|
25
|
+
stat,
|
|
26
|
+
mkdir,
|
|
27
|
+
writeFile,
|
|
28
|
+
rename,
|
|
29
|
+
rm,
|
|
30
|
+
utimes
|
|
31
|
+
} = __cjs_getBuiltinModule("node:fs/promises");
|
|
32
|
+
const {
|
|
33
|
+
pipeline
|
|
34
|
+
} = __cjs_getBuiltinModule("node:stream/promises");
|
|
35
|
+
import { dirname } from '@visulima/path';
|
|
36
|
+
import { u as uniqueId } from './utils-Bmnj-H2J.js';
|
|
37
|
+
import { digestFile } from './digestBuffer-CPdI2E1d.js';
|
|
38
|
+
import { casBlobPath, tmpDirectory } from './V2_ROOT-DKBLxKo4.js';
|
|
39
|
+
|
|
40
|
+
const containsBlob = async (root, digest) => {
|
|
41
|
+
try {
|
|
42
|
+
const stats = await stat(casBlobPath(root, digest.hash));
|
|
43
|
+
return stats.isFile() && stats.size === digest.sizeBytes;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const putBlobFromFile = async (root, digest, sourcePath) => {
|
|
49
|
+
const finalPath = casBlobPath(root, digest.hash);
|
|
50
|
+
if (await containsBlob(root, digest)) {
|
|
51
|
+
await touchBlob(root, digest).catch(() => {
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const stagingPath = await stageBlob(root, sourcePath);
|
|
56
|
+
try {
|
|
57
|
+
await mkdir(dirname(finalPath), { recursive: true });
|
|
58
|
+
await rename(stagingPath, finalPath);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
await rm(stagingPath, { force: true }).catch(() => {
|
|
61
|
+
});
|
|
62
|
+
if (!isAlreadyExistsError(error)) {
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const putBlobFromBytes = async (root, digest, bytes) => {
|
|
68
|
+
const finalPath = casBlobPath(root, digest.hash);
|
|
69
|
+
if (await containsBlob(root, digest)) {
|
|
70
|
+
await touchBlob(root, digest).catch(() => {
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const tmpDirectoryPath = tmpDirectory(root);
|
|
75
|
+
const stagingPath = `${tmpDirectoryPath}/${uniqueId()}`;
|
|
76
|
+
await mkdir(tmpDirectoryPath, { recursive: true });
|
|
77
|
+
await writeFile(stagingPath, bytes);
|
|
78
|
+
try {
|
|
79
|
+
await mkdir(dirname(finalPath), { recursive: true });
|
|
80
|
+
await rename(stagingPath, finalPath);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
await rm(stagingPath, { force: true }).catch(() => {
|
|
83
|
+
});
|
|
84
|
+
if (!isAlreadyExistsError(error)) {
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const fetchBlobToFile = async (root, digest, destinationPath) => {
|
|
90
|
+
const sourcePath = casBlobPath(root, digest.hash);
|
|
91
|
+
try {
|
|
92
|
+
await stat(sourcePath);
|
|
93
|
+
} catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
await mkdir(dirname(destinationPath), { recursive: true });
|
|
97
|
+
await pipeline(createReadStream(sourcePath), createWriteStream(destinationPath));
|
|
98
|
+
await touchBlob(root, digest).catch(() => {
|
|
99
|
+
});
|
|
100
|
+
return true;
|
|
101
|
+
};
|
|
102
|
+
const verifyBlob = async (filePath, expected) => {
|
|
103
|
+
const computed = await digestFile(filePath);
|
|
104
|
+
return computed?.hash === expected.hash && computed.sizeBytes === expected.sizeBytes;
|
|
105
|
+
};
|
|
106
|
+
const touchBlob = async (root, digest) => {
|
|
107
|
+
const now = /* @__PURE__ */ new Date();
|
|
108
|
+
await utimes(casBlobPath(root, digest.hash), now, now);
|
|
109
|
+
};
|
|
110
|
+
const stageBlob = async (root, sourcePath) => {
|
|
111
|
+
const tmpDirectoryPath = tmpDirectory(root);
|
|
112
|
+
const stagingPath = `${tmpDirectoryPath}/${uniqueId()}`;
|
|
113
|
+
await mkdir(tmpDirectoryPath, { recursive: true });
|
|
114
|
+
await pipeline(createReadStream(sourcePath), createWriteStream(stagingPath));
|
|
115
|
+
return stagingPath;
|
|
116
|
+
};
|
|
117
|
+
const isAlreadyExistsError = (error) => {
|
|
118
|
+
if (typeof error !== "object" || error === null) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const { code } = error;
|
|
122
|
+
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export { containsBlob, fetchBlobToFile, putBlobFromBytes, putBlobFromFile, touchBlob, verifyBlob };
|
|
@@ -16,6 +16,13 @@ const parseTaskId = (taskId) => {
|
|
|
16
16
|
target: parts[1]
|
|
17
17
|
};
|
|
18
18
|
};
|
|
19
|
+
const normalizeWarningPattern = (value) => {
|
|
20
|
+
if (value === void 0) {
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
const list = typeof value === "string" ? [value] : value;
|
|
24
|
+
return list.length === 0 ? void 0 : list;
|
|
25
|
+
};
|
|
19
26
|
const getTaskOutputs = (projectName, targetName, workspace, targetDefaults) => {
|
|
20
27
|
const project = workspace.projects[projectName];
|
|
21
28
|
const targetConfig = project?.targets?.[targetName];
|
|
@@ -40,12 +47,17 @@ const getSameProjectTask = (projectName, targetName, overrides, workspace, targe
|
|
|
40
47
|
{
|
|
41
48
|
always: project.targets?.[targetName]?.always ?? targetDefaults?.[targetName]?.always,
|
|
42
49
|
cache: project.targets?.[targetName]?.cache ?? targetDefaults?.[targetName]?.cache,
|
|
50
|
+
cacheOnWarning: project.targets?.[targetName]?.cacheOnWarning ?? targetDefaults?.[targetName]?.cacheOnWarning,
|
|
51
|
+
cacheRestore: project.targets?.[targetName]?.cacheRestore ?? targetDefaults?.[targetName]?.cacheRestore,
|
|
43
52
|
id: getTaskId(target),
|
|
44
53
|
outputs: getTaskOutputs(projectName, targetName, workspace, targetDefaults),
|
|
45
54
|
overrides,
|
|
46
55
|
parallelism: project.targets?.[targetName]?.parallelism ?? targetDefaults?.[targetName]?.parallelism,
|
|
47
56
|
projectRoot: project.root,
|
|
48
57
|
target,
|
|
58
|
+
warningPattern: normalizeWarningPattern(
|
|
59
|
+
project.targets?.[targetName]?.warningPattern ?? targetDefaults?.[targetName]?.warningPattern
|
|
60
|
+
),
|
|
49
61
|
when: project.targets?.[targetName]?.when ?? targetDefaults?.[targetName]?.when
|
|
50
62
|
}
|
|
51
63
|
];
|
|
@@ -67,12 +79,17 @@ const getDependencyProjectTasks = (projectName, targetName, overrides, workspace
|
|
|
67
79
|
tasks.push({
|
|
68
80
|
always: depProject.targets?.[targetName]?.always ?? targetDefaults?.[targetName]?.always,
|
|
69
81
|
cache: depProject.targets?.[targetName]?.cache ?? targetDefaults?.[targetName]?.cache,
|
|
82
|
+
cacheOnWarning: depProject.targets?.[targetName]?.cacheOnWarning ?? targetDefaults?.[targetName]?.cacheOnWarning,
|
|
83
|
+
cacheRestore: depProject.targets?.[targetName]?.cacheRestore ?? targetDefaults?.[targetName]?.cacheRestore,
|
|
70
84
|
id: getTaskId(target),
|
|
71
85
|
outputs: getTaskOutputs(dep.target, targetName, workspace, targetDefaults),
|
|
72
86
|
overrides,
|
|
73
87
|
parallelism: depProject.targets?.[targetName]?.parallelism ?? targetDefaults?.[targetName]?.parallelism,
|
|
74
88
|
projectRoot: depProject.root,
|
|
75
89
|
target,
|
|
90
|
+
warningPattern: normalizeWarningPattern(
|
|
91
|
+
depProject.targets?.[targetName]?.warningPattern ?? targetDefaults?.[targetName]?.warningPattern
|
|
92
|
+
),
|
|
76
93
|
when: depProject.targets?.[targetName]?.when ?? targetDefaults?.[targetName]?.when
|
|
77
94
|
});
|
|
78
95
|
}
|