nx-auto-cache-deps 0.0.2 → 0.0.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/LICENSE +21 -0
- package/THIRD_PARTY_LICENSES +2531 -0
- package/dist/dependencies.js +38 -10
- package/dist/executor.js +7 -3
- package/dist/store.js +4 -2
- package/package.json +3 -2
package/dist/dependencies.js
CHANGED
|
@@ -14,7 +14,24 @@ const toWorkspacePath = (workspaceRoot, absolutePath) => {
|
|
|
14
14
|
return path.split(sep).join('/');
|
|
15
15
|
};
|
|
16
16
|
const sortedUnique = (values) => [...new Set(values)].sort();
|
|
17
|
-
|
|
17
|
+
const isWithin = (path, base) => base === '.' || path === base || path.startsWith(`${base}/`);
|
|
18
|
+
/** 成果物そのもの・その中・その祖先のパス。成果物の削除や復元で状態が変わるため、入力として評価しない。 */
|
|
19
|
+
const touchesOutput = (path, outputs) => outputs.some((output) => isWithin(path, output) || isWithin(output, path));
|
|
20
|
+
const GLOB_CHARACTERS = /[*?[\]{}!]/;
|
|
21
|
+
/**
|
|
22
|
+
* Nx の outputs(ワークスペースルートからの相対パス。glob を含みうる)を、除外に使うディレクトリまたはファイルのパスにする。
|
|
23
|
+
* glob はその手前のディレクトリまでに広げる。否定 (`!`) は除外を狭めるだけなので使わない。
|
|
24
|
+
*/
|
|
25
|
+
export const toOutputPaths = (outputs) => sortedUnique(outputs
|
|
26
|
+
.filter((output) => !output.startsWith('!'))
|
|
27
|
+
.map((output) => {
|
|
28
|
+
const segments = output.split('/');
|
|
29
|
+
const index = segments.findIndex((segment) => GLOB_CHARACTERS.test(segment));
|
|
30
|
+
return (index === -1 ? segments : segments.slice(0, index)).join('/');
|
|
31
|
+
})
|
|
32
|
+
// 先頭から glob の outputs はワークスペース全体を除外してしまうため使わない
|
|
33
|
+
.filter((output) => output !== ''));
|
|
34
|
+
export const toDependencyList = (accesses, workspaceRoot, outputs) => {
|
|
18
35
|
const inWorkspace = accesses.flatMap((access) => {
|
|
19
36
|
const path = toWorkspacePath(workspaceRoot, access.path);
|
|
20
37
|
return path === undefined ? [] : [{ kind: access.kind, path }];
|
|
@@ -22,13 +39,23 @@ export const toDependencyList = (accesses, workspaceRoot) => {
|
|
|
22
39
|
// 自分で書いたパスを入力にすると、成果物の更新だけで毎回ミスするため除く
|
|
23
40
|
const written = new Set(inWorkspace.filter((a) => a.kind === 'write').map((a) => a.path));
|
|
24
41
|
const observed = (kind) => sortedUnique(inWorkspace.filter((a) => a.kind === kind && !written.has(a.path)).map((a) => a.path));
|
|
25
|
-
return {
|
|
42
|
+
return {
|
|
43
|
+
version: 2,
|
|
44
|
+
paths: observed('read').filter((path) => !touchesOutput(path, outputs)),
|
|
45
|
+
// 成果物の祖先の列挙は残し、評価時に成果物へ通じるエントリだけを無視する
|
|
46
|
+
directories: observed('readDir').filter((path) => !outputs.some((output) => isWithin(path, output))),
|
|
47
|
+
outputs: sortedUnique(outputs),
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export const mergeDependencyLists = (a, b) => {
|
|
51
|
+
const outputs = sortedUnique([...a.outputs, ...b.outputs]);
|
|
52
|
+
return {
|
|
53
|
+
version: 2,
|
|
54
|
+
paths: sortedUnique([...a.paths, ...b.paths]).filter((path) => !touchesOutput(path, outputs)),
|
|
55
|
+
directories: sortedUnique([...a.directories, ...b.directories]).filter((path) => !outputs.some((output) => isWithin(path, output))),
|
|
56
|
+
outputs,
|
|
57
|
+
};
|
|
26
58
|
};
|
|
27
|
-
export const mergeDependencyLists = (a, b) => ({
|
|
28
|
-
version: 1,
|
|
29
|
-
paths: sortedUnique([...a.paths, ...b.paths]),
|
|
30
|
-
directories: sortedUnique([...a.directories, ...b.directories]),
|
|
31
|
-
});
|
|
32
59
|
const isMissingError = (error) => error instanceof Error && 'code' in error && (error.code === 'ENOENT' || error.code === 'ENOTDIR');
|
|
33
60
|
const pathState = (absolutePath) => {
|
|
34
61
|
const stats = statSync(absolutePath, { throwIfNoEntry: false });
|
|
@@ -40,9 +67,10 @@ const pathState = (absolutePath) => {
|
|
|
40
67
|
return `file:${createHash('sha256').update(readFileSync(absolutePath)).digest('hex')}`;
|
|
41
68
|
return 'other';
|
|
42
69
|
};
|
|
43
|
-
const directoryState = (
|
|
70
|
+
const directoryState = (workspaceRoot, path, outputs) => {
|
|
44
71
|
try {
|
|
45
|
-
return readdirSync(
|
|
72
|
+
return readdirSync(join(workspaceRoot, path), { withFileTypes: true })
|
|
73
|
+
.filter((entry) => !touchesOutput(path === '.' ? entry.name : `${path}/${entry.name}`, outputs))
|
|
46
74
|
.map((entry) => `${entry.name}:${entry.isDirectory() ? 'd' : entry.isFile() ? 'f' : entry.isSymbolicLink() ? 'l' : 'o'}`)
|
|
47
75
|
.sort()
|
|
48
76
|
.join('\n');
|
|
@@ -59,6 +87,6 @@ export const fingerprint = (list, workspaceRoot) => {
|
|
|
59
87
|
for (const path of list.paths)
|
|
60
88
|
hash.update(`path\0${path}\0${pathState(join(workspaceRoot, path))}\0`);
|
|
61
89
|
for (const path of list.directories)
|
|
62
|
-
hash.update(`dir\0${path}\0${directoryState(
|
|
90
|
+
hash.update(`dir\0${path}\0${directoryState(workspaceRoot, path, list.outputs)}\0`);
|
|
63
91
|
return hash.digest('hex');
|
|
64
92
|
};
|
package/dist/executor.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { cacheDir, logger } from '@nx/devkit';
|
|
1
|
+
import { cacheDir, getOutputsForTargetAndConfiguration, logger } from '@nx/devkit';
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
3
|
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { mergeDependencyLists, toDependencyList } from './dependencies.js';
|
|
6
|
+
import { mergeDependencyLists, toDependencyList, toOutputPaths } from './dependencies.js';
|
|
7
7
|
import { resolveTraceBinary } from './platform.js';
|
|
8
8
|
import { dependencyListPath, readDependencyList, storeDirectory, taskKey, writeDependencyList } from './store.js';
|
|
9
9
|
const runOriginalScript = fileURLToPath(new URL('./run-original.js', import.meta.url));
|
|
@@ -36,7 +36,11 @@ export default async function run(options, context) {
|
|
|
36
36
|
}
|
|
37
37
|
else if (code === 0) {
|
|
38
38
|
const listPath = dependencyListPath(cacheDir, taskKey(project.root, targetName));
|
|
39
|
-
const
|
|
39
|
+
const node = context.projectGraph.nodes[projectName];
|
|
40
|
+
if (node === undefined)
|
|
41
|
+
throw new Error(`nx-auto-cache-deps: ${projectName} is not in the project graph`);
|
|
42
|
+
const outputs = getOutputsForTargetAndConfiguration({ project: projectName, target: targetName, ...(context.configurationName === undefined ? {} : { configuration: context.configurationName }) }, options, node);
|
|
43
|
+
const observed = toDependencyList(report.accesses, context.root, toOutputPaths(outputs));
|
|
40
44
|
const stored = readDependencyList(listPath);
|
|
41
45
|
writeDependencyList(listPath, stored.status === 'found' ? mergeDependencyLists(stored.list, observed) : observed);
|
|
42
46
|
}
|
package/dist/store.js
CHANGED
|
@@ -8,11 +8,13 @@ export const dependencyListPath = (cacheDirectory, key) => join(storeDirectory(c
|
|
|
8
8
|
const isDependencyList = (value) => typeof value === 'object' &&
|
|
9
9
|
value !== null &&
|
|
10
10
|
'version' in value &&
|
|
11
|
-
value.version ===
|
|
11
|
+
value.version === 2 &&
|
|
12
12
|
'paths' in value &&
|
|
13
13
|
Array.isArray(value.paths) &&
|
|
14
14
|
'directories' in value &&
|
|
15
|
-
Array.isArray(value.directories)
|
|
15
|
+
Array.isArray(value.directories) &&
|
|
16
|
+
'outputs' in value &&
|
|
17
|
+
Array.isArray(value.outputs);
|
|
16
18
|
export const readDependencyList = (path) => {
|
|
17
19
|
let text;
|
|
18
20
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx-auto-cache-deps",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Nx plugin that derives cache inputs from the files a task actually accessed",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"dist",
|
|
17
17
|
"schemas",
|
|
18
18
|
"executors.json",
|
|
19
|
-
"generators.json"
|
|
19
|
+
"generators.json",
|
|
20
|
+
"THIRD_PARTY_LICENSES"
|
|
20
21
|
],
|
|
21
22
|
"preferUnplugged": true,
|
|
22
23
|
"scripts": {
|