@vltpkg/graph 1.1.1 → 1.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/dist/graph.js +9 -2
- package/dist/lockfile/load-nodes.js +4 -1
- package/dist/lockfile/types.d.ts +14 -3
- package/dist/lockfile/types.js +12 -4
- package/dist/node.d.ts +20 -0
- package/dist/node.js +65 -4
- package/dist/reify/bin-chmod.js +14 -14
- package/dist/reify/binding-gyp.d.ts +8 -0
- package/dist/reify/binding-gyp.js +19 -0
- package/dist/reify/build.js +2 -5
- package/dist/reify/check-needed-build.js +4 -5
- package/dist/reify/extract-node.js +26 -12
- package/dist/reify/index.js +10 -0
- package/package.json +22 -22
package/dist/graph.js
CHANGED
|
@@ -427,7 +427,11 @@ export class Graph {
|
|
|
427
427
|
toFoundNode.manifest = manifest;
|
|
428
428
|
this.manifests.set(toFoundNode.id, manifest);
|
|
429
429
|
}
|
|
430
|
-
|
|
430
|
+
// never onto a node resolved to a `.tar.br`: `dist.integrity`
|
|
431
|
+
// is the `.tgz` hash, a different artifact's bytes
|
|
432
|
+
if (!toFoundNode.brotli) {
|
|
433
|
+
toFoundNode.integrity ??= manifest.dist?.integrity;
|
|
434
|
+
}
|
|
431
435
|
}
|
|
432
436
|
return toFoundNode;
|
|
433
437
|
}
|
|
@@ -455,7 +459,10 @@ export class Graph {
|
|
|
455
459
|
toNode.optional = flags.optional;
|
|
456
460
|
if (samePackage)
|
|
457
461
|
copyPackageMetadata(toNode, samePackage);
|
|
458
|
-
|
|
462
|
+
// not onto a node bound for the `.tar.br`: `dist.integrity` is the
|
|
463
|
+
// `.tgz` hash, and that is a different artifact's bytes
|
|
464
|
+
if (!toNode.brotli)
|
|
465
|
+
toNode.integrity ??= manifest?.dist?.integrity;
|
|
459
466
|
// split extra into modifier and peerSetHash
|
|
460
467
|
if (extra) {
|
|
461
468
|
const { modifier, peerSetHash } = splitExtra(extra);
|
|
@@ -68,10 +68,13 @@ export const loadNodes = (graph, nodes, options, actual, throwOnMissingManifest)
|
|
|
68
68
|
node.peerSetHash = peerSetHash;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
const { dev, optional } = getBooleanFlagsFromNum(flags);
|
|
71
|
+
const { dev, optional, brotli } = getBooleanFlagsFromNum(flags);
|
|
72
72
|
node.options = options;
|
|
73
73
|
node.dev = dev;
|
|
74
74
|
node.optional = optional;
|
|
75
|
+
// before setResolved(), which needs it to pick the extension for a
|
|
76
|
+
// node whose `resolved` the lockfile left out
|
|
77
|
+
node.brotli = brotli;
|
|
75
78
|
node.integrity = integrity ?? referenceNode?.integrity;
|
|
76
79
|
node.resolved =
|
|
77
80
|
type === 'remote' ? filepath : ((resolved ?? referenceNode?.resolved));
|
package/dist/lockfile/types.d.ts
CHANGED
|
@@ -57,19 +57,30 @@ export declare const LOCKFILE_VERSION = 1;
|
|
|
57
57
|
export declare const getFlagNumFromNode: (node: {
|
|
58
58
|
optional?: boolean;
|
|
59
59
|
dev?: boolean;
|
|
60
|
-
|
|
60
|
+
brotli?: boolean;
|
|
61
|
+
}) => LockfileNodeFlags;
|
|
61
62
|
export declare const getBooleanFlagsFromNum: (flags: LockfileNodeFlags) => {
|
|
62
63
|
dev: boolean;
|
|
63
64
|
optional: boolean;
|
|
65
|
+
brotli: boolean;
|
|
64
66
|
};
|
|
65
67
|
export declare const LockfileNodeFlagNone = 0;
|
|
66
68
|
export declare const LockfileNodeFlagOptional = 1;
|
|
67
69
|
export declare const LockfileNodeFlagDev = 2;
|
|
68
70
|
export declare const LockfileNodeFlagDevOptional = 3;
|
|
69
71
|
/**
|
|
70
|
-
*
|
|
72
|
+
* This node's artifact is the registry's Brotli (`.tar.br`) tarball, so
|
|
73
|
+
* `integrity` is that artifact's hash. Carried as a flag bit rather than a
|
|
74
|
+
* field because a default-registry node writes no `resolved` at all --
|
|
75
|
+
* `Node.setResolved()` rebuilds the URL, and this is what tells it which
|
|
76
|
+
* extension to rebuild.
|
|
71
77
|
*/
|
|
72
|
-
export
|
|
78
|
+
export declare const LockfileNodeFlagBrotli = 4;
|
|
79
|
+
/**
|
|
80
|
+
* Bit flags indicating whether a node is optional, dev, and/or served as
|
|
81
|
+
* a Brotli tarball.
|
|
82
|
+
*/
|
|
83
|
+
export type LockfileNodeFlags = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
73
84
|
/**
|
|
74
85
|
* Build state constants for lockfile nodes
|
|
75
86
|
*/
|
package/dist/lockfile/types.js
CHANGED
|
@@ -4,18 +4,26 @@
|
|
|
4
4
|
* Bump when making breaking format changes.
|
|
5
5
|
*/
|
|
6
6
|
export const LOCKFILE_VERSION = 1;
|
|
7
|
-
export const getFlagNumFromNode = (node) => node.optional
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
: LockfileNodeFlagNone;
|
|
7
|
+
export const getFlagNumFromNode = (node) => ((node.optional ? LockfileNodeFlagOptional : 0) |
|
|
8
|
+
(node.dev ? LockfileNodeFlagDev : 0) |
|
|
9
|
+
(node.brotli ? LockfileNodeFlagBrotli : 0));
|
|
11
10
|
export const getBooleanFlagsFromNum = (flags) => ({
|
|
12
11
|
dev: !!(flags & LockfileNodeFlagDev),
|
|
13
12
|
optional: !!(flags & LockfileNodeFlagOptional),
|
|
13
|
+
brotli: !!(flags & LockfileNodeFlagBrotli),
|
|
14
14
|
});
|
|
15
15
|
export const LockfileNodeFlagNone = 0;
|
|
16
16
|
export const LockfileNodeFlagOptional = 1;
|
|
17
17
|
export const LockfileNodeFlagDev = 2;
|
|
18
18
|
export const LockfileNodeFlagDevOptional = 3;
|
|
19
|
+
/**
|
|
20
|
+
* This node's artifact is the registry's Brotli (`.tar.br`) tarball, so
|
|
21
|
+
* `integrity` is that artifact's hash. Carried as a flag bit rather than a
|
|
22
|
+
* field because a default-registry node writes no `resolved` at all --
|
|
23
|
+
* `Node.setResolved()` rebuilds the URL, and this is what tells it which
|
|
24
|
+
* extension to rebuild.
|
|
25
|
+
*/
|
|
26
|
+
export const LockfileNodeFlagBrotli = 4;
|
|
19
27
|
/**
|
|
20
28
|
* Build state constants for lockfile nodes
|
|
21
29
|
*/
|
package/dist/node.d.ts
CHANGED
|
@@ -7,6 +7,11 @@ import type { Graph } from './graph.ts';
|
|
|
7
7
|
export type NodeOptions = SpecOptions & {
|
|
8
8
|
projectRoot: string;
|
|
9
9
|
graph: GraphLike;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve to a version's Brotli (`.tar.br`) alternate when its manifest
|
|
12
|
+
* advertises one. Defaults to true; false always resolves to the `.tgz`.
|
|
13
|
+
*/
|
|
14
|
+
'brotli-tarballs'?: boolean;
|
|
10
15
|
};
|
|
11
16
|
export declare class Node implements NodeLike {
|
|
12
17
|
#private;
|
|
@@ -85,6 +90,16 @@ export declare class Node implements NodeLike {
|
|
|
85
90
|
* The manifest this node represents in the graph.
|
|
86
91
|
*/
|
|
87
92
|
manifest?: NormalizedManifest;
|
|
93
|
+
/**
|
|
94
|
+
* True when this node's artifact is the registry's Brotli (`.tar.br`)
|
|
95
|
+
* tarball rather than the gzip `.tgz`, which makes `integrity` that
|
|
96
|
+
* artifact's hash. `resolved` is authoritative whenever it is set, so
|
|
97
|
+
* the two can never drift; the stored bit only carries the lockfile's
|
|
98
|
+
* answer across to `setResolved()`, which has to know the extension
|
|
99
|
+
* before it can build the URL.
|
|
100
|
+
*/
|
|
101
|
+
get brotli(): boolean;
|
|
102
|
+
set brotli(brotli: boolean);
|
|
88
103
|
/**
|
|
89
104
|
* Project where this node resides
|
|
90
105
|
*/
|
|
@@ -128,6 +143,11 @@ export declare class Node implements NodeLike {
|
|
|
128
143
|
* Record of binary names to their paths in the package, if any.
|
|
129
144
|
*/
|
|
130
145
|
bins?: Record<string, string>;
|
|
146
|
+
/**
|
|
147
|
+
* True if the package has a root binding.gyp, when known without a
|
|
148
|
+
* disk check (placed from the global store). Not persisted.
|
|
149
|
+
*/
|
|
150
|
+
bindingGyp?: boolean;
|
|
131
151
|
/**
|
|
132
152
|
* True if this node has been built as part of the reify step.
|
|
133
153
|
*/
|
package/dist/node.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { isPackageNameConfused, getId, hydrateTuple, splitDepID, } from '@vltpkg/dep-id';
|
|
2
2
|
import { typeError } from '@vltpkg/error-cause';
|
|
3
|
-
import { expandNormalizedManifestSymbols } from '@vltpkg/types';
|
|
3
|
+
import { brotliTarballName, brotliTarballUrl, expandNormalizedManifestSymbols, tarballFormat, } from '@vltpkg/types';
|
|
4
4
|
import { Edge } from "./edge.js";
|
|
5
5
|
import { stringifyNode } from "./stringify-node.js";
|
|
6
|
+
/**
|
|
7
|
+
* The absolute URL of a version's Brotli (`.tar.br`) tarball. `dist`
|
|
8
|
+
* arrives here with an absolute `tarball`, so the alternate's relative
|
|
9
|
+
* reference resolves against it. See {@link brotliTarballUrl} for which
|
|
10
|
+
* references this client accepts.
|
|
11
|
+
*/
|
|
12
|
+
const brotliAlternate = (dist) => brotliTarballUrl(dist?.tarball, dist?.alternates);
|
|
6
13
|
export class Node {
|
|
7
14
|
get [Symbol.toStringTag]() {
|
|
8
15
|
return '@vltpkg/graph.Node';
|
|
@@ -110,6 +117,31 @@ export class Node {
|
|
|
110
117
|
* The manifest this node represents in the graph.
|
|
111
118
|
*/
|
|
112
119
|
manifest;
|
|
120
|
+
/**
|
|
121
|
+
* Whether this node's artifact is the `.tar.br`: from the manifest's
|
|
122
|
+
* `dist.alternates` at construction, or overwritten by the lockfile's
|
|
123
|
+
* flag bit when the node came from one (so an existing lockfile keeps
|
|
124
|
+
* whichever artifact it pinned). Only consulted while `resolved` is
|
|
125
|
+
* still unset -- once there is a URL, it is the answer (see the
|
|
126
|
+
* getter).
|
|
127
|
+
*/
|
|
128
|
+
#brotli = false;
|
|
129
|
+
/**
|
|
130
|
+
* True when this node's artifact is the registry's Brotli (`.tar.br`)
|
|
131
|
+
* tarball rather than the gzip `.tgz`, which makes `integrity` that
|
|
132
|
+
* artifact's hash. `resolved` is authoritative whenever it is set, so
|
|
133
|
+
* the two can never drift; the stored bit only carries the lockfile's
|
|
134
|
+
* answer across to `setResolved()`, which has to know the extension
|
|
135
|
+
* before it can build the URL.
|
|
136
|
+
*/
|
|
137
|
+
get brotli() {
|
|
138
|
+
return this.resolved ?
|
|
139
|
+
tarballFormat(this.resolved) === 'brotli'
|
|
140
|
+
: this.#brotli;
|
|
141
|
+
}
|
|
142
|
+
set brotli(brotli) {
|
|
143
|
+
this.#brotli = brotli;
|
|
144
|
+
}
|
|
113
145
|
/**
|
|
114
146
|
* Project where this node resides
|
|
115
147
|
*/
|
|
@@ -160,6 +192,11 @@ export class Node {
|
|
|
160
192
|
* Record of binary names to their paths in the package, if any.
|
|
161
193
|
*/
|
|
162
194
|
bins;
|
|
195
|
+
/**
|
|
196
|
+
* True if the package has a root binding.gyp, when known without a
|
|
197
|
+
* disk check (placed from the global store). Not persisted.
|
|
198
|
+
*/
|
|
199
|
+
bindingGyp;
|
|
163
200
|
/**
|
|
164
201
|
* True if this node has been built as part of the reify step.
|
|
165
202
|
*/
|
|
@@ -240,6 +277,13 @@ export class Node {
|
|
|
240
277
|
}
|
|
241
278
|
this.graph = options.graph;
|
|
242
279
|
this.manifest = manifest;
|
|
280
|
+
// Settled here, not in setResolved(), because `integrity` is filled
|
|
281
|
+
// in from `dist.integrity` between the two -- and that hash is the
|
|
282
|
+
// `.tgz`'s. A node whose artifact is the `.tar.br` has to be able to
|
|
283
|
+
// turn that down before it arrives.
|
|
284
|
+
this.#brotli =
|
|
285
|
+
options['brotli-tarballs'] !== false &&
|
|
286
|
+
!!brotliAlternate(manifest?.dist);
|
|
243
287
|
this.#name = name || this.manifest?.name;
|
|
244
288
|
this.version = version || this.manifest?.version;
|
|
245
289
|
}
|
|
@@ -258,9 +302,26 @@ export class Node {
|
|
|
258
302
|
}
|
|
259
303
|
#registryNodeResolved(tuple) {
|
|
260
304
|
const spec = hydrateTuple(tuple, this.#name, this.#options);
|
|
261
|
-
this.
|
|
262
|
-
|
|
263
|
-
|
|
305
|
+
const dist = this.manifest?.dist;
|
|
306
|
+
const tarball = dist?.tarball || spec.conventionalRegistryTarball;
|
|
307
|
+
const brotli = this.#brotli ?
|
|
308
|
+
// the manifest's own reference when there is one, and otherwise
|
|
309
|
+
// the registry's naming for it: same stem as the `.tgz`, a
|
|
310
|
+
// different extension. That convention is what lets a lockfile
|
|
311
|
+
// node -- which has no manifest -- spend one flag bit rather
|
|
312
|
+
// than a second URL.
|
|
313
|
+
(brotliAlternate(dist) ??
|
|
314
|
+
(tarball && brotliTarballName(tarball)))
|
|
315
|
+
: undefined;
|
|
316
|
+
if (brotli) {
|
|
317
|
+
this.resolved = brotli;
|
|
318
|
+
// `dist.integrity` describes the `.tgz`. The `.tar.br` is a
|
|
319
|
+
// different artifact with a different hash, pinned by its own
|
|
320
|
+
// `Repr-Digest` on the install that first fetches it.
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
this.resolved = tarball;
|
|
324
|
+
this.integrity ??= dist?.integrity;
|
|
264
325
|
}
|
|
265
326
|
get options() {
|
|
266
327
|
return this.#options;
|
package/dist/reify/bin-chmod.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { statSync
|
|
1
|
+
import { statSync } from 'node:fs';
|
|
2
2
|
import { chmod } from 'node:fs/promises';
|
|
3
3
|
/**
|
|
4
4
|
* Make all the packages' bins executable.
|
|
@@ -19,20 +19,20 @@ export const binChmod = async (node, scurry) => {
|
|
|
19
19
|
return;
|
|
20
20
|
for (const bin of Object.values(node.bins)) {
|
|
21
21
|
const path = scurry.resolve(`${node.resolvedLocation(scurry)}/${bin}`);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
let mode;
|
|
23
|
+
try {
|
|
24
|
+
mode = statSync(path).mode;
|
|
25
25
|
}
|
|
26
|
+
catch {
|
|
27
|
+
// missing or unreadable (ENOENT, ELOOP, EACCES): skip
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
// a file linked from the global store is executable already, and
|
|
31
|
+
// chmod would change the store
|
|
32
|
+
if ((mode & 0o111) === 0o111)
|
|
33
|
+
continue;
|
|
34
|
+
// `| 0o111` keeps group-writable files at 0o775
|
|
35
|
+
chmods.push(chmod(path, (mode & 0o777) | 0o111));
|
|
26
36
|
}
|
|
27
37
|
await Promise.all(chmods);
|
|
28
38
|
};
|
|
29
|
-
// 0 is "not yet set"
|
|
30
|
-
// This is defined by doing `0o111 | <mode>` so that systems
|
|
31
|
-
// that create files group-writable result in 0o775 instead of 0o755
|
|
32
|
-
let execMode = 0;
|
|
33
|
-
const makeExecutable = async (path) => {
|
|
34
|
-
if (!execMode) {
|
|
35
|
-
execMode = (statSync(path).mode & 0o777) | 0o111;
|
|
36
|
-
}
|
|
37
|
-
await chmod(path, execMode);
|
|
38
|
-
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PathScurry } from 'path-scurry';
|
|
2
|
+
import type { Node } from '../node.ts';
|
|
3
|
+
/**
|
|
4
|
+
* True if the package has a root binding.gyp (implicit install). Known
|
|
5
|
+
* from the global store index, else checked on disk past the path
|
|
6
|
+
* cache, which may still hold ENOENT from before the extraction.
|
|
7
|
+
*/
|
|
8
|
+
export declare const hasBindingGyp: (node: Node, scurry: PathScurry) => boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { lstatSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const onDisk = (dir) => {
|
|
4
|
+
try {
|
|
5
|
+
return !!lstatSync(join(dir, 'binding.gyp'), {
|
|
6
|
+
throwIfNoEntry: false,
|
|
7
|
+
})?.isFile();
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
// e.g. ENOTDIR, location is a file
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* True if the package has a root binding.gyp (implicit install). Known
|
|
16
|
+
* from the global store index, else checked on disk past the path
|
|
17
|
+
* cache, which may still hold ENOENT from before the extraction.
|
|
18
|
+
*/
|
|
19
|
+
export const hasBindingGyp = (node, scurry) => node.bindingGyp ?? onDisk(node.resolvedLocation(scurry));
|
package/dist/reify/build.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// walk the graph of added nodes, building and chmoding their bins
|
|
2
2
|
// at the end, we get back to the importers, and run their prepare
|
|
3
3
|
// script as well as install script.
|
|
4
|
-
import { join } from 'node:path';
|
|
5
4
|
import { run } from '@vltpkg/run';
|
|
6
5
|
import { graphRun } from '@vltpkg/graph-run';
|
|
7
6
|
import { nonEmptyList } from "../non-empty-list.js";
|
|
8
7
|
import { optionalFail } from "./optional-fail.js";
|
|
9
8
|
import { binChmod } from "./bin-chmod.js";
|
|
9
|
+
import { hasBindingGyp } from "./binding-gyp.js";
|
|
10
10
|
import { scriptsManifest } from "./scripts-manifest.js";
|
|
11
11
|
export const build = async (diff, packageJson, scurry, allowScriptsNodes) => {
|
|
12
12
|
const graph = diff.to;
|
|
@@ -78,10 +78,7 @@ const visit = async (packageJson, scurry, node, signal, _path) => {
|
|
|
78
78
|
// "If there is a binding.gyp file in the root of your package and you
|
|
79
79
|
// haven't defined your own install or preinstall scripts, npm will default
|
|
80
80
|
// the install command to compile using node-gyp via node-gyp rebuild"
|
|
81
|
-
const
|
|
82
|
-
.lstatSync(join(node.resolvedLocation(scurry), 'binding.gyp'))
|
|
83
|
-
?.isFile() ?? false;
|
|
84
|
-
const hasImplicitInstall = hasBindingGyp && !install && !preinstall;
|
|
81
|
+
const hasImplicitInstall = hasBindingGyp(node, scurry) && !install && !preinstall;
|
|
85
82
|
// if it has install script or binding.gyp (implicit install), run it
|
|
86
83
|
const runInstall = !!(install || preinstall || postinstall) || hasImplicitInstall;
|
|
87
84
|
if (runInstall) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hasBindingGyp } from "./binding-gyp.js";
|
|
2
2
|
import { scriptsManifest } from "./scripts-manifest.js";
|
|
3
3
|
/**
|
|
4
4
|
* Checks if a node needs to be built based on the conditions from build.ts:
|
|
@@ -38,10 +38,9 @@ const nodeNeedsBuild = (node, scurry, packageJson) => {
|
|
|
38
38
|
// "If there is a binding.gyp file in the root of your package and you
|
|
39
39
|
// haven't defined your own install or preinstall scripts, npm will default
|
|
40
40
|
// the install command to compile using node-gyp via node-gyp rebuild"
|
|
41
|
-
|
|
42
|
-
.
|
|
43
|
-
|
|
44
|
-
if (hasBindingGyp && !scripts.install && !scripts.preinstall)
|
|
41
|
+
if (hasBindingGyp(node, scurry) &&
|
|
42
|
+
!scripts.install &&
|
|
43
|
+
!scripts.preinstall)
|
|
45
44
|
return true;
|
|
46
45
|
// Check for prepare scripts on importers or git dependencies
|
|
47
46
|
const prepable = node.id.startsWith('git') || node.importer || !node.inVltStore();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hydrate } from '@vltpkg/dep-id';
|
|
2
2
|
import { platformCheck } from '@vltpkg/pick-manifest';
|
|
3
|
+
import { asManifest, normalizeManifest } from '@vltpkg/types';
|
|
3
4
|
import { optionalFail } from "./optional-fail.js";
|
|
4
5
|
import { removeOptionalSubgraph } from "../remove-optional-subgraph.js";
|
|
5
6
|
/**
|
|
@@ -38,22 +39,40 @@ export const extractNode = async (node, scurry, remover, options, packageInfo, d
|
|
|
38
39
|
error: new Error('Platform check failed or package deprecated'),
|
|
39
40
|
};
|
|
40
41
|
}
|
|
42
|
+
// the registry manifest can declare install scripts that the
|
|
43
|
+
// tarball's package.json, read by the global store, lacks
|
|
44
|
+
const { scripts, hasInstallScript } = manifest;
|
|
41
45
|
const extractOptions = {
|
|
42
46
|
from,
|
|
43
47
|
integrity,
|
|
44
48
|
resolved,
|
|
45
49
|
fromLockfile: node.resolvedFromLockfile,
|
|
50
|
+
installScripts: !!(hasInstallScript ||
|
|
51
|
+
scripts?.install ||
|
|
52
|
+
scripts?.preinstall ||
|
|
53
|
+
scripts?.postinstall),
|
|
54
|
+
};
|
|
55
|
+
const extracted = (r) => {
|
|
56
|
+
// Store computed integrity for git/remote deps
|
|
57
|
+
if (r.integrity && !node.integrity)
|
|
58
|
+
node.integrity = r.integrity;
|
|
59
|
+
// a global store link hands over what reify would read from disk;
|
|
60
|
+
// same result as reading it back, or left for that on failure
|
|
61
|
+
if (r.manifest && !node.manifest) {
|
|
62
|
+
try {
|
|
63
|
+
node.manifest = normalizeManifest(asManifest(JSON.parse(r.manifest)));
|
|
64
|
+
}
|
|
65
|
+
catch { }
|
|
66
|
+
}
|
|
67
|
+
if (r.bindingGyp !== undefined)
|
|
68
|
+
node.bindingGyp = r.bindingGyp;
|
|
69
|
+
return { success: true, node };
|
|
46
70
|
};
|
|
47
71
|
try {
|
|
48
72
|
await remover.rm(target);
|
|
49
73
|
if (removeOptionalFailedNode) {
|
|
50
74
|
try {
|
|
51
|
-
|
|
52
|
-
// Store computed integrity for git/remote deps
|
|
53
|
-
if (result.integrity && !node.integrity) {
|
|
54
|
-
node.integrity = result.integrity;
|
|
55
|
-
}
|
|
56
|
-
return { success: true, node };
|
|
75
|
+
return extracted(await packageInfo.extract(spec, target, extractOptions));
|
|
57
76
|
}
|
|
58
77
|
catch (error) {
|
|
59
78
|
removeOptionalFailedNode();
|
|
@@ -61,12 +80,7 @@ export const extractNode = async (node, scurry, remover, options, packageInfo, d
|
|
|
61
80
|
}
|
|
62
81
|
}
|
|
63
82
|
else {
|
|
64
|
-
|
|
65
|
-
// Store computed integrity for git/remote deps
|
|
66
|
-
if (result.integrity && !node.integrity) {
|
|
67
|
-
node.integrity = result.integrity;
|
|
68
|
-
}
|
|
69
|
-
return { success: true, node };
|
|
83
|
+
return extracted(await packageInfo.extract(spec, target, extractOptions));
|
|
70
84
|
}
|
|
71
85
|
}
|
|
72
86
|
catch (error) {
|
package/dist/reify/index.js
CHANGED
|
@@ -185,6 +185,16 @@ const reify_ = async (options, diff, remover, saveImportersPackageJson) => {
|
|
|
185
185
|
await Promise.all(rmActions);
|
|
186
186
|
// updates package.json files if anything was added / removed
|
|
187
187
|
saveImportersPackageJson?.();
|
|
188
|
+
// an integrity first learned while extracting -- a git or remote dep,
|
|
189
|
+
// or a registry tarball verified against the digest the registry sent
|
|
190
|
+
// with it -- was not known when lfData was captured above. pin it, so
|
|
191
|
+
// the next install checks the same bytes.
|
|
192
|
+
for (const node of diff.nodes.add) {
|
|
193
|
+
const lfNode = lfData.nodes[node.id];
|
|
194
|
+
if (lfNode && node.integrity && !lfNode[2]) {
|
|
195
|
+
lfNode[2] = node.integrity;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
188
198
|
// write the ideal graph data to the lockfile
|
|
189
199
|
saveData(lfData, scurry.resolve('vlt-lock.json'), false);
|
|
190
200
|
// update the store config reference if a config file was used
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/graph",
|
|
3
3
|
"description": "A library that helps understanding & expressing what happens on an install",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -13,26 +13,26 @@
|
|
|
13
13
|
"url": "http://vlt.sh"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@vltpkg/cmd-shim": "1.
|
|
17
|
-
"@vltpkg/dep-id": "1.
|
|
18
|
-
"@vltpkg/dss-breadcrumb": "1.
|
|
19
|
-
"@vltpkg/error-cause": "1.
|
|
20
|
-
"@vltpkg/fast-split": "1.
|
|
21
|
-
"@vltpkg/graph-run": "1.
|
|
22
|
-
"@vltpkg/init": "1.
|
|
23
|
-
"@vltpkg/output": "1.
|
|
24
|
-
"@vltpkg/package-info": "1.
|
|
25
|
-
"@vltpkg/package-json": "1.
|
|
26
|
-
"@vltpkg/pick-manifest": "1.
|
|
27
|
-
"@vltpkg/query": "1.
|
|
28
|
-
"@vltpkg/rollback-remove": "1.
|
|
29
|
-
"@vltpkg/run": "1.
|
|
30
|
-
"@vltpkg/satisfies": "1.
|
|
31
|
-
"@vltpkg/security-archive": "1.
|
|
32
|
-
"@vltpkg/spec": "1.
|
|
33
|
-
"@vltpkg/types": "1.
|
|
34
|
-
"@vltpkg/vlt-json": "1.
|
|
35
|
-
"@vltpkg/workspaces": "1.
|
|
16
|
+
"@vltpkg/cmd-shim": "1.3.0",
|
|
17
|
+
"@vltpkg/dep-id": "1.3.0",
|
|
18
|
+
"@vltpkg/dss-breadcrumb": "1.3.0",
|
|
19
|
+
"@vltpkg/error-cause": "1.3.0",
|
|
20
|
+
"@vltpkg/fast-split": "1.3.0",
|
|
21
|
+
"@vltpkg/graph-run": "1.3.0",
|
|
22
|
+
"@vltpkg/init": "1.3.0",
|
|
23
|
+
"@vltpkg/output": "1.3.0",
|
|
24
|
+
"@vltpkg/package-info": "1.3.0",
|
|
25
|
+
"@vltpkg/package-json": "1.3.0",
|
|
26
|
+
"@vltpkg/pick-manifest": "1.3.0",
|
|
27
|
+
"@vltpkg/query": "1.3.0",
|
|
28
|
+
"@vltpkg/rollback-remove": "1.3.0",
|
|
29
|
+
"@vltpkg/run": "1.3.0",
|
|
30
|
+
"@vltpkg/satisfies": "1.3.0",
|
|
31
|
+
"@vltpkg/security-archive": "1.3.0",
|
|
32
|
+
"@vltpkg/spec": "1.3.0",
|
|
33
|
+
"@vltpkg/types": "1.3.0",
|
|
34
|
+
"@vltpkg/vlt-json": "1.3.0",
|
|
35
|
+
"@vltpkg/workspaces": "1.3.0",
|
|
36
36
|
"path-scurry": "^2.0.1",
|
|
37
37
|
"promise-call-limit": "^3.0.2"
|
|
38
38
|
},
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@types/node": "^22.19.2",
|
|
42
42
|
"eslint": "^9.39.1",
|
|
43
43
|
"prettier": "^3.7.4",
|
|
44
|
-
"tap": "^21.
|
|
44
|
+
"tap": "^21.8.0",
|
|
45
45
|
"tar": "^7.5.2",
|
|
46
46
|
"typedoc": "~0.27.9",
|
|
47
47
|
"typescript": "5.7.3",
|