@vltpkg/cli-sdk 1.1.1 → 1.2.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/commands/cache.d.ts +27 -3
- package/dist/commands/cache.js +127 -2
- package/dist/commands/install/reporter.js +3 -1
- package/dist/commands/view.js +1 -1
- package/dist/config/definition.d.ts +9 -0
- package/dist/config/definition.js +33 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +24 -1
- package/dist/custom-help.js +1 -1
- package/dist/print-err.js +7 -3
- package/dist/verbose-log.js +1 -0
- package/package.json +27 -26
package/dist/commands/cache.d.ts
CHANGED
|
@@ -4,12 +4,20 @@ import type { CommandFn, CommandUsage } from '../index.ts';
|
|
|
4
4
|
import type { ViewOptions, Views } from '../view.ts';
|
|
5
5
|
import { ViewClass } from '../view.ts';
|
|
6
6
|
export type CacheMap = Record<string, ReturnType<CacheEntry['toJSON']>>;
|
|
7
|
+
/** `verify`, `prune-store`: entries checked, and why each was removed */
|
|
8
|
+
export type StoreResult = {
|
|
9
|
+
checked: number;
|
|
10
|
+
removed: Record<string, string>;
|
|
11
|
+
/** `verify <spec>`: specs not in the global store */
|
|
12
|
+
missing?: string[];
|
|
13
|
+
};
|
|
14
|
+
export type CacheResult = void | CacheMap | StoreResult;
|
|
7
15
|
export type CacheSubcommands = keyof (typeof usageDef)['subcommands'];
|
|
8
16
|
export declare class CacheView extends ViewClass {
|
|
9
17
|
constructor(options: ViewOptions, conf: LoadedConfig);
|
|
10
18
|
stdout(...args: unknown[]): void;
|
|
11
19
|
}
|
|
12
|
-
export declare const views: Views<
|
|
20
|
+
export declare const views: Views<CacheResult>;
|
|
13
21
|
declare const usageDef: {
|
|
14
22
|
readonly command: "cache";
|
|
15
23
|
readonly usage: "<command> [flags]";
|
|
@@ -37,12 +45,20 @@ declare const usageDef: {
|
|
|
37
45
|
};
|
|
38
46
|
readonly 'delete-before': {
|
|
39
47
|
readonly usage: "<date>";
|
|
40
|
-
readonly description: "Purge all cache items from before a given date. Date can be\n provided in any format that JavaScript can parse.";
|
|
48
|
+
readonly description: "Purge all cache items from before a given date, and\n global store entries written before it. Date can be\n provided in any format that JavaScript can parse.";
|
|
41
49
|
};
|
|
42
50
|
readonly 'delete-all': {
|
|
43
51
|
readonly usage: "";
|
|
44
52
|
readonly description: "Delete the entire cache folder to make vlt slower.";
|
|
45
53
|
};
|
|
54
|
+
readonly verify: {
|
|
55
|
+
readonly usage: ["<package-spec> [<package-spec>...]", "--all"];
|
|
56
|
+
readonly description: "Check global store entries against their cached\n tarballs (file list, contents, exec bits) and remove\n any that differ or have no cached tarball, e.g. after\n a file in `node_modules` was edited in place.";
|
|
57
|
+
};
|
|
58
|
+
readonly 'prune-store': {
|
|
59
|
+
readonly usage: "";
|
|
60
|
+
readonly description: "Remove global store entries that no `node_modules`\n folder links to. Entries ever copied from (install\n scripts, `store-linker=copy`, a cache on another\n drive) stay: copies do not show use.";
|
|
61
|
+
};
|
|
46
62
|
};
|
|
47
63
|
readonly examples: {
|
|
48
64
|
readonly 'vlt cache ls https://registry.npmjs.org/typescript': {
|
|
@@ -57,9 +73,17 @@ declare const usageDef: {
|
|
|
57
73
|
readonly 'vlt cache delete-before 2025-01-01': {
|
|
58
74
|
readonly description: "Delete all entries created before Jan 1, 2025";
|
|
59
75
|
};
|
|
76
|
+
readonly 'verify --all': {
|
|
77
|
+
readonly description: "Check every global store entry";
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
readonly options: {
|
|
81
|
+
readonly all: {
|
|
82
|
+
readonly description: "With `verify`, check every global store entry.";
|
|
83
|
+
};
|
|
60
84
|
};
|
|
61
85
|
};
|
|
62
86
|
export declare const needsRegistry = true;
|
|
63
87
|
export declare const usage: CommandUsage;
|
|
64
|
-
export declare const command: CommandFn<
|
|
88
|
+
export declare const command: CommandFn<CacheResult>;
|
|
65
89
|
export {};
|
package/dist/commands/cache.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { error } from '@vltpkg/error-cause';
|
|
2
2
|
import { CacheEntry, assertOk } from '@vltpkg/registry-client';
|
|
3
3
|
import { Spec } from '@vltpkg/spec';
|
|
4
|
+
import { removeStoreEntry, storeEntryCopied, storeEntryLinked, storeEntryNames, storeEntryTime, verifyStoreEntry, } from '@vltpkg/tar/store-entry';
|
|
5
|
+
import { readStoreIndex } from '@vltpkg/tar/store-index';
|
|
6
|
+
import { integrityHex } from '@vltpkg/types';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
4
8
|
import { mkdir, rm } from 'node:fs/promises';
|
|
9
|
+
import { resolve } from 'node:path';
|
|
5
10
|
import prettyBytes from 'pretty-bytes';
|
|
6
11
|
import { commandUsage } from "../config/usage.js";
|
|
7
12
|
import { stderr, stdout } from "../output.js";
|
|
@@ -55,13 +60,28 @@ const usageDef = {
|
|
|
55
60
|
},
|
|
56
61
|
'delete-before': {
|
|
57
62
|
usage: '<date>',
|
|
58
|
-
description: `Purge all cache items from before a given date
|
|
63
|
+
description: `Purge all cache items from before a given date, and
|
|
64
|
+
global store entries written before it. Date can be
|
|
59
65
|
provided in any format that JavaScript can parse.`,
|
|
60
66
|
},
|
|
61
67
|
'delete-all': {
|
|
62
68
|
usage: '',
|
|
63
69
|
description: `Delete the entire cache folder to make vlt slower.`,
|
|
64
70
|
},
|
|
71
|
+
verify: {
|
|
72
|
+
usage: ['<package-spec> [<package-spec>...]', '--all'],
|
|
73
|
+
description: `Check global store entries against their cached
|
|
74
|
+
tarballs (file list, contents, exec bits) and remove
|
|
75
|
+
any that differ or have no cached tarball, e.g. after
|
|
76
|
+
a file in \`node_modules\` was edited in place.`,
|
|
77
|
+
},
|
|
78
|
+
'prune-store': {
|
|
79
|
+
usage: '',
|
|
80
|
+
description: `Remove global store entries that no \`node_modules\`
|
|
81
|
+
folder links to. Entries ever copied from (install
|
|
82
|
+
scripts, \`store-linker=copy\`, a cache on another
|
|
83
|
+
drive) stay: copies do not show use.`,
|
|
84
|
+
},
|
|
65
85
|
},
|
|
66
86
|
examples: {
|
|
67
87
|
'vlt cache ls https://registry.npmjs.org/typescript': {
|
|
@@ -78,6 +98,14 @@ const usageDef = {
|
|
|
78
98
|
'vlt cache delete-before 2025-01-01': {
|
|
79
99
|
description: 'Delete all entries created before Jan 1, 2025',
|
|
80
100
|
},
|
|
101
|
+
'verify --all': {
|
|
102
|
+
description: 'Check every global store entry',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
options: {
|
|
106
|
+
all: {
|
|
107
|
+
description: 'With `verify`, check every global store entry.',
|
|
108
|
+
},
|
|
81
109
|
},
|
|
82
110
|
};
|
|
83
111
|
export const needsRegistry = true;
|
|
@@ -99,6 +127,10 @@ export const command = async (conf) => {
|
|
|
99
127
|
return deleteBefore(conf, args, view);
|
|
100
128
|
case 'delete-all':
|
|
101
129
|
return deleteAll(conf, args, view);
|
|
130
|
+
case 'verify':
|
|
131
|
+
return verify(conf, args, view);
|
|
132
|
+
case 'prune-store':
|
|
133
|
+
return pruneStore(conf, args, view);
|
|
102
134
|
default: {
|
|
103
135
|
throw error('Unrecognized cache command', {
|
|
104
136
|
code: 'EUSAGE',
|
|
@@ -212,7 +244,18 @@ const deleteBefore = async (conf, args, view) => {
|
|
|
212
244
|
found: before,
|
|
213
245
|
});
|
|
214
246
|
}
|
|
215
|
-
|
|
247
|
+
const map = await deleteEntries(conf, [], entry => !!entry.date && entry.date < before, view);
|
|
248
|
+
const { storeRoot } = conf.options;
|
|
249
|
+
let count = 0;
|
|
250
|
+
for (const hex of storeEntryNames(storeRoot)) {
|
|
251
|
+
const entry = resolve(storeRoot, hex);
|
|
252
|
+
if (storeEntryTime(entry) < before.getTime()) {
|
|
253
|
+
removeStoreEntry(entry);
|
|
254
|
+
count++;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
view?.stdout(`Removed ${entries(count)}`);
|
|
258
|
+
return map;
|
|
216
259
|
};
|
|
217
260
|
const deleteKeys = async (conf, keys, view) => {
|
|
218
261
|
if (!keys.length) {
|
|
@@ -225,9 +268,91 @@ const deleteKeys = async (conf, keys, view) => {
|
|
|
225
268
|
const deleteAll = async (conf, _, view) => {
|
|
226
269
|
const { cache } = await conf.options.packageInfo.getRegistryClient();
|
|
227
270
|
await rm(cache.path(), { recursive: true, force: true });
|
|
271
|
+
// every global store layout version, and a store root set elsewhere
|
|
272
|
+
const rf = { recursive: true, force: true };
|
|
273
|
+
await rm(resolve(conf.options.cache, 'store'), rf);
|
|
274
|
+
if (cache.store)
|
|
275
|
+
await rm(cache.store, rf);
|
|
228
276
|
await mkdir(cache.path(), { recursive: true });
|
|
229
277
|
view?.stdout('Deleted all cache entries.');
|
|
230
278
|
};
|
|
279
|
+
const entries = (n) => `${n} global store entr${n === 1 ? 'y' : 'ies'}`;
|
|
280
|
+
/** `name@version` from the entry's sidecar, else `hex` */
|
|
281
|
+
const entryLabel = (entry, hex) => {
|
|
282
|
+
const i = readStoreIndex(entry);
|
|
283
|
+
return i?.name && i.version ? `${i.name}@${i.version}` : hex;
|
|
284
|
+
};
|
|
285
|
+
const verify = async (conf, specs, view) => {
|
|
286
|
+
const all = !!conf.values.all;
|
|
287
|
+
if (!specs.length && !all) {
|
|
288
|
+
throw error('Must provide specs to verify, or --all', {
|
|
289
|
+
code: 'EUSAGE',
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
const { packageInfo, storeRoot } = conf.options;
|
|
293
|
+
const cachePath = (await packageInfo.getRegistryClient()).cache.path();
|
|
294
|
+
const present = new Set(storeEntryNames(storeRoot));
|
|
295
|
+
const checks = [];
|
|
296
|
+
const missing = [];
|
|
297
|
+
if (all) {
|
|
298
|
+
for (const hex of present)
|
|
299
|
+
checks.push([hex, hex]);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
for (const spec of specs) {
|
|
303
|
+
const { integrity } = await packageInfo.resolve(Spec.parseArgs(spec, conf.options));
|
|
304
|
+
const hex = integrityHex(integrity);
|
|
305
|
+
if (hex && present.has(hex))
|
|
306
|
+
checks.push([spec, hex]);
|
|
307
|
+
else {
|
|
308
|
+
missing.push(spec);
|
|
309
|
+
view?.stdout('Not in the global store:', spec);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const removed = {};
|
|
314
|
+
for (const [key, hex] of checks) {
|
|
315
|
+
const entry = resolve(storeRoot, hex);
|
|
316
|
+
let tarball;
|
|
317
|
+
try {
|
|
318
|
+
tarball = CacheEntry.decode(readFileSync(resolve(cachePath, hex))).buffer();
|
|
319
|
+
}
|
|
320
|
+
catch { }
|
|
321
|
+
const reason = tarball ? verifyStoreEntry(entry, tarball) : 'no cached tarball';
|
|
322
|
+
if (reason) {
|
|
323
|
+
// read before the sidecar goes
|
|
324
|
+
const label = all ? entryLabel(entry, hex) : key;
|
|
325
|
+
removeStoreEntry(entry);
|
|
326
|
+
removed[key] = reason;
|
|
327
|
+
view?.stdout('-', label, reason);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const n = Object.keys(removed).length;
|
|
331
|
+
view?.stdout(`Checked ${entries(checks.length)}, removed ${n}`);
|
|
332
|
+
return {
|
|
333
|
+
checked: checks.length,
|
|
334
|
+
removed,
|
|
335
|
+
...(!all && { missing }),
|
|
336
|
+
};
|
|
337
|
+
};
|
|
338
|
+
const pruneStore = async (conf, _, view) => {
|
|
339
|
+
const { storeRoot } = conf.options;
|
|
340
|
+
const names = storeEntryNames(storeRoot);
|
|
341
|
+
const removed = {};
|
|
342
|
+
for (const hex of names) {
|
|
343
|
+
const entry = resolve(storeRoot, hex);
|
|
344
|
+
const index = readStoreIndex(entry);
|
|
345
|
+
if (storeEntryCopied(entry, index) ||
|
|
346
|
+
storeEntryLinked(entry, index)) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
removeStoreEntry(entry);
|
|
350
|
+
removed[hex] = 'unused';
|
|
351
|
+
}
|
|
352
|
+
const n = Object.keys(removed).length;
|
|
353
|
+
view?.stdout(`Removed ${n} of ${entries(names.length)}`);
|
|
354
|
+
return { checked: names.length, removed };
|
|
355
|
+
};
|
|
231
356
|
const add = async (conf, specs, view) => {
|
|
232
357
|
if (!specs.length) {
|
|
233
358
|
throw error('Must provide specs to add to the cache', {
|
|
@@ -38,7 +38,9 @@ const App = ({ trailer }) => {
|
|
|
38
38
|
if (state === 'start') {
|
|
39
39
|
setRequests(p => p + 1);
|
|
40
40
|
}
|
|
41
|
-
else if (state === 'cache' ||
|
|
41
|
+
else if (state === 'cache' ||
|
|
42
|
+
state === 'stale' ||
|
|
43
|
+
state === 'store') {
|
|
42
44
|
setCacheHit(p => p + 1);
|
|
43
45
|
}
|
|
44
46
|
};
|
package/dist/commands/view.js
CHANGED
|
@@ -301,7 +301,7 @@ export const command = async (conf) => {
|
|
|
301
301
|
const pic = new PackageInfoClient(conf.options);
|
|
302
302
|
// Fetch the full packument (needs time, maintainers) and resolved manifest
|
|
303
303
|
const [packument, resolvedManifest] = await Promise.all([
|
|
304
|
-
pic.packument(spec),
|
|
304
|
+
pic.packument(spec, { full: true }),
|
|
305
305
|
pic.manifest(spec),
|
|
306
306
|
]);
|
|
307
307
|
const manifest = resolvedManifest;
|
|
@@ -73,6 +73,8 @@ export declare const getCommand: (s?: string) => Commands[keyof Commands] | unde
|
|
|
73
73
|
export declare const recordFields: readonly ["git-hosts", "registries", "git-host-archives", "scoped-registries", "jsr-registries"];
|
|
74
74
|
export type RecordField = (typeof recordFields)[number];
|
|
75
75
|
export declare const isRecordField: (s: string) => s is RecordField;
|
|
76
|
+
/** Valid `store-linker` values. */
|
|
77
|
+
export declare const storeLinkers: readonly ["auto", "hardlink", "copy", "unpack"];
|
|
76
78
|
export declare const definition: import("jackspeak").Jack<{
|
|
77
79
|
color: {
|
|
78
80
|
short: string;
|
|
@@ -133,6 +135,12 @@ export declare const definition: import("jackspeak").Jack<{
|
|
|
133
135
|
description: string;
|
|
134
136
|
default: string;
|
|
135
137
|
};
|
|
138
|
+
'store-linker': {
|
|
139
|
+
hint: string;
|
|
140
|
+
description: string;
|
|
141
|
+
validOptions: readonly ["auto", "hardlink", "copy", "unpack"];
|
|
142
|
+
default: string;
|
|
143
|
+
};
|
|
136
144
|
tag: {
|
|
137
145
|
description: string;
|
|
138
146
|
default: string;
|
|
@@ -159,6 +167,7 @@ export declare const definition: import("jackspeak").Jack<{
|
|
|
159
167
|
};
|
|
160
168
|
} & {
|
|
161
169
|
cache: import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
|
|
170
|
+
'store-linker': import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
|
|
162
171
|
tag: import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
|
|
163
172
|
before: import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
|
|
164
173
|
os: import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
|
|
@@ -109,6 +109,13 @@ export const recordFields = [
|
|
|
109
109
|
'jsr-registries',
|
|
110
110
|
];
|
|
111
111
|
export const isRecordField = (s) => recordFields.includes(s);
|
|
112
|
+
/** Valid `store-linker` values. */
|
|
113
|
+
export const storeLinkers = [
|
|
114
|
+
'auto',
|
|
115
|
+
'hardlink',
|
|
116
|
+
'copy',
|
|
117
|
+
'unpack',
|
|
118
|
+
];
|
|
112
119
|
const j = jack({
|
|
113
120
|
envPrefix: 'VLT',
|
|
114
121
|
allowPositionals: true,
|
|
@@ -308,6 +315,32 @@ export const definition = j
|
|
|
308
315
|
`,
|
|
309
316
|
default: cacheDir,
|
|
310
317
|
},
|
|
318
|
+
'store-linker': {
|
|
319
|
+
hint: 'auto | hardlink | copy | unpack',
|
|
320
|
+
description: `How packages are placed in \`node_modules\`. Every
|
|
321
|
+
linker but \`unpack\` fills a global store under
|
|
322
|
+
\`cache\` in the background, then places packages
|
|
323
|
+
from it.
|
|
324
|
+
|
|
325
|
+
- auto: Default. On Linux, hardlink from the global
|
|
326
|
+
store, copying any file that cannot be linked.
|
|
327
|
+
Elsewhere, same as \`unpack\`: a hardlink is the
|
|
328
|
+
slowest way to place a file on APFS, so macOS and
|
|
329
|
+
Windows unpack by default.
|
|
330
|
+
- hardlink: Hardlink from the global store on every
|
|
331
|
+
platform.
|
|
332
|
+
- copy: Copy from the global store. Use this when
|
|
333
|
+
editing files in \`node_modules\` in place, since
|
|
334
|
+
a hardlink shares its content with every project.
|
|
335
|
+
- unpack: Unpack each package tarball, skipping the
|
|
336
|
+
global store.
|
|
337
|
+
|
|
338
|
+
Packages with install scripts are always copied.
|
|
339
|
+
An invalid \`VLT_STORE_LINKER\` warns and uses
|
|
340
|
+
\`unpack\`.`,
|
|
341
|
+
validOptions: storeLinkers,
|
|
342
|
+
default: 'auto',
|
|
343
|
+
},
|
|
311
344
|
tag: {
|
|
312
345
|
description: `Default \`dist-tag\` to install or publish`,
|
|
313
346
|
default: 'latest',
|
package/dist/config/index.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ export type ConfigOptions = ConfigOptionsNoExtras & Pick<SpecOptions, 'catalog'
|
|
|
81
81
|
packageJson: PackageJson;
|
|
82
82
|
scurry: PathScurry;
|
|
83
83
|
projectRoot: string;
|
|
84
|
+
/** global store root, under `cache` */
|
|
85
|
+
storeRoot: string;
|
|
84
86
|
monorepo?: Monorepo;
|
|
85
87
|
packageInfo: PackageInfoClient;
|
|
86
88
|
};
|
package/dist/config/index.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import { error } from '@vltpkg/error-cause';
|
|
24
24
|
import { PackageInfoClient } from '@vltpkg/package-info';
|
|
25
25
|
import { PackageJson } from '@vltpkg/package-json';
|
|
26
|
+
import { storeRoot } from '@vltpkg/registry-client/store-root';
|
|
26
27
|
import { resetCaches } from '@vltpkg/dep-id';
|
|
27
28
|
import { getOptions } from '@vltpkg/spec';
|
|
28
29
|
import { assertRecordStringString, assertRecordStringT, isObject, isRecordStringString, } from '@vltpkg/types';
|
|
@@ -31,7 +32,7 @@ import { Monorepo } from '@vltpkg/workspaces';
|
|
|
31
32
|
import { readFile, rm, writeFile } from 'node:fs/promises';
|
|
32
33
|
import { dirname } from 'node:path';
|
|
33
34
|
import { PathScurry } from 'path-scurry';
|
|
34
|
-
import { commands, definition, defaultValues, getCommand, isRecordField, recordFields, } from "./definition.js";
|
|
35
|
+
import { commands, definition, defaultValues, getCommand, isRecordField, recordFields, storeLinkers, } from "./definition.js";
|
|
35
36
|
import { merge } from "./merge.js";
|
|
36
37
|
import { cloneLayer, mergeLayers } from "./merge-layers.js";
|
|
37
38
|
export { commands, definition, isRecordField, recordFields, };
|
|
@@ -92,6 +93,7 @@ export const recordsToPairs = (obj) => {
|
|
|
92
93
|
k === 'packageJson' ||
|
|
93
94
|
k === 'monorepo' ||
|
|
94
95
|
k === 'projectRoot' ||
|
|
96
|
+
k === 'storeRoot' ||
|
|
95
97
|
k === 'packageInfo'))
|
|
96
98
|
.map(([k, v]) => [
|
|
97
99
|
k,
|
|
@@ -170,6 +172,7 @@ export class Config {
|
|
|
170
172
|
const asRecords = pairsToRecords(this.parse().values);
|
|
171
173
|
const extras = {
|
|
172
174
|
projectRoot: this.projectRoot,
|
|
175
|
+
storeRoot: storeRoot(asRecords.cache),
|
|
173
176
|
scurry,
|
|
174
177
|
packageJson,
|
|
175
178
|
monorepo: Monorepo.maybeLoad(this.projectRoot, {
|
|
@@ -250,6 +253,12 @@ export class Config {
|
|
|
250
253
|
return this;
|
|
251
254
|
// Store the original args for potential reload
|
|
252
255
|
this.#originalArgs = [...args];
|
|
256
|
+
// an invalid env linker is treated as unpack
|
|
257
|
+
const badLinker = process.env.VLT_STORE_LINKER;
|
|
258
|
+
const fixLinker = badLinker !== undefined &&
|
|
259
|
+
!storeLinkers.includes(badLinker);
|
|
260
|
+
if (fixLinker)
|
|
261
|
+
process.env.VLT_STORE_LINKER = 'unpack';
|
|
253
262
|
const envKeys = Object.keys(defaultValues).filter(k => process.env[envKey(k)] !== undefined);
|
|
254
263
|
const parent = parentEnv();
|
|
255
264
|
// file layer values, before env replaces them
|
|
@@ -267,6 +276,15 @@ export class Config {
|
|
|
267
276
|
this.jack.setConfigValues(cmdPairs);
|
|
268
277
|
// ok, applied cmd-specific defaults, do rest of the parse
|
|
269
278
|
this.jack.applyDefaults(p);
|
|
279
|
+
// `auto` only hardlinks from the global store on linux: on APFS a
|
|
280
|
+
// hardlink is the slowest way to place a file, so darwin and win32
|
|
281
|
+
// unpack by default. the env layer is rewritten too, so `explicit`
|
|
282
|
+
// records the resolved value.
|
|
283
|
+
if (p.values['store-linker'] === 'auto' &&
|
|
284
|
+
process.platform !== 'linux') {
|
|
285
|
+
p.values['store-linker'] = 'unpack';
|
|
286
|
+
envValues['store-linker'] = 'unpack';
|
|
287
|
+
}
|
|
270
288
|
// what was set on the cli or env for this run. record fields hold
|
|
271
289
|
// only those pairs, env then cli, so later ones win per key.
|
|
272
290
|
const values = p.values;
|
|
@@ -318,6 +336,11 @@ export class Config {
|
|
|
318
336
|
if (p.values.verbose && p.values.loglevel === 'info') {
|
|
319
337
|
p.values.loglevel = 'verbose';
|
|
320
338
|
}
|
|
339
|
+
const { loglevel } = p.values;
|
|
340
|
+
if (fixLinker && loglevel !== 'silent' && loglevel !== 'error') {
|
|
341
|
+
// eslint-disable-next-line no-console
|
|
342
|
+
console.error(`Warning: invalid VLT_STORE_LINKER ${JSON.stringify(badLinker)}, using ${p.values['store-linker']}`);
|
|
343
|
+
}
|
|
321
344
|
/* c8 ignore start - unpossible */
|
|
322
345
|
if (!isParsed(this))
|
|
323
346
|
throw error('failed to parse config');
|
package/dist/custom-help.js
CHANGED
package/dist/print-err.js
CHANGED
|
@@ -16,7 +16,9 @@ const formatURL = (v, format) => v instanceof URL ? v.toString() : /* c8 ignore
|
|
|
16
16
|
// True when `v` overrides the default `Object.prototype.toString`, i.e.
|
|
17
17
|
// stringifying it yields something meaningful (like a `Spec` → `next@*`)
|
|
18
18
|
// rather than `[object Object]`.
|
|
19
|
-
const hasCustomToString = (v) =>
|
|
19
|
+
const hasCustomToString = (v) => typeof v === 'object' &&
|
|
20
|
+
v !== null &&
|
|
21
|
+
v.toString !== Object.prototype.toString;
|
|
20
22
|
// Render a value that has a meaningful custom `toString()` (such as a
|
|
21
23
|
// `Spec`, e.g. `next@*`) as a concise string rather than dumping its
|
|
22
24
|
// entire internal structure via util.inspect. Falls back to `format`
|
|
@@ -161,8 +163,10 @@ const printCode = (err, usage, stderr, format) => {
|
|
|
161
163
|
if (from) {
|
|
162
164
|
stderr(indent(`From: ${format(from)}`));
|
|
163
165
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
// the full response is in the error log; here only the status
|
|
167
|
+
const status = response?.statusCode;
|
|
168
|
+
if (status) {
|
|
169
|
+
stderr(indent(`Status: ${format(status)}`));
|
|
166
170
|
}
|
|
167
171
|
return { file: true };
|
|
168
172
|
}
|
package/dist/verbose-log.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/cli-sdk",
|
|
3
3
|
"description": "The source for the vlt CLI",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -14,30 +14,31 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@resvg/resvg-wasm": "^2.6.2",
|
|
17
|
-
"@vltpkg/config": "1.
|
|
18
|
-
"@vltpkg/dep-id": "1.
|
|
19
|
-
"@vltpkg/dot-prop": "1.
|
|
20
|
-
"@vltpkg/error-cause": "1.
|
|
21
|
-
"@vltpkg/git": "1.
|
|
22
|
-
"@vltpkg/graph": "1.
|
|
23
|
-
"@vltpkg/graph-run": "1.
|
|
24
|
-
"@vltpkg/init": "1.
|
|
25
|
-
"@vltpkg/output": "1.
|
|
26
|
-
"@vltpkg/package-info": "1.
|
|
27
|
-
"@vltpkg/package-json": "1.
|
|
28
|
-
"@vltpkg/promise-spawn": "1.
|
|
29
|
-
"@vltpkg/query": "1.
|
|
30
|
-
"@vltpkg/registry-client": "1.
|
|
31
|
-
"@vltpkg/rollback-remove": "1.
|
|
32
|
-
"@vltpkg/run": "1.
|
|
33
|
-
"@vltpkg/security-archive": "1.
|
|
34
|
-
"@vltpkg/spec": "1.
|
|
35
|
-
"@vltpkg/
|
|
36
|
-
"@vltpkg/
|
|
37
|
-
"@vltpkg/
|
|
38
|
-
"@vltpkg/
|
|
39
|
-
"@vltpkg/
|
|
40
|
-
"@vltpkg/
|
|
17
|
+
"@vltpkg/config": "1.2.0",
|
|
18
|
+
"@vltpkg/dep-id": "1.2.0",
|
|
19
|
+
"@vltpkg/dot-prop": "1.2.0",
|
|
20
|
+
"@vltpkg/error-cause": "1.2.0",
|
|
21
|
+
"@vltpkg/git": "1.2.0",
|
|
22
|
+
"@vltpkg/graph": "1.2.0",
|
|
23
|
+
"@vltpkg/graph-run": "1.2.0",
|
|
24
|
+
"@vltpkg/init": "1.2.0",
|
|
25
|
+
"@vltpkg/output": "1.2.0",
|
|
26
|
+
"@vltpkg/package-info": "1.2.0",
|
|
27
|
+
"@vltpkg/package-json": "1.2.0",
|
|
28
|
+
"@vltpkg/promise-spawn": "1.2.0",
|
|
29
|
+
"@vltpkg/query": "1.2.0",
|
|
30
|
+
"@vltpkg/registry-client": "1.2.0",
|
|
31
|
+
"@vltpkg/rollback-remove": "1.2.0",
|
|
32
|
+
"@vltpkg/run": "1.2.0",
|
|
33
|
+
"@vltpkg/security-archive": "1.2.0",
|
|
34
|
+
"@vltpkg/spec": "1.2.0",
|
|
35
|
+
"@vltpkg/tar": "1.2.0",
|
|
36
|
+
"@vltpkg/types": "1.2.0",
|
|
37
|
+
"@vltpkg/url-open": "1.2.0",
|
|
38
|
+
"@vltpkg/vlt-json": "1.2.0",
|
|
39
|
+
"@vltpkg/vlx": "1.2.0",
|
|
40
|
+
"@vltpkg/workspaces": "1.2.0",
|
|
41
|
+
"@vltpkg/xdg": "1.2.0",
|
|
41
42
|
"ansi-to-pre": "^1.0.6",
|
|
42
43
|
"beautiful-mermaid": "^1.1.3",
|
|
43
44
|
"chalk": "^5.6.2",
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
"@types/ssri": "^7.1.5",
|
|
67
68
|
"eslint": "^9.39.1",
|
|
68
69
|
"prettier": "^3.7.4",
|
|
69
|
-
"tap": "^21.
|
|
70
|
+
"tap": "^21.8.0",
|
|
70
71
|
"typedoc": "~0.27.9",
|
|
71
72
|
"typescript": "5.7.3",
|
|
72
73
|
"typescript-eslint": "^8.49.0"
|