@gjsify/cli 0.46.0 → 0.48.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.
Files changed (35) hide show
  1. package/dist/cli.gjs.mjs +87 -83
  2. package/lib/commands/affected-classify.js +30 -1
  3. package/lib/commands/dlx.js +7 -3
  4. package/lib/commands/foreach.js +9 -2
  5. package/lib/commands/onboard.js +11 -0
  6. package/lib/commands/publish.d.ts +41 -0
  7. package/lib/commands/publish.js +223 -10
  8. package/lib/commands/run.js +7 -2
  9. package/lib/commands/ship.js +32 -4
  10. package/lib/types/config-data.d.ts +37 -1
  11. package/lib/utils/base64.d.ts +34 -0
  12. package/lib/utils/base64.js +47 -0
  13. package/lib/utils/cli-runtime-closure.d.ts +61 -0
  14. package/lib/utils/cli-runtime-closure.js +54 -17
  15. package/lib/utils/double-dash-args.d.ts +8 -0
  16. package/lib/utils/double-dash-args.js +64 -0
  17. package/lib/utils/publish-readback.d.ts +132 -0
  18. package/lib/utils/publish-readback.js +273 -0
  19. package/lib/utils/ship/changelog.d.ts +56 -0
  20. package/lib/utils/ship/changelog.js +166 -0
  21. package/lib/utils/ship/discover.d.ts +10 -1
  22. package/lib/utils/ship/discover.js +76 -2
  23. package/lib/utils/ship/entry-interpreter.d.ts +44 -0
  24. package/lib/utils/ship/entry-interpreter.js +109 -0
  25. package/lib/utils/ship/formats.js +5 -0
  26. package/lib/utils/ship/gi-namespaces.js +175 -12
  27. package/lib/utils/ship/layout.js +8 -4
  28. package/lib/utils/ship/plan.d.ts +5 -1
  29. package/lib/utils/ship/plan.js +21 -2
  30. package/lib/utils/ship/settings.d.ts +48 -2
  31. package/lib/utils/ship/settings.js +63 -3
  32. package/lib/utils/ship/stage-manifest.d.ts +22 -3
  33. package/lib/utils/ship/stage-manifest.js +40 -13
  34. package/lib/utils/ship/types.d.ts +13 -0
  35. package/package.json +19 -19
@@ -53,8 +53,17 @@ export declare const STAGE_MANIFEST_FILE = ".gjsify-ship-stage.json";
53
53
  * the one thing the reader can do about it. That is the same shape the 3-to-4
54
54
  * paragraph describes, and at 5 the schema check above fires first and says
55
55
  * "re-run the `--stage` phase with this gjsify".
56
+ *
57
+ * 6 made an overlay entry carry EITHER `text` or `base64`, for the gzipped
58
+ * `changelog.Debian.gz` Debian Policy § 4.4 requires. That is the meaning case
59
+ * again and the sharpest one yet: a schema-5 reader demands `text` on every
60
+ * entry, so it meets a 6 stage and fails on `overlay.deb[1].text must be a
61
+ * string` — a sentence about a field, over a stage whose only problem is the
62
+ * gjsify reading it. And the inverse is worse than a bad message: a reader that
63
+ * ignored the unknown key would write an entry with no bytes, or write base64 AS
64
+ * text, and ship a `.deb` whose changelog is a wall of ASCII at exit 0.
56
65
  */
57
- export declare const STAGE_SCHEMA_VERSION = 5;
66
+ export declare const STAGE_SCHEMA_VERSION = 6;
58
67
  /** What this stage was assembled FOR, in the repo-wide `${process.platform}-${process.arch}` spelling. */
