@gjsify/cli 0.44.0 → 0.46.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 +202 -167
- 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 +850 -58
- package/lib/commands/trust.d.ts +6 -0
- package/lib/commands/trust.js +1 -1
- package/lib/commands/upgrade.d.ts +23 -0
- package/lib/commands/upgrade.js +95 -12
- package/lib/templates/install.mjs.tmpl +2 -2
- package/lib/types/config-data.d.ts +127 -1
- package/lib/utils/gi-search-path.js +11 -3
- 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 +103 -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 +108 -7
- package/lib/utils/ship/formats.js +778 -15
- package/lib/utils/ship/launcher.d.ts +13 -3
- package/lib/utils/ship/launcher.js +419 -17
- package/lib/utils/ship/layout.d.ts +330 -0
- package/lib/utils/ship/layout.js +504 -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 +434 -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 +599 -14
- package/lib/utils/ship/pe-launcher.d.ts +29 -0
- package/lib/utils/ship/pe-launcher.js +663 -0
- package/lib/utils/ship/plan.d.ts +21 -0
- package/lib/utils/ship/plan.js +55 -7
- package/lib/utils/ship/plist.d.ts +98 -0
- package/lib/utils/ship/plist.js +256 -0
- package/lib/utils/ship/rpm.js +16 -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 +91 -2
- package/lib/utils/ship/settings.js +93 -1
- package/lib/utils/ship/share-dirs.d.ts +53 -0
- package/lib/utils/ship/share-dirs.js +76 -0
- package/lib/utils/ship/signing.d.ts +311 -0
- package/lib/utils/ship/signing.js +506 -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 +91 -2
- package/lib/utils/ship/types.d.ts +191 -14
- 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/system-gi.d.ts +20 -5
- package/lib/utils/system-gi.js +36 -13
- package/lib/utils/trust-registry.js +5 -0
- package/package.json +19 -19
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Command } from '../types/index.js';
|
|
2
|
-
type GettextFormat = 'mo' | 'xml' | 'desktop'
|
|
2
|
+
type GettextFormat = 'mo' | 'xml' | 'desktop';
|
|
3
3
|
interface GettextOptions {
|
|
4
4
|
poDir: string;
|
|
5
5
|
outDir: string;
|
|
6
6
|
domain: string;
|
|
7
7
|
format?: GettextFormat;
|
|
8
|
+
template?: string;
|
|
8
9
|
metainfo?: string;
|
|
9
10
|
filename?: string;
|
|
10
11
|
removeXmlComments?: boolean;
|
package/lib/commands/gettext.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
|
-
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
3
4
|
import { basename, join, resolve } from 'node:path';
|
|
4
5
|
import { promisify } from 'node:util';
|
|
6
|
+
import { mergeCatalogues } from '../utils/msgfmt-merge.js';
|
|
5
7
|
const execFileAsync = promisify(execFile);
|
|
6
8
|
async function listLanguages(poDir) {
|
|
7
9
|
const entries = await readdir(poDir);
|
|
@@ -25,40 +27,79 @@ async function fileExists(path) {
|
|
|
25
27
|
return false;
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Fold every catalogue into ONE template.
|
|
32
|
+
*
|
|
33
|
+
* The chain, and the four measured msgfmt constraints that shape it, live in
|
|
34
|
+
* `utils/msgfmt-merge.ts` — `gjsify ship` folds the catalogues it stages into the
|
|
35
|
+
* metadata it generates through the same function, and a second copy of those
|
|
36
|
+
* constraints here would be the copy that drifts.
|
|
37
|
+
*
|
|
38
|
+
* What is local to this command: the output keeps the CALLER's `--filename`,
|
|
39
|
+
* while every INTERMEDIATE is named after the TEMPLATE. Those have to be two
|
|
40
|
+
* different names, because msgfmt finds its ITS rules by filename pattern
|
|
41
|
+
* (constraint 4 over there) and from the second catalogue on the intermediates
|
|
42
|
+
* ARE templates. Named after `--filename` instead, the command's answer depended
|
|
43
|
+
* on how many catalogues there were: measured, `--format xml --template
|
|
44
|
+
* app.metainfo.xml.in --filename out.xml` wrote a translated file for a one-language
|
|
45
|
+
* `po/` and died on a two-language one with `cannot locate ITS rules for
|
|
46
|
+
* <tmpdir>/0-out.xml` — naming an internal path over a rule the user could act on.
|
|
47
|
+
* The template's suffix is what msgfmt validated for call 1, so it is the one
|
|
48
|
+
* suffix known to work for calls 2..n.
|
|
49
|
+
*/
|
|
50
|
+
async function compileMerged(opts) {
|
|
51
|
+
const languages = await listLanguages(opts.poDir);
|
|
52
|
+
if (languages.length === 0) {
|
|
53
|
+
console.warn(`[gjsify gettext] no .po files found in ${opts.poDir}`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
29
56
|
const outputFile = join(opts.outDir, opts.filename);
|
|
30
57
|
await ensureDir(opts.outDir);
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
58
|
+
const workDir = await mkdtemp(join(tmpdir(), 'gjsify-gettext-'));
|
|
59
|
+
try {
|
|
60
|
+
const merged = await readFile(mergeCatalogues({
|
|
61
|
+
mode: `--${opts.format}`,
|
|
62
|
+
template: opts.template,
|
|
63
|
+
// The TEMPLATE's name, minus the `.in` convention — see the header.
|
|
64
|
+
// `basename`, so an intermediate stays inside `workDir` rather than
|
|
65
|
+
// following the directory part of the path the user passed.
|
|
66
|
+
extension: `-${basename(opts.template).replace(/\.in$/, '')}`,
|
|
67
|
+
catalogues: languages.map((lang) => ({ locale: lang, po: join(opts.poDir, `${lang}.po`) })),
|
|
68
|
+
workDir,
|
|
69
|
+
onCall: opts.verbose ? (args) => console.log(`[gjsify gettext] msgfmt ${args.join(' ')}`) : undefined,
|
|
70
|
+
}), 'utf-8');
|
|
71
|
+
await writeFile(outputFile, opts.removeXmlComments && opts.format === 'xml' ? stripXmlComments(merged) : merged);
|
|
34
72
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const content = await readFile(outputFile, 'utf-8');
|
|
38
|
-
await writeFile(outputFile, stripXmlComments(content));
|
|
73
|
+
finally {
|
|
74
|
+
await rm(workDir, { recursive: true, force: true });
|
|
39
75
|
}
|
|
40
76
|
if (opts.verbose) {
|
|
41
|
-
console.log(`[gjsify gettext]
|
|
77
|
+
console.log(`[gjsify gettext] merged ${languages.length} language(s) into ${outputFile}`);
|
|
42
78
|
}
|
|
43
79
|
}
|
|
44
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Compile each `<lang>.po` into `<outDir>/<lang>/LC_MESSAGES/<filename>`.
|
|
82
|
+
*
|
|
83
|
+
* `mo` only. The other two formats SUBSTITUTE a template rather than producing a
|
|
84
|
+
* catalogue, and there is no per-language file for them to write — which is the
|
|
85
|
+
* defect this signature now makes unrepresentable: the old shared loop passed
|
|
86
|
+
* `--desktop`/`--xml` with no `--template`, and msgfmt refuses that outright
|
|
87
|
+
* (`--desktop requires a "--template template" specification`, exit 1). Every
|
|
88
|
+
* `gjsify gettext --format=desktop` invocation had therefore always failed; the
|
|
89
|
+
* only e2e coverage passes `--format mo`, so nothing ever ran the other branch.
|
|
90
|
+
*/
|
|
91
|
+
async function compileCatalogues(opts) {
|
|
45
92
|
const languages = await listLanguages(opts.poDir);
|
|
46
93
|
if (languages.length === 0) {
|
|
47
94
|
console.warn(`[gjsify gettext] no .po files found in ${opts.poDir}`);
|
|
48
95
|
return;
|
|
49
96
|
}
|
|
50
97
|
for (const lang of languages) {
|
|
51
|
-
const
|
|
52
|
-
const langDir = opts.format === 'mo' ? join(opts.outDir, lang, 'LC_MESSAGES') : join(opts.outDir, lang);
|
|
98
|
+
const langDir = join(opts.outDir, lang, 'LC_MESSAGES');
|
|
53
99
|
await ensureDir(langDir);
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
const args = [`--output-file=${outputFile}`];
|
|
58
|
-
if (opts.format !== 'mo') {
|
|
59
|
-
args.push(`--${opts.format}`);
|
|
60
|
-
}
|
|
61
|
-
args.push(poFile);
|
|
100
|
+
// msgfmt produces the binary .mo format by default — there is no `--mo`
|
|
101
|
+
// flag (only --xml, --desktop, --properties-output, ...).
|
|
102
|
+
const args = [`--output-file=${join(langDir, opts.filename)}`, join(opts.poDir, `${lang}.po`)];
|
|
62
103
|
if (opts.verbose) {
|
|
63
104
|
console.log(`[gjsify gettext] msgfmt ${args.join(' ')}`);
|
|
64
105
|
}
|
|
@@ -68,24 +109,22 @@ async function compilePerLanguage(opts) {
|
|
|
68
109
|
console.log(`[gjsify gettext] compiled ${languages.length} language(s) into ${opts.outDir}`);
|
|
69
110
|
}
|
|
70
111
|
}
|
|
71
|
-
function defaultFilename(domain, format,
|
|
112
|
+
function defaultFilename(domain, format, template) {
|
|
72
113
|
switch (format) {
|
|
73
114
|
case 'mo':
|
|
74
115
|
return `${domain}.mo`;
|
|
75
|
-
case 'json':
|
|
76
|
-
return `${domain}.json`;
|
|
77
116
|
case 'desktop':
|
|
78
117
|
return `${domain}.desktop`;
|
|
79
118
|
case 'xml': {
|
|
80
119
|
// Mirror the template filename but without the trailing `.in` (convention for
|
|
81
120
|
// pre-processed metainfo templates: `org.foo.Bar.metainfo.xml.in`).
|
|
82
|
-
if (
|
|
121
|
+
if (template) {
|
|
83
122
|
// `basename`, not a hand-rolled `lastIndexOf('/')`: this is a path the USER
|
|
84
123
|
// passed, and on win32 it separates with `\`, which the slice read as part
|
|
85
124
|
// of the name (#1143). `node:path` is the right owner for host tooling —
|
|
86
125
|
// though it only answers correctly under Node until #1146 makes
|
|
87
126
|
// `@gjsify/path` select win32 per host.
|
|
88
|
-
return basename(
|
|
127
|
+
return basename(template.replace(/\.in$/, ''));
|
|
89
128
|
}
|
|
90
129
|
return `${domain}.xml`;
|
|
91
130
|
}
|
|
@@ -93,7 +132,8 @@ function defaultFilename(domain, format, metainfoTemplate) {
|
|
|
93
132
|
}
|
|
94
133
|
export const gettextCommand = {
|
|
95
134
|
command: 'gettext <poDir> <outDir>',
|
|
96
|
-
description: 'Compile gettext .po files to .mo (per-language locale tree) or
|
|
135
|
+
description: 'Compile gettext .po files to .mo (per-language locale tree), or merge every catalogue into a ' +
|
|
136
|
+
'.desktop / AppStream template via msgfmt --desktop / --xml.',
|
|
97
137
|
builder: (yargs) => {
|
|
98
138
|
return yargs
|
|
99
139
|
.positional('poDir', {
|
|
@@ -103,7 +143,7 @@ export const gettextCommand = {
|
|
|
103
143
|
demandOption: true,
|
|
104
144
|
})
|
|
105
145
|
.positional('outDir', {
|
|
106
|
-
description: 'Output directory (locale tree for --format=mo, plain dir for xml/desktop
|
|
146
|
+
description: 'Output directory (locale tree for --format=mo, plain dir for xml/desktop)',
|
|
107
147
|
type: 'string',
|
|
108
148
|
normalize: true,
|
|
109
149
|
demandOption: true,
|
|
@@ -117,13 +157,21 @@ export const gettextCommand = {
|
|
|
117
157
|
.option('format', {
|
|
118
158
|
description: 'Output format',
|
|
119
159
|
type: 'string',
|
|
120
|
-
choices: ['mo', 'xml', 'desktop'
|
|
160
|
+
choices: ['mo', 'xml', 'desktop'],
|
|
121
161
|
default: 'mo',
|
|
162
|
+
})
|
|
163
|
+
.option('template', {
|
|
164
|
+
description: 'Required for --format=xml|desktop: the file msgfmt substitutes into. Its SUFFIX matters — ' +
|
|
165
|
+
'msgfmt --xml finds its ITS rules by filename pattern, so an AppStream template must be ' +
|
|
166
|
+
'named `*.metainfo.xml[.in]`.',
|
|
167
|
+
type: 'string',
|
|
168
|
+
normalize: true,
|
|
122
169
|
})
|
|
123
170
|
.option('metainfo', {
|
|
124
|
-
description: '
|
|
171
|
+
description: 'Deprecated alias for --template.',
|
|
125
172
|
type: 'string',
|
|
126
173
|
normalize: true,
|
|
174
|
+
hidden: true,
|
|
127
175
|
})
|
|
128
176
|
.option('filename', {
|
|
129
177
|
description: 'Override the output filename (defaults to <domain>.<ext>)',
|
|
@@ -146,8 +194,12 @@ export const gettextCommand = {
|
|
|
146
194
|
const outDir = resolve(args.outDir);
|
|
147
195
|
const domain = args.domain;
|
|
148
196
|
const format = args.format ?? 'mo';
|
|
149
|
-
|
|
150
|
-
|
|
197
|
+
// `--metainfo` predates the option being useful for `.desktop` too. Kept as a
|
|
198
|
+
// hidden alias rather than removed: it is the spelling `cli-reference.md`
|
|
199
|
+
// documented, so removing it would break the invocation the docs taught.
|
|
200
|
+
const templateArg = args.template ?? args.metainfo;
|
|
201
|
+
const template = templateArg ? resolve(templateArg) : undefined;
|
|
202
|
+
const filename = args.filename ?? defaultFilename(domain, format, template);
|
|
151
203
|
const verbose = !!args.verbose;
|
|
152
204
|
const removeXmlComments = !!args['remove-xml-comments'];
|
|
153
205
|
if (!(await fileExists(poDir))) {
|
|
@@ -155,28 +207,34 @@ export const gettextCommand = {
|
|
|
155
207
|
process.exitCode = 1;
|
|
156
208
|
return;
|
|
157
209
|
}
|
|
210
|
+
// REFUSED, not worked around. `--xml` and `--desktop` substitute into a
|
|
211
|
+
// template, and msgfmt rejects both without one (`--desktop requires a
|
|
212
|
+
// "--template template" specification`, exit 1). The old code fell back to a
|
|
213
|
+
// per-language loop that passed no template at all, so the fallback could only
|
|
214
|
+
// ever reproduce that same error one layer further down — with the user's
|
|
215
|
+
// `--format` reported as the thing that failed rather than the missing template.
|
|
216
|
+
if (format !== 'mo' && template === undefined) {
|
|
217
|
+
console.error(`[gjsify gettext] --format=${format} needs a template to substitute into: pass ` +
|
|
218
|
+
'`--template <file>`. msgfmt has no way to produce this format from .po files alone.' +
|
|
219
|
+
(format === 'xml'
|
|
220
|
+
? ' Name it `*.metainfo.xml[.in]` — msgfmt --xml finds its ITS rules by filename pattern.'
|
|
221
|
+
: ''));
|
|
222
|
+
process.exitCode = 1;
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
158
225
|
try {
|
|
159
|
-
if (format === '
|
|
160
|
-
await
|
|
161
|
-
poDir,
|
|
162
|
-
outDir,
|
|
163
|
-
domain,
|
|
164
|
-
template: metainfo,
|
|
165
|
-
filename,
|
|
166
|
-
removeXmlComments,
|
|
167
|
-
verbose,
|
|
168
|
-
});
|
|
226
|
+
if (format === 'mo') {
|
|
227
|
+
await compileCatalogues({ poDir, outDir, filename, verbose });
|
|
169
228
|
}
|
|
170
229
|
else {
|
|
171
|
-
|
|
172
|
-
console.warn('[gjsify gettext] --format=xml without --metainfo: falling back to per-language XML files');
|
|
173
|
-
}
|
|
174
|
-
await compilePerLanguage({
|
|
230
|
+
await compileMerged({
|
|
175
231
|
poDir,
|
|
176
232
|
outDir,
|
|
177
|
-
domain,
|
|
178
233
|
format,
|
|
234
|
+
// Narrowed by the refusal above.
|
|
235
|
+
template: template,
|
|
179
236
|
filename,
|
|
237
|
+
removeXmlComments,
|
|
180
238
|
verbose,
|
|
181
239
|
});
|
|
182
240
|
}
|
|
@@ -6,6 +6,13 @@ interface OnboardOptions {
|
|
|
6
6
|
registry?: string;
|
|
7
7
|
otp?: string;
|
|
8
8
|
concurrency: number;
|
|
9
|
+
'write-concurrency': number;
|
|
10
|
+
packages?: string[];
|
|
11
|
+
include?: string[];
|
|
12
|
+
exclude?: string[];
|
|
13
|
+
access: string;
|
|
14
|
+
build: boolean;
|
|
15
|
+
verbose?: boolean;
|
|
9
16
|
'dry-run'?: boolean;
|
|
10
17
|
json?: boolean;
|
|
11
18
|
yes?: boolean;
|