@gamecrate/cli 2.0.0 → 2.1.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/gamecrate.js CHANGED
@@ -4496,8 +4496,8 @@ import { join as join15 } from "node:path";
4496
4496
 
4497
4497
  // src/image/base.ts
4498
4498
  var RUNTIME_BASE = {
4499
- xvfb: "ghcr.io/rimworks/gamecrate/runtime-base@sha256:bb56228089823908bc3f6452ba3eb10f35f395813b2358758080452201ee4792",
4500
- proton: "ghcr.io/rimworks/gamecrate/runtime-base-proton@sha256:55ee5e995a88207074ac455fc1932adb57239da66536bed26041436cb7f44fea"
4499
+ xvfb: "ghcr.io/rimworks/gamecrate/runtime-base:1",
4500
+ proton: "ghcr.io/rimworks/gamecrate/runtime-base-proton:1"
4501
4501
  };
4502
4502
  function resolveBase(kind, override) {
4503
4503
  if (kind === "none")
@@ -4722,6 +4722,12 @@ async function craneMutateLabels(ref, labels) {
4722
4722
  args.push("-t", ref);
4723
4723
  await runOnce(craneArgv([], ref, [args]), `crane mutate ${ref}`);
4724
4724
  }
4725
+ async function craneDigest(ref, platform) {
4726
+ const argv = craneArgv([], ref, [["crane", "digest", "--platform", platform, ref]]);
4727
+ const { code, stdout } = await capture(argv);
4728
+ const digest = stdout.trim();
4729
+ return code === 0 && digest.startsWith("sha256:") ? digest : null;
4730
+ }
4725
4731
  async function craneLabels(ref) {
4726
4732
  const { code, stdout } = await capture(craneArgv([], ref, [["crane", "config", ref]]));
4727
4733
  if (code !== 0)
@@ -4922,6 +4928,7 @@ async function cell(input, opts, ctx) {
4922
4928
  mkdirSync4(layers, { recursive: true });
4923
4929
  const tar = join15(layers, `${branch.name}-${variant.name}-${version}.tar`);
4924
4930
  const base = resolveBase(variant.base, opts.baseOverride);
4931
+ const baseDigest = base === null ? null : await resolvedBase(base, opts.platform);
4925
4932
  const versioned = `${input.image}:${tags[0]}`;
4926
4933
  try {
4927
4934
  say(`appending onto ${base ?? "scratch"}`);
@@ -4937,14 +4944,14 @@ async function cell(input, opts, ctx) {
4937
4944
  if (opts.push) {
4938
4945
  say(`pushing ${versioned}`);
4939
4946
  await cranePush(tar, versioned);
4940
- await craneMutateLabels(versioned, labelsFor(input, ctx, base));
4947
+ await craneMutateLabels(versioned, labelsFor(input, ctx, baseDigest));
4941
4948
  for (const tag of tags.slice(1))
4942
4949
  await craneTag(versioned, tag);
4943
4950
  }
4944
4951
  if (opts.load && base !== null) {
4945
4952
  say(`loading ${versioned}`);
4946
4953
  await dockerLoad(tar, versioned);
4947
- await dockerLabel(versioned, labelsFor(input, ctx, base));
4954
+ await dockerLabel(versioned, labelsFor(input, ctx, baseDigest));
4948
4955
  for (const tag of tags.slice(1))
4949
4956
  await dockerTag(versioned, `${input.image}:${tag}`);
4950
4957
  }
@@ -4975,6 +4982,12 @@ async function download(input, opts, ctx, say) {
4975
4982
  }
4976
4983
  return (await pending).dir;
4977
4984
  }
4985
+ async function resolvedBase(base, platform) {
4986
+ if (base.includes("@sha256:"))
4987
+ return base;
4988
+ const digest = await craneDigest(base, platform);
4989
+ return digest === null ? base : `${base.split(":")[0]}@${digest}`;
4990
+ }
4978
4991
  function labelsFor(input, ctx, base) {
4979
4992
  const labels = {
4980
4993
  "gamecrate.variant": ctx.variant.name,
@@ -7480,7 +7493,7 @@ function published2(value) {
7480
7493
  }
7481
7494
 
7482
7495
  // src/index.ts
7483
- var VERSION = "2.0.0";
7496
+ var VERSION = "2.1.0";
7484
7497
  async function main(argv) {
7485
7498
  const supervised = supervisedDir(argv);
7486
7499
  try {
@@ -1,7 +1,7 @@
1
1
  export type BaseKind = 'xvfb' | 'proton' | 'none';
2
2
  /**
3
- * Pinned by digest, never by tag: a rebuilt base would otherwise change under released code.
4
- * These are the linux/amd64 manifests, not the index a push reports. See landmines.md.
3
+ * A major tag, so an apt fix in a base reaches a released cli without a new release. Each built
4
+ * image records the digest this resolved to, which is what makes that safe. See landmines.md.
5
5
  */
6
6
  export declare const RUNTIME_BASE: Readonly<Record<'xvfb' | 'proton', string>>;
7
7
  /**
@@ -23,5 +23,10 @@ export declare function cranePush(tar: string, ref: string): Promise<void>;
23
23
  /** Runs after the push, never before. A moving tag only moves once the real tag is there. */
24
24
  export declare function craneTag(ref: string, tag: string): Promise<void>;
25
25
  export declare function craneMutateLabels(ref: string, labels: Record<string, string>): Promise<void>;
26
+ /**
27
+ * The platform manifest a tag resolves to, so an image records the base it was built on rather
28
+ * than the moving tag. Never the index digest: that is not what a runtime pulls.
29
+ */
30
+ export declare function craneDigest(ref: string, platform: string): Promise<string | null>;
26
31
  /** null when the image or its config cannot be read. An empty record means no labels. */
27
32
  export declare function craneLabels(ref: string): Promise<Record<string, string> | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gamecrate/cli",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Run a modded game in a container, with mods resolved from your local checkouts.",
5
5
  "license": "MIT",
6
6
  "type": "module",