@gamecrate/cli 2.2.1 → 2.3.1
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/gamecrate.js +34 -19
- package/dist/lib.js +5 -2
- package/dist/types/launch/image.d.ts +1 -2
- package/dist/types/launch/updates.d.ts +1 -2
- package/package.json +1 -1
package/dist/gamecrate.js
CHANGED
|
@@ -2449,7 +2449,10 @@ function repeats(entries, key) {
|
|
|
2449
2449
|
});
|
|
2450
2450
|
return found;
|
|
2451
2451
|
}
|
|
2452
|
-
|
|
2452
|
+
function describe(value) {
|
|
2453
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
2454
|
+
}
|
|
2455
|
+
var TAG_COMPONENT = /^\w[\w.-]*$/;
|
|
2453
2456
|
function steamBuildRules(ctx) {
|
|
2454
2457
|
const push = (message, path, suggestion) => {
|
|
2455
2458
|
ctx.issues.push({
|
|
@@ -2504,7 +2507,7 @@ function steamBuildRules(ctx) {
|
|
|
2504
2507
|
const wants = depot === "windows" ? "proton" : "xvfb";
|
|
2505
2508
|
if (base === wants)
|
|
2506
2509
|
return;
|
|
2507
|
-
push(`a ${
|
|
2510
|
+
push(`a ${describe(depot)} depot cannot run on the "${base}" base`, ["variants", index, "base"], depot === "windows" ? 'set base to "proton"; it is the only base with wine' : 'set base to "xvfb", or set depot to "windows" if the image should run under wine');
|
|
2508
2511
|
});
|
|
2509
2512
|
}
|
|
2510
2513
|
var steamBuildSchema = obj({
|
|
@@ -4523,7 +4526,10 @@ function refsLink(game) {
|
|
|
4523
4526
|
}
|
|
4524
4527
|
var MARK2 = "@@gamecrate@@ ";
|
|
4525
4528
|
function extractScript(candidates, container) {
|
|
4526
|
-
const quoted = candidates.map((c) =>
|
|
4529
|
+
const quoted = candidates.map((c) => {
|
|
4530
|
+
const escaped = join11(container, c).replaceAll("'", String.raw`'\''`);
|
|
4531
|
+
return `'${escaped}'`;
|
|
4532
|
+
});
|
|
4527
4533
|
return [
|
|
4528
4534
|
`for d in ${quoted.join(" ")}; do`,
|
|
4529
4535
|
' set -- "$d"/*.dll',
|
|
@@ -4875,7 +4881,7 @@ async function modsAdd(args, ctx) {
|
|
|
4875
4881
|
const target = await resolveTarget(args, ctx, game);
|
|
4876
4882
|
const pins = await discover(source, gameConfig, requirePlugin(ctx.plugins, game), ctx);
|
|
4877
4883
|
if (pins.length === 0) {
|
|
4878
|
-
throw new GamecrateError(`no mod manifest at ${
|
|
4884
|
+
throw new GamecrateError(`no mod manifest at ${describe2(source)}`, Exit.Resolution, `looked for ${gameConfig.manifest.file}`);
|
|
4879
4885
|
}
|
|
4880
4886
|
const where = new Map;
|
|
4881
4887
|
for (const pin of pins) {
|
|
@@ -4888,7 +4894,7 @@ async function modsAdd(args, ctx) {
|
|
|
4888
4894
|
const lines = [...where.entries()].filter(([, at]) => at.length > 1);
|
|
4889
4895
|
const rows = lines.map(([id, at]) => ` ${id}: ${at.join(", ")}`).join(`
|
|
4890
4896
|
`);
|
|
4891
|
-
throw new GamecrateError(`${twice.length} mod id(s) are declared by more than one directory in ${
|
|
4897
|
+
throw new GamecrateError(`${twice.length} mod id(s) are declared by more than one directory in ${describe2(source)}`, Exit.Config, `${rows}
|
|
4892
4898
|
pin one of them with --subdir`);
|
|
4893
4899
|
}
|
|
4894
4900
|
const clashes = pins.filter((pin) => existingKey(target.existing, pin.id) !== undefined);
|
|
@@ -5018,7 +5024,7 @@ async function syncWorkshop(ctx, name, pins) {
|
|
|
5018
5024
|
function gitPin(url, entry) {
|
|
5019
5025
|
return { url, ...entry.subdir === undefined ? {} : { subdir: entry.subdir } };
|
|
5020
5026
|
}
|
|
5021
|
-
function
|
|
5027
|
+
function describe2(source) {
|
|
5022
5028
|
if (source.kind === "path")
|
|
5023
5029
|
return source.value;
|
|
5024
5030
|
if (source.kind === "workshop")
|
|
@@ -5297,7 +5303,8 @@ function dockerRun(mounts, script) {
|
|
|
5297
5303
|
];
|
|
5298
5304
|
}
|
|
5299
5305
|
function shq(value) {
|
|
5300
|
-
|
|
5306
|
+
const escaped = value.replaceAll("'", String.raw`'\''`);
|
|
5307
|
+
return `'${escaped}'`;
|
|
5301
5308
|
}
|
|
5302
5309
|
function craneArgv(mounts, ref, lines) {
|
|
5303
5310
|
const creds = ref === null ? null : registryCreds();
|
|
@@ -5348,7 +5355,7 @@ async function runLive(argv, what) {
|
|
|
5348
5355
|
}
|
|
5349
5356
|
function lastLine(text) {
|
|
5350
5357
|
return text.split(`
|
|
5351
|
-
`).map((l) => l.trim()).
|
|
5358
|
+
`).map((l) => l.trim()).findLast((l) => l !== "") ?? "no output";
|
|
5352
5359
|
}
|
|
5353
5360
|
async function craneAppend(opts) {
|
|
5354
5361
|
for (const p of opts.include) {
|
|
@@ -5532,7 +5539,7 @@ function sanitizeVersion(raw, fallback) {
|
|
|
5532
5539
|
}
|
|
5533
5540
|
function versionPrefixes(version) {
|
|
5534
5541
|
const parts = version.split(".");
|
|
5535
|
-
if (parts.length < 2 || parts.
|
|
5542
|
+
if (parts.length < 2 || parts.includes(""))
|
|
5536
5543
|
return [];
|
|
5537
5544
|
return parts.slice(0, -1).map((_, i) => parts.slice(0, i + 1).join("."));
|
|
5538
5545
|
}
|
|
@@ -5678,6 +5685,10 @@ async function download(input, opts, ctx, say) {
|
|
|
5678
5685
|
}
|
|
5679
5686
|
return (await pending).dir;
|
|
5680
5687
|
}
|
|
5688
|
+
function loadOutput(stdout, stderr) {
|
|
5689
|
+
return `${stdout}
|
|
5690
|
+
${stderr}`.trim() || "(no output)";
|
|
5691
|
+
}
|
|
5681
5692
|
async function resolvedBase(base, platform) {
|
|
5682
5693
|
if (base.includes("@sha256:"))
|
|
5683
5694
|
return base;
|
|
@@ -5703,7 +5714,7 @@ async function readGate(ref, opts) {
|
|
|
5703
5714
|
reads.push(await craneLabels(ref));
|
|
5704
5715
|
if (opts.load)
|
|
5705
5716
|
reads.push(await inspectLabels(ref));
|
|
5706
|
-
if (reads.
|
|
5717
|
+
if (reads.includes(null))
|
|
5707
5718
|
return { present: false, buildid: null };
|
|
5708
5719
|
const ids = reads.map((labels) => labels?.["steam.buildid"] ?? null);
|
|
5709
5720
|
return { present: reads.length > 0, buildid: ids.every((id) => id === ids[0]) ? ids[0] ?? null : null };
|
|
@@ -5721,8 +5732,7 @@ async function inspectLabels(ref) {
|
|
|
5721
5732
|
async function dockerLoad(tar, ref) {
|
|
5722
5733
|
const { code, stdout, stderr } = await capture(["docker", "load", "-i", tar]);
|
|
5723
5734
|
if (code !== 0 || !stdout.includes(`Loaded image: ${ref}`)) {
|
|
5724
|
-
throw new GamecrateError(`docker load failed for ${tar}`, Exit.Environment, `expected "Loaded image: ${ref}", got: ${
|
|
5725
|
-
${stderr}`.trim() || "(no output)"}`);
|
|
5735
|
+
throw new GamecrateError(`docker load failed for ${tar}`, Exit.Environment, `expected "Loaded image: ${ref}", got: ${loadOutput(stdout, stderr)}`);
|
|
5726
5736
|
}
|
|
5727
5737
|
}
|
|
5728
5738
|
async function dockerLabel(ref, labels) {
|
|
@@ -5997,7 +6007,10 @@ ${cases}
|
|
|
5997
6007
|
complete -F ${fn} ${NAME}
|
|
5998
6008
|
`;
|
|
5999
6009
|
}
|
|
6000
|
-
const zshVerbs = SUBCOMMANDS.map((s) =>
|
|
6010
|
+
const zshVerbs = SUBCOMMANDS.map((s) => {
|
|
6011
|
+
const summary = s.summary.replaceAll("'", String.raw`'\''`);
|
|
6012
|
+
return ` '${s.name}:${summary}'`;
|
|
6013
|
+
}).join(`
|
|
6001
6014
|
`);
|
|
6002
6015
|
const zshFlags = options.map((f) => {
|
|
6003
6016
|
const desc = f.description.replaceAll("'", String.raw`'\''`).replaceAll(/[[\]:]/g, "");
|
|
@@ -7585,7 +7598,7 @@ function published2(value) {
|
|
|
7585
7598
|
}
|
|
7586
7599
|
|
|
7587
7600
|
// src/index.ts
|
|
7588
|
-
var VERSION = "2.
|
|
7601
|
+
var VERSION = "2.3.1";
|
|
7589
7602
|
async function main(argv) {
|
|
7590
7603
|
const supervised = supervisedDir(argv);
|
|
7591
7604
|
try {
|
|
@@ -7866,8 +7879,10 @@ async function rebuiltForUpdate(plan, config, args) {
|
|
|
7866
7879
|
cwd: process.cwd(),
|
|
7867
7880
|
configFile: await globalConfigPath(),
|
|
7868
7881
|
ask: async (question) => {
|
|
7869
|
-
if (args.yes)
|
|
7870
|
-
|
|
7882
|
+
if (args.yes) {
|
|
7883
|
+
rebuilt = true;
|
|
7884
|
+
return true;
|
|
7885
|
+
}
|
|
7871
7886
|
if (process.stdin.isTTY !== true || args.json) {
|
|
7872
7887
|
warn("no terminal to ask, so the launch keeps the current image");
|
|
7873
7888
|
return false;
|
|
@@ -8011,7 +8026,7 @@ async function copyOutLogs(plan) {
|
|
|
8011
8026
|
try {
|
|
8012
8027
|
await cp(source, target, { recursive: true, force: true });
|
|
8013
8028
|
} catch (error) {
|
|
8014
|
-
warn(`could not copy ${source}: ${
|
|
8029
|
+
warn(`could not copy ${source}: ${describe3(error)}`);
|
|
8015
8030
|
}
|
|
8016
8031
|
}
|
|
8017
8032
|
async function mods(args, config, plugins, defaults) {
|
|
@@ -8486,7 +8501,7 @@ async function spawnStatus(argv, interactive = false) {
|
|
|
8486
8501
|
const proc = spawnArgv(argv, [interactive ? "inherit" : "ignore", "inherit", "inherit"]);
|
|
8487
8502
|
return exited(proc);
|
|
8488
8503
|
}
|
|
8489
|
-
function
|
|
8504
|
+
function describe3(error) {
|
|
8490
8505
|
return error instanceof Error ? error.message : String(error);
|
|
8491
8506
|
}
|
|
8492
8507
|
function reportFatal(error) {
|
|
@@ -8498,7 +8513,7 @@ function reportFatal(error) {
|
|
|
8498
8513
|
`);
|
|
8499
8514
|
return error.code;
|
|
8500
8515
|
}
|
|
8501
|
-
process.stderr.write(`gamecrate: ${
|
|
8516
|
+
process.stderr.write(`gamecrate: ${describe3(error)}
|
|
8502
8517
|
`);
|
|
8503
8518
|
return Exit.GameFailed;
|
|
8504
8519
|
}
|
package/dist/lib.js
CHANGED
|
@@ -242,7 +242,10 @@ function repeats(entries, key) {
|
|
|
242
242
|
});
|
|
243
243
|
return found;
|
|
244
244
|
}
|
|
245
|
-
|
|
245
|
+
function describe(value) {
|
|
246
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
247
|
+
}
|
|
248
|
+
var TAG_COMPONENT = /^\w[\w.-]*$/;
|
|
246
249
|
function steamBuildRules(ctx) {
|
|
247
250
|
const push = (message, path, suggestion) => {
|
|
248
251
|
ctx.issues.push({
|
|
@@ -297,7 +300,7 @@ function steamBuildRules(ctx) {
|
|
|
297
300
|
const wants = depot === "windows" ? "proton" : "xvfb";
|
|
298
301
|
if (base === wants)
|
|
299
302
|
return;
|
|
300
|
-
push(`a ${
|
|
303
|
+
push(`a ${describe(depot)} depot cannot run on the "${base}" base`, ["variants", index, "base"], depot === "windows" ? 'set base to "proton"; it is the only base with wine' : 'set base to "xvfb", or set depot to "windows" if the image should run under wine');
|
|
301
304
|
});
|
|
302
305
|
}
|
|
303
306
|
var steamBuildSchema = obj({
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ImageLaunch } from '../docker/spec';
|
|
2
|
-
import type { ModeName, Problem } from '../types';
|
|
3
|
-
import type { GameConfig } from '../types';
|
|
2
|
+
import type { GameConfig, ModeName, Problem } from '../types';
|
|
4
3
|
/** What an image says about itself. Every field is null for an image gamecrate did not build. */
|
|
5
4
|
export interface ImageFacts {
|
|
6
5
|
present: boolean;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ImageFacts } from './image';
|
|
2
|
-
import type { ParsedArgs, RootConfig } from '../types';
|
|
3
|
-
import type { UpdateCheckSpec } from '../types';
|
|
2
|
+
import type { ParsedArgs, RootConfig, UpdateCheckSpec } from '../types';
|
|
4
3
|
export interface CheckInput {
|
|
5
4
|
facts: ImageFacts;
|
|
6
5
|
spec: UpdateCheckSpec | undefined;
|