@pnpm/deps.graph-hasher 1100.2.18 → 1100.3.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/CHANGELOG.md +18 -0
- package/lib/index.d.ts +25 -0
- package/lib/index.js +80 -20
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @pnpm/calc-dep-state
|
|
2
2
|
|
|
3
|
+
## 1100.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added an opt-in proof of concept that lets installs reuse a dependency's build output across machines, by publishing and restoring signed, organization-scoped artifacts through pnpr instead of running the lifecycle scripts locally.
|
|
8
|
+
|
|
9
|
+
Configure it with the new `remoteSideEffectsCache` setting. A workspace names the eligible `organization` and `packages`; everything describing the act of signing — `publish`, `keyId`, `builderId`, `trustedKeys`, `privateKey` and the provenance fields — is refused in `pnpm-workspace.yaml` and read from the global config file or the environment instead.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies:
|
|
14
|
+
- @pnpm/deps.path@1101.0.1
|
|
15
|
+
- @pnpm/engine.runtime.system-version@1100.0.11
|
|
16
|
+
- @pnpm/lockfile.types@1100.1.0
|
|
17
|
+
- @pnpm/lockfile.utils@1102.1.0
|
|
18
|
+
- @pnpm/resolving.resolver-base@1101.2.0
|
|
19
|
+
- @pnpm/types@1102.1.0
|
|
20
|
+
|
|
3
21
|
## 1100.2.18
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/lib/index.d.ts
CHANGED
|
@@ -51,6 +51,31 @@ export interface DepsGraphNode<T extends string> {
|
|
|
51
51
|
export interface DepsStateCache {
|
|
52
52
|
[depPath: string]: string;
|
|
53
53
|
}
|
|
54
|
+
export declare const DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX = "dependency-side-effects:v1:";
|
|
55
|
+
export interface CalcDepStateInputKeyOptions<T extends string> {
|
|
56
|
+
depsGraph: DepsGraph<T>;
|
|
57
|
+
depPath: T;
|
|
58
|
+
patchFileHash?: string;
|
|
59
|
+
supportedArchitectures?: SupportedArchitectures;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Compute the machine-independent lookup key for a remotely shareable
|
|
63
|
+
* dependency build.
|
|
64
|
+
*
|
|
65
|
+
* `depsGraph` must contain `depPath`, and every reachable node must provide
|
|
66
|
+
* either `fullPkgId` or the resolution metadata needed to derive it. The
|
|
67
|
+
* function does not mutate the graph or caller state. Each call uses an
|
|
68
|
+
* isolated cache, so the result is independent of earlier roots and platform
|
|
69
|
+
* selections.
|
|
70
|
+
*
|
|
71
|
+
* The returned key starts with {@link DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX},
|
|
72
|
+
* followed by the recursive dependency-graph hash and, when non-empty, the
|
|
73
|
+
* patch-file hash. Host identity is excluded and advertised by the artifact's
|
|
74
|
+
* signed compatibility constraints. When a resolution contains platform
|
|
75
|
+
* variations, `supportedArchitectures` selects the source integrity included
|
|
76
|
+
* in the graph hash.
|
|
77
|
+
*/
|
|
78
|
+
export declare function calcDepStateInputKey<T extends string>(opts: CalcDepStateInputKeyOptions<T>): string;
|
|
54
79
|
export declare function calcDepState<T extends string>(depsGraph: DepsGraph<T>, cache: DepsStateCache, depPath: string, opts: {
|
|
55
80
|
patchFileHash?: string;
|
|
56
81
|
includeDepGraphHash: boolean;
|
package/lib/index.js
CHANGED
|
@@ -71,11 +71,52 @@ export function readSnapshotRuntimePin(children) {
|
|
|
71
71
|
const ref = children?.node;
|
|
72
72
|
return ref != null ? extractRuntimeNodeVersion(ref) : undefined;
|
|
73
73
|
}
|
|
74
|
+
export const DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX = 'dependency-side-effects:v1:';
|
|
75
|
+
/**
|
|
76
|
+
* Compute the machine-independent lookup key for a remotely shareable
|
|
77
|
+
* dependency build.
|
|
78
|
+
*
|
|
79
|
+
* `depsGraph` must contain `depPath`, and every reachable node must provide
|
|
80
|
+
* either `fullPkgId` or the resolution metadata needed to derive it. The
|
|
81
|
+
* function does not mutate the graph or caller state. Each call uses an
|
|
82
|
+
* isolated cache, so the result is independent of earlier roots and platform
|
|
83
|
+
* selections.
|
|
84
|
+
*
|
|
85
|
+
* The returned key starts with {@link DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX},
|
|
86
|
+
* followed by the recursive dependency-graph hash and, when non-empty, the
|
|
87
|
+
* patch-file hash. Host identity is excluded and advertised by the artifact's
|
|
88
|
+
* signed compatibility constraints. When a resolution contains platform
|
|
89
|
+
* variations, `supportedArchitectures` selects the source integrity included
|
|
90
|
+
* in the graph hash.
|
|
91
|
+
*/
|
|
92
|
+
export function calcDepStateInputKey(opts) {
|
|
93
|
+
if (opts.depsGraph[opts.depPath] == null) {
|
|
94
|
+
throw new Error(`Dependency side-effects input-key root ${opts.depPath} is not present in depsGraph`);
|
|
95
|
+
}
|
|
96
|
+
const depGraphHash = calcDepGraphHash({
|
|
97
|
+
depsGraph: opts.depsGraph,
|
|
98
|
+
cache: {},
|
|
99
|
+
parents: new Set(),
|
|
100
|
+
depPath: opts.depPath,
|
|
101
|
+
context: createDepGraphHashContext(opts.supportedArchitectures),
|
|
102
|
+
});
|
|
103
|
+
let result = `${DEPENDENCY_SIDE_EFFECTS_INPUT_KEY_PREFIX}deps=${depGraphHash}`;
|
|
104
|
+
if (opts.patchFileHash) {
|
|
105
|
+
result += `;patch=${opts.patchFileHash}`;
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
74
109
|
export function calcDepState(depsGraph, cache, depPath, opts) {
|
|
75
110
|
const ownPin = readSnapshotRuntimePin(depsGraph[depPath]?.children);
|
|
76
111
|
let result = engineName(ownPin ?? opts.nodeVersion);
|
|
77
112
|
if (opts.includeDepGraphHash) {
|
|
78
|
-
const depGraphHash = calcDepGraphHash(
|
|
113
|
+
const depGraphHash = calcDepGraphHash({
|
|
114
|
+
depsGraph,
|
|
115
|
+
cache,
|
|
116
|
+
parents: new Set(),
|
|
117
|
+
depPath: depPath,
|
|
118
|
+
context: createDepGraphHashContext(opts.supportedArchitectures),
|
|
119
|
+
});
|
|
79
120
|
result += `;deps=${depGraphHash}`;
|
|
80
121
|
}
|
|
81
122
|
if (opts.patchFileHash) {
|
|
@@ -83,36 +124,47 @@ export function calcDepState(depsGraph, cache, depPath, opts) {
|
|
|
83
124
|
}
|
|
84
125
|
return result;
|
|
85
126
|
}
|
|
86
|
-
function calcDepGraphHash(depsGraph, cache, parents, depPath,
|
|
87
|
-
|
|
88
|
-
|
|
127
|
+
function calcDepGraphHash({ depsGraph, cache, parents, depPath, context, }) {
|
|
128
|
+
const cacheKey = `${context.cacheKeyPrefix}${depPath}`;
|
|
129
|
+
if (cache[cacheKey])
|
|
130
|
+
return cache[cacheKey];
|
|
89
131
|
const node = depsGraph[depPath];
|
|
90
132
|
if (!node)
|
|
91
133
|
return '';
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
node.fullPkgId = createFullPkgId(node.pkgIdWithPatchHash, node.resolution, supportedArchitectures);
|
|
134
|
+
let fullPkgId = node.fullPkgId;
|
|
135
|
+
if (node.pkgIdWithPatchHash != null && node.resolution != null) {
|
|
136
|
+
fullPkgId = createFullPkgId(node.pkgIdWithPatchHash, node.resolution, context.supportedArchitectures);
|
|
137
|
+
}
|
|
138
|
+
else if (fullPkgId == null) {
|
|
139
|
+
throw new Error(`fullPkgId or resolution metadata is not defined for ${depPath} in depsGraph`);
|
|
100
140
|
}
|
|
101
141
|
const deps = {};
|
|
102
|
-
if (Object.keys(node.children).length && !parents.has(
|
|
103
|
-
const nextParents = new Set([...Array.from(parents),
|
|
142
|
+
if (Object.keys(node.children).length && !parents.has(fullPkgId)) {
|
|
143
|
+
const nextParents = new Set([...Array.from(parents), fullPkgId]);
|
|
104
144
|
for (const alias in node.children) {
|
|
105
145
|
if (Object.hasOwn(node.children, alias)) {
|
|
106
146
|
const childId = node.children[alias];
|
|
107
|
-
deps[alias] = calcDepGraphHash(
|
|
147
|
+
deps[alias] = calcDepGraphHash({
|
|
148
|
+
depsGraph,
|
|
149
|
+
cache,
|
|
150
|
+
parents: nextParents,
|
|
151
|
+
depPath: childId,
|
|
152
|
+
context,
|
|
153
|
+
});
|
|
108
154
|
}
|
|
109
155
|
}
|
|
110
156
|
}
|
|
111
|
-
cache[
|
|
112
|
-
id:
|
|
157
|
+
cache[cacheKey] = hashObject({
|
|
158
|
+
id: fullPkgId,
|
|
113
159
|
deps,
|
|
114
160
|
});
|
|
115
|
-
return cache[
|
|
161
|
+
return cache[cacheKey];
|
|
162
|
+
}
|
|
163
|
+
function createDepGraphHashContext(supportedArchitectures) {
|
|
164
|
+
return {
|
|
165
|
+
supportedArchitectures,
|
|
166
|
+
cacheKeyPrefix: supportedArchitectures == null ? '' : `\0architectures=${hashObject(supportedArchitectures)}\0`,
|
|
167
|
+
};
|
|
116
168
|
}
|
|
117
169
|
export function* iterateHashedGraphNodes(graph, pkgMetaIterator, opts = {}) {
|
|
118
170
|
let builtDepPaths;
|
|
@@ -157,7 +209,13 @@ export function calcGraphNodeHash({ graph, cache, builtDepPaths, buildRequiredCa
|
|
|
157
209
|
// to the install-wide value.
|
|
158
210
|
const ownPin = readSnapshotRuntimePin(graph[depPath]?.children);
|
|
159
211
|
const engine = includeEngine ? engineName(ownPin ?? nodeVersion) : null;
|
|
160
|
-
const deps = calcDepGraphHash(
|
|
212
|
+
const deps = calcDepGraphHash({
|
|
213
|
+
depsGraph: graph,
|
|
214
|
+
cache,
|
|
215
|
+
parents: new Set(),
|
|
216
|
+
depPath,
|
|
217
|
+
context: createDepGraphHashContext(supportedArchitectures),
|
|
218
|
+
});
|
|
161
219
|
const isLocalDirectory = isLocalDirectoryResolution(graph[depPath]?.resolution);
|
|
162
220
|
// Scoping the slot needs the project's identity; the segment only needs to
|
|
163
221
|
// know that the package is a local directory, so a caller that leaves
|
|
@@ -259,14 +317,16 @@ export function lockfileToDepGraph(lockfile, supportedArchitectures, lockfileDir
|
|
|
259
317
|
const linkTargetNodes = new Set();
|
|
260
318
|
if (lockfile.packages != null) {
|
|
261
319
|
for (const [depPath, pkgSnapshot] of Object.entries(lockfile.packages)) {
|
|
320
|
+
const pkgIdWithPatchHash = getPkgIdWithPatchHash(depPath);
|
|
262
321
|
const children = lockfileDepsToGraphChildren({
|
|
263
322
|
...pkgSnapshot.dependencies,
|
|
264
323
|
...pkgSnapshot.optionalDependencies,
|
|
265
324
|
}, lockfileDir, linkTargetNodes);
|
|
266
325
|
graph[depPath] = {
|
|
267
326
|
children,
|
|
327
|
+
pkgIdWithPatchHash,
|
|
268
328
|
resolution: pkgSnapshot.resolution,
|
|
269
|
-
fullPkgId: createFullPkgId(
|
|
329
|
+
fullPkgId: createFullPkgId(pkgIdWithPatchHash, pkgSnapshot.resolution, supportedArchitectures),
|
|
270
330
|
};
|
|
271
331
|
}
|
|
272
332
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/deps.graph-hasher",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.3.0",
|
|
4
4
|
"description": "Calculates the state of a dependency",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -28,17 +28,17 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@pnpm/crypto.object-hasher": "1100.0.1",
|
|
31
|
-
"@pnpm/deps.path": "1101.0.
|
|
32
|
-
"@pnpm/engine.runtime.system-version": "1100.0.
|
|
33
|
-
"@pnpm/lockfile.types": "1100.0
|
|
34
|
-
"@pnpm/lockfile.utils": "1102.
|
|
35
|
-
"@pnpm/resolving.resolver-base": "1101.
|
|
36
|
-
"@pnpm/types": "1102.
|
|
31
|
+
"@pnpm/deps.path": "1101.0.1",
|
|
32
|
+
"@pnpm/engine.runtime.system-version": "1100.0.11",
|
|
33
|
+
"@pnpm/lockfile.types": "1100.1.0",
|
|
34
|
+
"@pnpm/lockfile.utils": "1102.1.0",
|
|
35
|
+
"@pnpm/resolving.resolver-base": "1101.2.0",
|
|
36
|
+
"@pnpm/types": "1102.1.0",
|
|
37
37
|
"detect-libc": "^2.1.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@jest/globals": "30.4.1",
|
|
41
|
-
"@pnpm/deps.graph-hasher": "1100.
|
|
41
|
+
"@pnpm/deps.graph-hasher": "1100.3.0"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=22.13"
|