@gjsify/cli 0.44.0 → 0.45.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/cli.gjs.mjs +192 -165
- package/lib/commands/gettext.d.ts +2 -1
- package/lib/commands/gettext.js +105 -47
- package/lib/commands/onboard.d.ts +7 -0
- package/lib/commands/onboard.js +349 -96
- package/lib/commands/ship.d.ts +3 -0
- package/lib/commands/ship.js +833 -54
- package/lib/commands/trust.d.ts +6 -0
- package/lib/commands/trust.js +1 -1
- package/lib/types/config-data.d.ts +63 -1
- package/lib/utils/msgfmt-merge.d.ts +35 -0
- package/lib/utils/msgfmt-merge.js +102 -0
- package/lib/utils/npm-otp.d.ts +27 -2
- package/lib/utils/npm-otp.js +82 -7
- package/lib/utils/onboard-discovery.d.ts +68 -0
- package/lib/utils/onboard-discovery.js +178 -0
- package/lib/utils/onboard-probe.d.ts +118 -1
- package/lib/utils/onboard-probe.js +153 -4
- package/lib/utils/prompt-output.d.ts +12 -0
- package/lib/utils/prompt-output.js +54 -0
- package/lib/utils/prompt.js +22 -2
- package/lib/utils/publishable-packages.d.ts +1 -1
- package/lib/utils/publishable-packages.js +1 -0
- package/lib/utils/resolve-npm-package.d.ts +56 -0
- package/lib/utils/resolve-npm-package.js +69 -0
- package/lib/utils/ship/app-runtime.d.ts +214 -0
- package/lib/utils/ship/app-runtime.js +429 -0
- package/lib/utils/ship/depends.d.ts +50 -0
- package/lib/utils/ship/depends.js +117 -3
- package/lib/utils/ship/discover.js +18 -1
- package/lib/utils/ship/dmg.d.ts +71 -0
- package/lib/utils/ship/dmg.js +181 -0
- package/lib/utils/ship/flatpak.js +1 -1
- package/lib/utils/ship/formats.d.ts +85 -7
- package/lib/utils/ship/formats.js +734 -15
- package/lib/utils/ship/launcher.d.ts +13 -3
- package/lib/utils/ship/launcher.js +362 -17
- package/lib/utils/ship/layout.d.ts +268 -0
- package/lib/utils/ship/layout.js +351 -0
- package/lib/utils/ship/localize-metadata.d.ts +22 -0
- package/lib/utils/ship/localize-metadata.js +126 -0
- package/lib/utils/ship/mime.js +1 -9
- package/lib/utils/ship/msi.d.ts +126 -0
- package/lib/utils/ship/msi.js +417 -0
- package/lib/utils/ship/node-runtime.d.ts +71 -0
- package/lib/utils/ship/node-runtime.js +122 -0
- package/lib/utils/ship/payload.d.ts +156 -5
- package/lib/utils/ship/payload.js +580 -14
- package/lib/utils/ship/plan.d.ts +21 -0
- package/lib/utils/ship/plan.js +20 -7
- package/lib/utils/ship/plist.d.ts +58 -0
- package/lib/utils/ship/plist.js +198 -0
- package/lib/utils/ship/rpm.js +9 -3
- package/lib/utils/ship/schemas.d.ts +61 -0
- package/lib/utils/ship/schemas.js +118 -0
- package/lib/utils/ship/scripts.js +7 -3
- package/lib/utils/ship/settings.d.ts +19 -1
- package/lib/utils/ship/settings.js +12 -1
- package/lib/utils/ship/share-dirs.d.ts +23 -0
- package/lib/utils/ship/share-dirs.js +46 -0
- package/lib/utils/ship/signing.d.ts +195 -0
- package/lib/utils/ship/signing.js +317 -0
- package/lib/utils/ship/stage-manifest.d.ts +40 -12
- package/lib/utils/ship/stage-manifest.js +99 -13
- package/lib/utils/ship/stage-writer.d.ts +48 -0
- package/lib/utils/ship/stage-writer.js +71 -1
- package/lib/utils/ship/types.d.ts +158 -13
- package/lib/utils/ship/xml.d.ts +7 -0
- package/lib/utils/ship/xml.js +25 -0
- package/lib/utils/ship/zip.d.ts +69 -0
- package/lib/utils/ship/zip.js +245 -0
- package/lib/utils/trust-registry.js +5 -0
- package/package.json +19 -19
|
@@ -52,7 +52,24 @@ function discoverTypelibs(projectDir, dirs) {
|
|
|
52
52
|
'A missing directory here means the package would install without the typelib it promises.');
|
|
53
53
|
}
|
|
54
54
|
for (const file of listFilesRecursive(root)) {
|
|
55
|
-
|
|
55
|
+
// Every shared-library spelling, not only ELF's. A typelib is
|
|
56
|
+
// useless without its library on macOS and Windows too, and the
|
|
57
|
+
// `.so`-only test dropped `libgwebgl.dylib` and `gwebgl-0.dll` while
|
|
58
|
+
// staging the `.typelib` beside them — a package that installs and
|
|
59
|
+
// dies at the first import, with nothing in the output saying so.
|
|
60
|
+
// The layout axis (ADR 0024 § 2) is what put those two files in
|
|
61
|
+
// reach: they land in `Contents/Frameworks` and in the program
|
|
62
|
+
// directory's `lib\`.
|
|
63
|
+
// Case-insensitive for the extensions that come off case-preserving-
|
|
64
|
+
// but-INSENSITIVE filesystems — `LIBFOO.DLL` and `Foo.Dylib` are
|
|
65
|
+
// ordinary names on macOS and Windows, and a lowercase-only test drops
|
|
66
|
+
// them into exactly the silent failure the paragraph above describes.
|
|
67
|
+
//
|
|
68
|
+
// NOT for `.so`, and the asymmetry is the reason rather than an
|
|
69
|
+
// oversight: ELF sonames come off case-SENSITIVE filesystems where
|
|
70
|
+
// `libfoo.so` is the only spelling, and `/i` there additionally makes
|
|
71
|
+
// `README.SO` a shared library. One rationale, one scope.
|
|
72
|
+
if (/\.(typelib|dylib|dll)$/i.test(file) || /\.so(\.\d+)*$/.test(file))
|
|
56
73
|
out.push(join(root, file));
|
|
57
74
|
}
|
|
58
75
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { PackSettings } from './types.js';
|
|
2
|
+
/** The tool this packer execs. One spelling, read by this module AND by the format row. */
|
|
3
|
+
export declare const DMG_TOOL = "hdiutil";
|
|
4
|
+
/**
|
|
5
|
+
* What the mounted image is called in the Finder's sidebar.
|
|
6
|
+
*
|
|
7
|
+
* The DISPLAY name, like the `.app` inside it — the volume and the bundle are
|
|
8
|
+
* the two things a user reads during the one interaction this format has, and
|
|
9
|
+
* spelling them differently (`Ship Demo.app` inside `ship-demo-1.2.3`) makes the
|
|
10
|
+
* window look like somebody else's download. The FILE keeps the versioned,
|
|
11
|
+
* space-free name, because that one lands in a downloads folder beside others;
|
|
12
|
+
* `FormatDescriptor.fileName` is where that split lives, exactly as it does for
|
|
13
|
+
* the `.app` and its zip.
|
|
14
|
+
*
|
|
15
|
+
* EMPTY IS REFUSED, and it is not defensive: `resolveShipSettings` derives the
|
|
16
|
+
* name as `metadata.name ?? titleCase(binaryName)` and `??` passes `''` straight
|
|
17
|
+
* through — the same hole `windowsProgramDirName` documents. `hdiutil` answers an
|
|
18
|
+
* empty `-volname` by calling the volume `untitled`, at exit 0, so the image
|
|
19
|
+
* would build and mount under a name nothing in the project ever chose.
|
|
20
|
+
*/
|
|
21
|
+
export declare function dmgVolumeName(settings: PackSettings): string;
|
|
22
|
+
export interface DmgCreateInput {
|
|
23
|
+
/** The volume label — see {@link dmgVolumeName}. */
|
|
24
|
+
volumeName: string;
|
|
25
|
+
/** The directory whose CONTENTS become the volume root; it holds `<App>.app` and nothing else. */
|
|
26
|
+
sourceDir: string;
|
|
27
|
+
/** Absolute path the finished `.dmg` is written to. */
|
|
28
|
+
target: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The exact `hdiutil` invocation, as data.
|
|
32
|
+
*
|
|
33
|
+
* Pure, so every flag is unit-testable from Linux — which is the only kind of
|
|
34
|
+
* host this project's contributors and its `e2e` job have. Same split as
|
|
35
|
+
* `renderShipFlatpakManifest`: what the tool is TOLD is checkable everywhere,
|
|
36
|
+
* what the tool DOES is checkable on the one OS that has it, and the two are not
|
|
37
|
+
* the same test.
|
|
38
|
+
*
|
|
39
|
+
* `-srcfolder` and not `-srcdevice`/`-size`: the folder's contents become the
|
|
40
|
+
* volume root, so `hdiutil` sizes the image itself. Passing a `-size` instead is
|
|
41
|
+
* how a `.dmg` build starts failing on the day the payload grows past a number
|
|
42
|
+
* somebody typed once.
|
|
43
|
+
*/
|
|
44
|
+
export declare function hdiutilCreateArgs(input: DmgCreateInput): string[];
|
|
45
|
+
export interface DmgPackInput extends DmgCreateInput {
|
|
46
|
+
verbose: boolean;
|
|
47
|
+
/** Working root, so the log can name the directory that became the volume. */
|
|
48
|
+
workDir: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Build the image at `input.target`.
|
|
52
|
+
*
|
|
53
|
+
* Unlike the Flatpak packer's tool, this one cannot be installed where it is
|
|
54
|
+
* missing: `hdiutil` ships with macOS and exists nowhere else. So the `notFound` branch does not say "install
|
|
55
|
+
* it"; it says which host this belongs on and how the payload gets there, which
|
|
56
|
+
* is the same two-phase sentence `assertHostCanFinish` prints one step earlier.
|
|
57
|
+
* Reaching this branch at all means `process.platform` said darwin and `hdiutil`
|
|
58
|
+
* was still absent, so the honest advice is "this macOS installation is broken",
|
|
59
|
+
* not a package name.
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildDmgImage(input: DmgPackInput): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Where the volume is assembled before `hdiutil` turns it into an image.
|
|
64
|
+
*
|
|
65
|
+
* A directory of its own under the run's output root, never `out/` itself: the
|
|
66
|
+
* volume root holds the `.app` and NOTHING ELSE, because `-srcfolder` copies
|
|
67
|
+
* whatever it finds — a stray sibling would ride into the image, and the reader
|
|
68
|
+
* that would catch it is the same listing comparison that would then have to be
|
|
69
|
+
* relaxed to allow it.
|
|
70
|
+
*/
|
|
71
|
+
export declare function dmgVolumeDir(outRoot: string): string;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// The `.dmg` packer — ADR 0024 § A1/§ A6, issue #1354 M4.
|
|
2
|
+
//
|
|
3
|
+
// THE FIRST FORMAT THAT IS HOST-BOUND IN THE `HostRequirement` SENSE, and the
|
|
4
|
+
// distinction ADR 0024 § A3 drew between its two refusals is what this row is
|
|
5
|
+
// the first subject of. A Flatpak is `finishOn: ['linux']` because flatpak runs
|
|
6
|
+
// on Linux — the format is bound the way the application is. A `.dmg` is bound
|
|
7
|
+
// by the CONTAINER: it is a UDIF image over a real HFS+/APFS volume, no
|
|
8
|
+
// HFS+/APFS writer exists anywhere in this tree, and `hdiutil` is macOS-only.
|
|
9
|
+
// So `assertHostCanFinish` refuses it off darwin and `assertToolsInstalled`
|
|
10
|
+
// names `hdiutil` on a darwin host that somehow lacks it — two failures with
|
|
11
|
+
// two different fixes, which is exactly why they are two functions.
|
|
12
|
+
//
|
|
13
|
+
// A HAND-WRITTEN UDIF WRITER STAYS REJECTED (§ A6), in that section's own
|
|
14
|
+
// words: 1200-2000 lines against a whole existing packer surface of ~1243, and
|
|
15
|
+
// every mistake silent, because the Finder mounts the image and shows an empty
|
|
16
|
+
// window. What we would buy is an independent reader, and 7-Zip already
|
|
17
|
+
// advertises `Dmg`, `HFS` and `APFS` handlers regardless of who wrote the file.
|
|
18
|
+
//
|
|
19
|
+
// WHICH MAKES THE ORACLE THE INTERESTING PART, because `hdiutil verify` is
|
|
20
|
+
// `hdiutil` reading what `hdiutil` wrote. The reader is a chain that runs on
|
|
21
|
+
// LINUX — `7z l` (7-Zip 23.01 on ubuntu-24.04 carries `Dmg`, `HFS` and `APFS`),
|
|
22
|
+
// `7z t` to inflate what it stores, then `dmg2img` to a raw volume and
|
|
23
|
+
// `fsck.hfsplus -f -n` over that — driven by `.github/ship-oracle/verify-dmg.py`
|
|
24
|
+
// and compared against the stage manifest by name, size and MODE. Three
|
|
25
|
+
// implementations, none of them Apple's and none of them ours.
|
|
26
|
+
//
|
|
27
|
+
// TWO hdiutil FLAGS ARE DECISIONS AND NOT DEFAULTS:
|
|
28
|
+
//
|
|
29
|
+
// * `-fs HFS+J`. APFS is what a modern `hdiutil` reaches for when nothing says
|
|
30
|
+
// otherwise, and the whole Linux reader chain above is an HFS+ chain —
|
|
31
|
+
// `dmg2img` writes a raw volume and `fsck.hfsplus` is an HFS+ fsck. An APFS
|
|
32
|
+
// image would leave 7-Zip's handler as the only reader, i.e. one reader for
|
|
33
|
+
// the negative control to fool. Journaling costs a read-only image nothing
|
|
34
|
+
// and `fsck.hfsplus` reads it: measured on ubuntu-24.04 / hfsprogs
|
|
35
|
+
// 540.1.linux3-5build3 against a `mkfs.hfsplus -J` volume, "** Checking
|
|
36
|
+
// Journaled HFS Plus volume … appears to be OK", exit 0.
|
|
37
|
+
// * `-format UDZO`, i.e. zlib. The alternatives are ULFO (LZFSE) and ULMO
|
|
38
|
+
// (LZMA), and the reader that would have to decode them is the OLD one:
|
|
39
|
+
// ubuntu-24.04 ships 7-Zip 23.01, not this workstation's 26.02. zlib is the
|
|
40
|
+
// method its `Dmg` handler has read since long before either.
|
|
41
|
+
//
|
|
42
|
+
// WHAT THIS PACKER DOES NOT PUT IN THE VOLUME: an `/Applications` symlink, the
|
|
43
|
+
// drag-here convention. `writePayload` writes regular files and nothing else —
|
|
44
|
+
// which is a property `tests/e2e/ship` and the `ship-stage` job both assert, and
|
|
45
|
+
// a symlink is also what `actions/upload-artifact` silently dereferences. The
|
|
46
|
+
// artifact is still draggable out of the mounted volume; what it lacks is the
|
|
47
|
+
// arrow. Unblocker: a staged-symlink concept with a reader that can see one, at
|
|
48
|
+
// which point the link and its oracle land together.
|
|
49
|
+
import { join } from 'node:path';
|
|
50
|
+
import { describeExit, spawnToCompletion } from '../spawn.js';
|
|
51
|
+
/** The tool this packer execs. One spelling, read by this module AND by the format row. */
|
|
52
|
+
export const DMG_TOOL = 'hdiutil';
|
|
53
|
+
/**
|
|
54
|
+
* Characters an HFS+ volume name may not contain.
|
|
55
|
+
*
|
|
56
|
+
* Two of the three `layout.ts` refuses in a bundle DIRECTORY name — its
|
|
57
|
+
* `BUNDLE_NAME_FORBIDDEN` is `/[/:\\]/` — and for the same measured reason: `/`
|
|
58
|
+
* is the POSIX separator and `:` is HFS+'s, and the Finder shows a stored `:` as
|
|
59
|
+
* a `/` and vice versa. A volume called `Ship/Demo` mounts as `Ship:Demo`, so the
|
|
60
|
+
* name a user is told to look for is not the name they see. `\` is the one that
|
|
61
|
+
* is NOT here: it is an ordinary character in a volume name, while a bundle
|
|
62
|
+
* directory refuses it too and `windowsProgramDirName` refuses it for Windows'
|
|
63
|
+
* own reasons.
|
|
64
|
+
*/
|
|
65
|
+
const VOLUME_NAME_FORBIDDEN = /[/:]/;
|
|
66
|
+
/**
|
|
67
|
+
* What the mounted image is called in the Finder's sidebar.
|
|
68
|
+
*
|
|
69
|
+
* The DISPLAY name, like the `.app` inside it — the volume and the bundle are
|
|
70
|
+
* the two things a user reads during the one interaction this format has, and
|
|
71
|
+
* spelling them differently (`Ship Demo.app` inside `ship-demo-1.2.3`) makes the
|
|
72
|
+
* window look like somebody else's download. The FILE keeps the versioned,
|
|
73
|
+
* space-free name, because that one lands in a downloads folder beside others;
|
|
74
|
+
* `FormatDescriptor.fileName` is where that split lives, exactly as it does for
|
|
75
|
+
* the `.app` and its zip.
|
|
76
|
+
*
|
|
77
|
+
* EMPTY IS REFUSED, and it is not defensive: `resolveShipSettings` derives the
|
|
78
|
+
* name as `metadata.name ?? titleCase(binaryName)` and `??` passes `''` straight
|
|
79
|
+
* through — the same hole `windowsProgramDirName` documents. `hdiutil` answers an
|
|
80
|
+
* empty `-volname` by calling the volume `untitled`, at exit 0, so the image
|
|
81
|
+
* would build and mount under a name nothing in the project ever chose.
|
|
82
|
+
*/
|
|
83
|
+
export function dmgVolumeName(settings) {
|
|
84
|
+
const name = settings.name;
|
|
85
|
+
if (name.trim() === '') {
|
|
86
|
+
throw new Error('gjsify ship: the macOS image has no name to call its volume — `gjsify.ship.name` (or the ' +
|
|
87
|
+
'package name it is derived from) is empty. `hdiutil` would accept that and mount the ' +
|
|
88
|
+
'image as `untitled`, which is the name every nameless disk image on the machine has.');
|
|
89
|
+
}
|
|
90
|
+
if (VOLUME_NAME_FORBIDDEN.test(name)) {
|
|
91
|
+
throw new Error(`gjsify ship: the macOS image would mount a volume called "${name}", and HFS+ cannot hold it: ` +
|
|
92
|
+
'the Finder shows a stored ":" as a "/" and a stored "/" as a ":", so the volume would not ' +
|
|
93
|
+
'be the one this project named. Set `gjsify.ship.name` to the display name you want.');
|
|
94
|
+
}
|
|
95
|
+
return name;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The exact `hdiutil` invocation, as data.
|
|
99
|
+
*
|
|
100
|
+
* Pure, so every flag is unit-testable from Linux — which is the only kind of
|
|
101
|
+
* host this project's contributors and its `e2e` job have. Same split as
|
|
102
|
+
* `renderShipFlatpakManifest`: what the tool is TOLD is checkable everywhere,
|
|
103
|
+
* what the tool DOES is checkable on the one OS that has it, and the two are not
|
|
104
|
+
* the same test.
|
|
105
|
+
*
|
|
106
|
+
* `-srcfolder` and not `-srcdevice`/`-size`: the folder's contents become the
|
|
107
|
+
* volume root, so `hdiutil` sizes the image itself. Passing a `-size` instead is
|
|
108
|
+
* how a `.dmg` build starts failing on the day the payload grows past a number
|
|
109
|
+
* somebody typed once.
|
|
110
|
+
*/
|
|
111
|
+
export function hdiutilCreateArgs(input) {
|
|
112
|
+
return [
|
|
113
|
+
'create',
|
|
114
|
+
// Read-only + zlib. See the header: the alternatives are decodable only
|
|
115
|
+
// by a newer 7-Zip than the reader leg has.
|
|
116
|
+
'-format',
|
|
117
|
+
'UDZO',
|
|
118
|
+
// HFS+ EXPLICITLY, because the default is the thing the reader chain
|
|
119
|
+
// cannot read. See the header.
|
|
120
|
+
'-fs',
|
|
121
|
+
'HFS+J',
|
|
122
|
+
'-volname',
|
|
123
|
+
input.volumeName,
|
|
124
|
+
'-srcfolder',
|
|
125
|
+
input.sourceDir,
|
|
126
|
+
// hdiutil REFUSES an existing target rather than replacing it, and
|
|
127
|
+
// `packOne` writes into `out/` which a previous run may have filled. The
|
|
128
|
+
// failure without this is a pack that dies on its second invocation only.
|
|
129
|
+
'-ov',
|
|
130
|
+
// Progress on a TTY is a spinner; in a CI log it is thousands of lines.
|
|
131
|
+
'-quiet',
|
|
132
|
+
input.target,
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Build the image at `input.target`.
|
|
137
|
+
*
|
|
138
|
+
* Unlike the Flatpak packer's tool, this one cannot be installed where it is
|
|
139
|
+
* missing: `hdiutil` ships with macOS and exists nowhere else. So the `notFound` branch does not say "install
|
|
140
|
+
* it"; it says which host this belongs on and how the payload gets there, which
|
|
141
|
+
* is the same two-phase sentence `assertHostCanFinish` prints one step earlier.
|
|
142
|
+
* Reaching this branch at all means `process.platform` said darwin and `hdiutil`
|
|
143
|
+
* was still absent, so the honest advice is "this macOS installation is broken",
|
|
144
|
+
* not a package name.
|
|
145
|
+
*/
|
|
146
|
+
export async function buildDmgImage(input) {
|
|
147
|
+
const args = hdiutilCreateArgs(input);
|
|
148
|
+
if (input.verbose)
|
|
149
|
+
console.log(`[gjsify ship] ${DMG_TOOL} ${args.join(' ')}`);
|
|
150
|
+
// `completion: 'return'`, matching the Flatpak packer: `ship` packs the
|
|
151
|
+
// remaining formats and prints the artifact list afterwards, so it cannot end
|
|
152
|
+
// in `process.exit()`. Under GJS that selects the blocking path, which
|
|
153
|
+
// captures the child's output and re-emits it — the documented cost of a
|
|
154
|
+
// spawn a caller has to return from (`utils/spawn.ts`), and why `--verbose`
|
|
155
|
+
// prints the invocation before the silence starts.
|
|
156
|
+
const result = await spawnToCompletion(DMG_TOOL, args, {
|
|
157
|
+
completion: 'return',
|
|
158
|
+
cwd: input.workDir,
|
|
159
|
+
stdio: 'inherit',
|
|
160
|
+
notFound: () => new Error(`gjsify ship: ${DMG_TOOL} is not on PATH. It ships with macOS and cannot be installed ` +
|
|
161
|
+
'anywhere else, so this is either a broken macOS installation or a host that is not ' +
|
|
162
|
+
'macOS at all. A `.dmg` is packed on darwin (ADR 0024 § A1); from anywhere else the ' +
|
|
163
|
+
'route is `gjsify ship darwin --stage` here and `gjsify ship --from-stage <dir> ' +
|
|
164
|
+
'--target macos-app-dmg` there.'),
|
|
165
|
+
});
|
|
166
|
+
if (result.code !== 0) {
|
|
167
|
+
throw new Error(`gjsify ship: ${DMG_TOOL} failed with ${describeExit(result)}.`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Where the volume is assembled before `hdiutil` turns it into an image.
|
|
172
|
+
*
|
|
173
|
+
* A directory of its own under the run's output root, never `out/` itself: the
|
|
174
|
+
* volume root holds the `.app` and NOTHING ELSE, because `-srcfolder` copies
|
|
175
|
+
* whatever it finds — a stray sibling would ride into the image, and the reader
|
|
176
|
+
* that would catch it is the same listing comparison that would then have to be
|
|
177
|
+
* relaxed to allow it.
|
|
178
|
+
*/
|
|
179
|
+
export function dmgVolumeDir(outRoot) {
|
|
180
|
+
return join(outRoot, 'dmg', 'volume');
|
|
181
|
+
}
|
|
@@ -143,6 +143,6 @@ async function run(cmd, args, input, notFoundHint) {
|
|
|
143
143
|
notFound: () => new Error(`gjsify ship: ${notFoundHint}`),
|
|
144
144
|
});
|
|
145
145
|
if (result.code !== 0) {
|
|
146
|
-
throw new Error(`gjsify ship: ${cmd} failed${describeExit(result)}.`);
|
|
146
|
+
throw new Error(`gjsify ship: ${cmd} failed with ${describeExit(result)}.`);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
@@ -1,9 +1,40 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type Layout } from './layout.js';
|
|
2
|
+
import type { FormatDescriptor, FormatId, HostOs, PackSettings, RequiredTools } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The directory `windows-dir` produces, and the top level `windows-dir-zip` puts
|
|
5
|
+
* its entries under.
|
|
6
|
+
*
|
|
7
|
+
* ONE function with TWO readers, deliberately: the zip has to expand to the same
|
|
8
|
+
* directory the other row writes, and two literals would be two names a user is
|
|
9
|
+
* asked to believe are one.
|
|
10
|
+
*/
|
|
11
|
+
export declare function windowsProgramDirName(settings: PackSettings): string;
|
|
12
|
+
/**
|
|
13
|
+
* The tools ONE host needs for a format, whichever shape the row declares.
|
|
14
|
+
*
|
|
15
|
+
* The one place the union in {@link RequiredTools} is opened, so a caller cannot
|
|
16
|
+
* read the map and get `undefined.filter` or read the array on a row that has a
|
|
17
|
+
* map. An OS the map does not name answers `[]` — not because nothing is needed
|
|
18
|
+
* there, but because {@link assertHostCanFinish} has already refused that host by
|
|
19
|
+
* the time this is asked, and inventing a tool list for a host that cannot finish
|
|
20
|
+
* the format would answer a question nobody may ask.
|
|
21
|
+
*/
|
|
22
|
+
export declare function requiredToolsOn(tools: RequiredTools, host: string): readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* Every tool any host could need for a format — the question `installHint`'s
|
|
25
|
+
* presence is gated on.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately NOT what {@link assertToolsInstalled} checks. "Does this row need a
|
|
28
|
+
* hint at all" is a property of the ROW; "is this tool here" is a question about
|
|
29
|
+
* one machine, and answering the first with the second would let a row declare a
|
|
30
|
+
* Windows-only tool and no hint, because the gate happened to run on Linux.
|
|
31
|
+
*/
|
|
32
|
+
export declare function allRequiredTools(tools: RequiredTools): readonly string[];
|
|
2
33
|
export declare const FORMATS: Record<FormatId, FormatDescriptor>;
|
|
3
34
|
export declare const FORMAT_IDS: FormatId[];
|
|
4
35
|
/**
|
|
5
|
-
* What `gjsify ship
|
|
6
|
-
* needs no tool and no particular host.
|
|
36
|
+
* What `gjsify ship <os>` builds when nothing said otherwise — every format that
|
|
37
|
+
* wraps THAT OS's layout and needs no tool and no particular host.
|
|
7
38
|
*
|
|
8
39
|
* A SECOND derivation from the same table, and it has to be one: `FORMAT_IDS`
|
|
9
40
|
* used to be both "every format that exists" and "every format to build by
|
|
@@ -14,8 +45,22 @@ export declare const FORMAT_IDS: FormatId[];
|
|
|
14
45
|
* packs `@gjsify/cli` itself on a bare ubuntu runner. A host-bound format is
|
|
15
46
|
* opt-in through `--target` or `gjsify.ship.targets`; `--help` still lists all
|
|
16
47
|
* of them.
|
|
48
|
+
*
|
|
49
|
+
* `layoutOs` is the SECOND criterion, and it is what the layout axis needed: a
|
|
50
|
+
* `.app` and its zip and a Windows program directory are all `finishOn: 'any'`,
|
|
51
|
+
* so on the one criterion a bare `gjsify ship` on Linux would start emitting
|
|
52
|
+
* five artifacts (ADR 0024 issue #1354, open question 3). Answered with § A2's
|
|
53
|
+
* positional rather than instead of it — the positional picks the layout, this
|
|
54
|
+
* picks the formats that wrap it, and `gjsify ship` on Linux keeps emitting
|
|
55
|
+
* exactly `deb` and `rpm`.
|
|
56
|
+
*
|
|
57
|
+
* An EMPTY answer is legal and is what darwin and windows give today: their
|
|
58
|
+
* layouts assemble (`--stage`) and no format wraps them yet. `assemble` refuses
|
|
59
|
+
* a pack with nothing to pack rather than exiting 0 having produced no artifact.
|
|
17
60
|
*/
|
|
18
|
-
export declare
|
|
61
|
+
export declare function defaultFormatIds(layoutOs: HostOs): FormatId[];
|
|
62
|
+
/** Every format that wraps one OS's layout, tool-bound ones included. */
|
|
63
|
+
export declare function formatIdsFor(layoutOs: HostOs): FormatId[];
|
|
19
64
|
/**
|
|
20
65
|
* Refuse a format this host cannot finish, BEFORE anything is built or written.
|
|
21
66
|
*
|
|
@@ -35,6 +80,39 @@ export declare function assertHostCanFinish(format: FormatDescriptor, host?: str
|
|
|
35
80
|
* a build: `gjsify ship` runs the project's `build` script first, and finding
|
|
36
81
|
* out afterwards that `flatpak-builder` is absent costs the whole build.
|
|
37
82
|
*/
|
|
38
|
-
export declare function assertToolsInstalled(format: FormatDescriptor, present?: (cmd: string) => boolean): void;
|
|
39
|
-
/**
|
|
40
|
-
|
|
83
|
+
export declare function assertToolsInstalled(format: FormatDescriptor, present?: (cmd: string) => boolean, host?: string): void;
|
|
84
|
+
/**
|
|
85
|
+
* Parse an explicit `--target deb,rpm` into a sorted, deduplicated descriptor list.
|
|
86
|
+
*
|
|
87
|
+
* A format belonging to another layout is an ERROR here, not a filter:
|
|
88
|
+
* `gjsify ship darwin --target deb` is a mistake worth naming, and dropping it
|
|
89
|
+
* silently would stage the darwin layout, pack nothing and exit 0 — the shape
|
|
90
|
+
* the empty-list refusal above already exists to prevent, arriving through a
|
|
91
|
+
* different door.
|
|
92
|
+
*
|
|
93
|
+
* The FLAG is what makes that the right answer, and it is the whole difference
|
|
94
|
+
* from {@link configuredFormats}: a value typed on this command line is a claim
|
|
95
|
+
* about THIS run.
|
|
96
|
+
*/
|
|
97
|
+
export declare function resolveFormats(raw: readonly string[], layout: Layout): FormatDescriptor[];
|
|
98
|
+
/**
|
|
99
|
+
* The same names from `gjsify.ship.targets`, FILTERED to the current layout.
|
|
100
|
+
*
|
|
101
|
+
* A configured list is a project-level DEFAULT — "when I ship this, build these"
|
|
102
|
+
* — written once and read by every run, so it cannot be a claim about a layout
|
|
103
|
+
* the author had not heard of when they wrote it. Refusing it the way
|
|
104
|
+
* {@link resolveFormats} refuses a flag makes the new positional unusable in
|
|
105
|
+
* every project that has the key, and this repository is the proof: with
|
|
106
|
+
* `targets: ["deb", "rpm"]` in `packages/infra/cli/package.json`,
|
|
107
|
+
* `gjsify ship darwin --stage` exited 1 telling the author to run
|
|
108
|
+
* `gjsify ship darwin --stage`. There was no `--target` value that got a darwin
|
|
109
|
+
* stage out of such a project at all.
|
|
110
|
+
*
|
|
111
|
+
* Filtering is safe HERE and only here, because an empty result is not a silent
|
|
112
|
+
* success: `assemble` refuses a PACK with nothing to pack, and a `--stage` run
|
|
113
|
+
* legitimately wants exactly this — assemble the layout, wrap nothing.
|
|
114
|
+
*/
|
|
115
|
+
export declare function configuredFormats(raw: readonly string[], layout: Layout): {
|
|
116
|
+
formats: FormatDescriptor[];
|
|
117
|
+
dropped: FormatId[];
|
|
118
|
+
};
|