59
68
  export interface StageTarget {
60
69
  /** The layout the stage carries, in the `process.platform` spelling — `win32`, never `windows`. */
@@ -65,9 +74,19 @@ export interface StageTarget {
65
74
  export interface StageFileRecord extends StagedMode {
66
75
  bytes: number;
67
76
  }
68
- /** One pre-rendered overlay file. Text only — see {@link writeStageManifest}. */
77
+ /**
78
+ * One pre-rendered overlay file. EXACTLY ONE of `text` and `base64` is present —
79
+ * see {@link writeStageManifest} for why a file reference is still refused.
80
+ *
81
+ * `text` is preferred wherever the content is text, because the sidecar is the one
82
+ * artifact in this handoff a human reads: the whole copyright is legible in it. The
83
+ * `base64` half exists for the gzipped Debian changelog, whose bytes must be the
84
+ * bytes that ship — a stage packed on another host cannot re-compress it and get
85
+ * the same file.
86
+ */
69
87
  export interface StageOverlayFile extends StagedMode {
70
- text: string;
88
+ text?: string;
89
+ base64?: string;
71
90
  }
72
91
  export interface StageManifest {
73
92
  schema: number;
@@ -13,8 +13,10 @@
13
13
  // * no `staged` — modes come from the plan (see `stage-writer.ts`), so the
14
14
  // launcher packs 0644 and the installed `bin/<name>` is not executable.
15
15
  // * no `overlay` — the `.deb` ships no `/usr/share/doc/<pkg>/copyright`,
16
- // which Debian Policy § 12.5 requires and lintian errors on, and the
17
- // `.rpm` ships no `/usr/share/licenses/<pkg>/LICENSE`.
16
+ // which Debian Policy § 12.5 requires and lintian errors on, no
17
+ // `/usr/share/doc/<pkg>/changelog.Debian.gz`, which § 4.4 requires and
18
+ // lintian also errors on, and the `.rpm` ships no
19
+ // `/usr/share/licenses/<pkg>/LICENSE`.
18
20
  // * no `namespaces` — they are scanned from the BUILD TREE's bundle, so a
19
21
  // packing host that re-derived nothing would emit `Depends:` without
20
22
  // `gir1.2-gtk-4.0` and `gir1.2-adw-1`: the package installs on a machine
@@ -36,6 +38,7 @@
36
38
  // that is right there.
37
39
  import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
38
40
  import { join, sep } from 'node:path';
41
+ import { base64Decode, base64Encode } from '../base64.js';
39
42
  import { cliVersion } from '../publish-headers.js';
40
43
  import { FORMAT_IDS } from './formats.js';
41
44
  import { layoutForOs, LAYOUTS, LAYOUT_NAMES } from './layout.js';
@@ -93,8 +96,17 @@ export const STAGE_MANIFEST_FILE = '.gjsify-ship-stage.json';
93
96
  * the one thing the reader can do about it. That is the same shape the 3-to-4
94
97
  * paragraph describes, and at 5 the schema check above fires first and says
95
98
  * "re-run the `--stage` phase with this gjsify".
99
+ *
100
+ * 6 made an overlay entry carry EITHER `text` or `base64`, for the gzipped
101
+ * `changelog.Debian.gz` Debian Policy § 4.4 requires. That is the meaning case
102
+ * again and the sharpest one yet: a schema-5 reader demands `text` on every
103
+ * entry, so it meets a 6 stage and fails on `overlay.deb[1].text must be a
104
+ * string` — a sentence about a field, over a stage whose only problem is the
105
+ * gjsify reading it. And the inverse is worse than a bad message: a reader that
106
+ * ignored the unknown key would write an entry with no bytes, or write base64 AS
107
+ * text, and ship a `.deb` whose changelog is a wall of ASCII at exit 0.
96
108
  */
97
- export const STAGE_SCHEMA_VERSION = 5;
109
+ export const STAGE_SCHEMA_VERSION = 6;
98
110
  /**
99
111
  * The half of {@link ShipSettings} that crosses the host boundary.
100
112
  *
@@ -149,15 +161,17 @@ export function writeStageManifest(input) {
149
161
  const overlay = {};
150
162
  for (const format of input.formats) {
151
163
  overlay[format.id] = (input.overlay.get(format.id) ?? []).map((file) => {
152
- if (file.source.kind !== 'text') {
153
- // Every overlay entry `planOverlay` produces today is rendered text. A file
154
- // reference would be a build-host path, and putting one in here is how the
155
- // manifest would start naming files the packing host cannot open.
156
- throw new Error(`gjsify ship: internal error — the ${format.id} overlay entry ${file.path} is a file ` +
157
- 'reference, and a stage manifest may only carry rendered text. Render it in ' +
158
- '`planOverlay` instead.');
164
+ if (file.source.kind === 'text')
165
+ return { path: file.path, mode: file.mode, text: file.source.text };
166
+ if (file.source.kind === 'bytes') {
167
+ return { path: file.path, mode: file.mode, base64: base64Encode(file.source.data) };
159
168
  }
160
- return { path: file.path, mode: file.mode, text: file.source.text };
169
+ // A FILE reference is still refused. It would be a build-host path, and
170
+ // putting one in here is how the manifest would start naming files the
171
+ // packing host cannot open — the failure the closure exists to prevent.
172
+ throw new Error(`gjsify ship: internal error — the ${format.id} overlay entry ${file.path} is a file ` +
173
+ 'reference, and a stage manifest may only carry rendered bytes. Render it in ' +
174
+ '`planOverlay` instead.');
161
175
  });
162
176
  }
163
177
  const manifest = {
@@ -295,10 +309,21 @@ export function readStageManifest(stageDir) {
295
309
  // lintian errors on.
296
310
  manifest.overlay[id] = expectArray(overlay[id], at(`overlay.${id}`)).map((entry, index) => {
297
311
  const file = record(entry, at(`overlay.${id}[${index}]`));
312
+ const where = at(`overlay.${id}[${index}]`);
313
+ // EXACTLY ONE, checked in both directions. Neither would write an empty
314
+ // file at a path Debian policy demands content at; both would leave which
315
+ // one wins to whichever branch `overlayFiles` happens to test first.
316
+ if ((file.text === undefined) === (file.base64 === undefined)) {
317
+ throw new Error(`gjsify ship: ${where} must carry exactly one of \`text\` and \`base64\`. ` +
318
+ 'An overlay entry is either rendered text or rendered bytes; an entry with ' +
319
+ 'neither would pack an empty file at a path the format requires content at.');
320
+ }
298
321
  return {
299
322
  path: expectString(file.path, at(`overlay.${id}[${index}].path`)),
300
323
  mode: expectInteger(file.mode, at(`overlay.${id}[${index}].mode`)),
301
- text: expectString(file.text, at(`overlay.${id}[${index}].text`)),
324
+ ...(file.text === undefined
325
+ ? { base64: expectString(file.base64, at(`overlay.${id}[${index}].base64`)) }
326
+ : { text: expectString(file.text, at(`overlay.${id}[${index}].text`)) }),
302
327
  };
303
328
  });
304
329
  }
@@ -329,7 +354,9 @@ export function overlayFiles(manifest, format) {
329
354
  return (manifest.overlay[format] ?? []).map((file) => ({
330
355
  path: file.path,
331
356
  mode: file.mode,
332
- source: { kind: 'text', text: file.text },
357
+ source: file.base64 === undefined
358
+ ? { kind: 'text', text: file.text ?? '' }
359
+ : { kind: 'bytes', data: base64Decode(file.base64) },
333
360
  }));
334
361
  }
335
362
  /**
@@ -224,6 +224,17 @@ export interface FormatDescriptor {
224
224
  interpreterGap: string;
225
225
  /** Where the project's licence text goes in this format's overlay. */
226
226
  licenseDest: (binaryName: string) => string;
227
+ /**
228
+ * Where this format wants a packaging changelog, when it wants one at all.
229
+ *
230
+ * OPTIONAL, unlike {@link licenseDest}, and the asymmetry is a policy
231
+ * difference rather than an oversight: Debian Policy § 4.4 makes
232
+ * `share/doc/<package>/changelog.Debian.gz` mandatory and lintian errors
233
+ * without it, while rpm's `%doc` changelog is a convention and `rpm` says
234
+ * nothing when it is absent. A format that leaves this undefined has
235
+ * answered "this format does not require one".
236
+ */
237
+ changelogDest?: (binaryName: string) => string;
227
238
  /**
228
239
  * `debian-copyright` renders the machine-readable copyright 1.0 format
229
240
  * Debian policy asks for; `plain` copies the licence file verbatim.
@@ -420,6 +431,8 @@ export interface ShipSettings extends PackSettings {
420
431
  projectDir: string;
421
432
  /** Absolute path to the licence file, when one was found. */
422
433
  licenseFile?: string;
434
+ /** Absolute path to the project's own changelog, when one was found. */
435
+ changelogFile?: string;
423
436
  /** `'app'` stages a desktop entry and an icon; `'cli'` stages neither. */
424
437
  kind: 'app' | 'cli';
425
438
  /** Absolute path to the built bundle that `bin/<binaryName>` executes. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/cli",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "description": "CLI for Gjsify",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -142,21 +142,21 @@
142
142
  "cli"
143
143
  ],
144
144
  "dependencies": {
145
- "@gjsify/buffer": "^0.46.0",
146
- "@gjsify/create-app": "^0.46.0",
147
- "@gjsify/node-globals": "^0.46.0",
148
- "@gjsify/node-polyfills": "^0.46.0",
149
- "@gjsify/npm-registry": "^0.46.0",
150
- "@gjsify/resolve-npm": "^0.46.0",
151
- "@gjsify/rolldown-plugin-gjsify": "^0.46.0",
152
- "@gjsify/vite-plugin-blueprint": "^0.46.0",
153
- "@gjsify/rolldown-plugin-pnp": "^0.46.0",
154
- "@gjsify/semver": "^0.46.0",
155
- "@gjsify/tar": "^0.46.0",
156
- "@gjsify/tsc": "^0.46.0",
157
- "@gjsify/utils": "^0.46.0",
158
- "@gjsify/web-polyfills": "^0.46.0",
159
- "@gjsify/workspace": "^0.46.0",
145
+ "@gjsify/buffer": "^0.48.0",
146
+ "@gjsify/create-app": "^0.48.0",
147
+ "@gjsify/node-globals": "^0.48.0",
148
+ "@gjsify/node-polyfills": "^0.48.0",
149
+ "@gjsify/npm-registry": "^0.48.0",
150
+ "@gjsify/resolve-npm": "^0.48.0",
151
+ "@gjsify/rolldown-plugin-gjsify": "^0.48.0",
152
+ "@gjsify/vite-plugin-blueprint": "^0.48.0",
153
+ "@gjsify/rolldown-plugin-pnp": "^0.48.0",
154
+ "@gjsify/semver": "^0.48.0",
155
+ "@gjsify/tar": "^0.48.0",
156
+ "@gjsify/tsc": "^0.48.0",
157
+ "@gjsify/utils": "^0.48.0",
158
+ "@gjsify/web-polyfills": "^0.48.0",
159
+ "@gjsify/workspace": "^0.48.0",
160
160
  "acorn": "^8.17.0",
161
161
  "cosmiconfig": "^9.0.2",
162
162
  "get-tsconfig": "^4.14.0",
@@ -165,13 +165,13 @@
165
165
  "yargs": "^18.0.0"
166
166
  },
167
167
  "devDependencies": {
168
- "@gjsify/unit": "^0.46.0",
168
+ "@gjsify/unit": "^0.48.0",
169
169
  "@types/yargs": "^17.0.35",
170
170
  "typescript": "^6.0.3"
171
171
  },
172
172
  "peerDependencies": {
173
- "@gjsify/oxfmt-native": "^0.46.0",
174
- "@gjsify/rolldown-native": "^0.46.0"
173
+ "@gjsify/oxfmt-native": "^0.48.0",
174
+ "@gjsify/rolldown-native": "^0.48.0"
175
175
  },
176
176
  "peerDependenciesMeta": {
177
177
  "@gjsify/oxfmt-native": {