@gjsify/cli 0.4.10 → 0.4.12
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 +16 -12
- package/lib/commands/flatpak/check.d.ts +11 -0
- package/lib/commands/flatpak/check.js +163 -0
- package/lib/commands/flatpak/index.d.ts +2 -1
- package/lib/commands/flatpak/index.js +5 -3
- package/lib/commands/flatpak/init.d.ts +4 -0
- package/lib/commands/flatpak/init.js +94 -27
- package/lib/commands/flatpak/scaffold.d.ts +26 -0
- package/lib/commands/flatpak/scaffold.js +327 -0
- package/lib/commands/index.d.ts +1 -0
- package/lib/commands/index.js +1 -0
- package/lib/commands/uninstall.d.ts +9 -0
- package/lib/commands/uninstall.js +145 -0
- package/lib/index.js +2 -1
- package/lib/templates/flatpak/desktop.tmpl +10 -0
- package/lib/templates/flatpak/flathub-app.json.tmpl +1 -0
- package/lib/templates/flatpak/flathub-cli.json.tmpl +3 -0
- package/lib/types/config-data.d.ts +193 -0
- package/package.json +16 -16
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from '../../types/index.js';
|
|
2
|
+
interface FlatpakCheckOptions {
|
|
3
|
+
manifest?: string;
|
|
4
|
+
repo?: string;
|
|
5
|
+
metainfo?: string;
|
|
6
|
+
appstream?: boolean;
|
|
7
|
+
builderLint?: boolean;
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const flatpakCheckCommand: Command<unknown, FlatpakCheckOptions>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// `gjsify flatpak check` — run Flathub's pre-submission linters locally.
|
|
2
|
+
//
|
|
3
|
+
// Wraps two tools:
|
|
4
|
+
// - `appstreamcli validate --strict <metainfo>` — MetaInfo XML
|
|
5
|
+
// correctness check
|
|
6
|
+
// - `flatpak-builder-lint manifest <manifest.json>` — manifest
|
|
7
|
+
// correctness check (and optionally `repo` for built artefacts)
|
|
8
|
+
//
|
|
9
|
+
// Both ship inside the `org.flatpak.Builder` flatpak. We exec them from
|
|
10
|
+
// the host PATH; if missing, print an install hint pointing at
|
|
11
|
+
// `flatpak install -y flathub org.flatpak.Builder`.
|
|
12
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
13
|
+
import { resolve, join } from 'node:path';
|
|
14
|
+
import { spawn } from 'node:child_process';
|
|
15
|
+
import { readPackageJson, looksLikeAppId } from './utils.js';
|
|
16
|
+
import { Config } from '../../config.js';
|
|
17
|
+
export const flatpakCheckCommand = {
|
|
18
|
+
command: 'check [manifest]',
|
|
19
|
+
description: 'Run Flathub pre-submission linters: appstreamcli validate + flatpak-builder-lint.',
|
|
20
|
+
builder: (yargs) => {
|
|
21
|
+
return yargs
|
|
22
|
+
.positional('manifest', {
|
|
23
|
+
description: 'Path to the Flatpak manifest. Auto-detects `<app-id>.json` if omitted.',
|
|
24
|
+
type: 'string',
|
|
25
|
+
normalize: true,
|
|
26
|
+
})
|
|
27
|
+
.option('repo', {
|
|
28
|
+
description: 'Built ostree-repo path. If given, also runs `flatpak-builder-lint repo`.',
|
|
29
|
+
type: 'string',
|
|
30
|
+
normalize: true,
|
|
31
|
+
})
|
|
32
|
+
.option('metainfo', {
|
|
33
|
+
description: 'MetaInfo XML path. Default: `data/<app-id>.metainfo.xml.in`.',
|
|
34
|
+
type: 'string',
|
|
35
|
+
normalize: true,
|
|
36
|
+
})
|
|
37
|
+
.option('appstream', {
|
|
38
|
+
description: 'Run `appstreamcli validate --strict` (default: true).',
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
default: true,
|
|
41
|
+
})
|
|
42
|
+
.option('builder-lint', {
|
|
43
|
+
description: 'Run `flatpak-builder-lint manifest` (default: true).',
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
default: true,
|
|
46
|
+
})
|
|
47
|
+
.option('verbose', {
|
|
48
|
+
description: 'Stream linter stdout/stderr verbatim.',
|
|
49
|
+
type: 'boolean',
|
|
50
|
+
default: false,
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
handler: async (args) => {
|
|
54
|
+
const cfg = new Config();
|
|
55
|
+
const configData = await cfg.forBuild({}).catch(() => ({}));
|
|
56
|
+
const flatpak = configData.flatpak ?? {};
|
|
57
|
+
const cwd = process.cwd();
|
|
58
|
+
const appId = resolveAppId(args.manifest, flatpak, cwd);
|
|
59
|
+
const manifestPath = resolveManifestPath(args.manifest, appId, cwd);
|
|
60
|
+
const metainfoPath = args.metainfo ?? `data/${appId ?? 'unknown'}.metainfo.xml.in`;
|
|
61
|
+
const metainfoAbs = resolve(cwd, metainfoPath);
|
|
62
|
+
let failures = 0;
|
|
63
|
+
if (args.appstream !== false) {
|
|
64
|
+
if (!existsSync(metainfoAbs)) {
|
|
65
|
+
console.warn(`[gjsify flatpak check] skipping appstreamcli — ${metainfoAbs} not found`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const ok = await runLinter('appstreamcli', ['validate', '--strict', metainfoAbs], args.verbose ?? false);
|
|
69
|
+
if (!ok)
|
|
70
|
+
failures++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (args.builderLint !== false) {
|
|
74
|
+
if (!existsSync(manifestPath)) {
|
|
75
|
+
console.error(`[gjsify flatpak check] manifest not found: ${manifestPath}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const ok = await runLinter('flatpak-builder-lint', ['manifest', manifestPath], args.verbose ?? false);
|
|
80
|
+
if (!ok)
|
|
81
|
+
failures++;
|
|
82
|
+
if (args.repo) {
|
|
83
|
+
const repoPath = resolve(cwd, args.repo);
|
|
84
|
+
const okRepo = await runLinter('flatpak-builder-lint', ['repo', repoPath], args.verbose ?? false);
|
|
85
|
+
if (!okRepo)
|
|
86
|
+
failures++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (failures > 0) {
|
|
90
|
+
console.error(`\n[gjsify flatpak check] ${failures} check(s) failed.`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
console.log('[gjsify flatpak check] all checks passed.');
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
function resolveAppId(explicit, flatpak, cwd) {
|
|
97
|
+
if (flatpak.appId)
|
|
98
|
+
return flatpak.appId;
|
|
99
|
+
try {
|
|
100
|
+
const pkg = readPackageJson(cwd);
|
|
101
|
+
if (looksLikeAppId(pkg.name))
|
|
102
|
+
return pkg.name;
|
|
103
|
+
}
|
|
104
|
+
catch { /* no pkg.json */ }
|
|
105
|
+
if (explicit) {
|
|
106
|
+
// strip `.json` extension if present
|
|
107
|
+
return explicit.replace(/\.json$/, '');
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
function resolveManifestPath(explicit, appId, cwd) {
|
|
112
|
+
if (explicit)
|
|
113
|
+
return resolve(cwd, explicit);
|
|
114
|
+
if (appId)
|
|
115
|
+
return resolve(cwd, `${appId}.json`);
|
|
116
|
+
// Last resort: find a single *.json that looks like a manifest
|
|
117
|
+
const candidates = readdirSync(cwd).filter((f) => f.endsWith('.json') && !f.startsWith('package'));
|
|
118
|
+
if (candidates.length === 1)
|
|
119
|
+
return resolve(cwd, candidates[0]);
|
|
120
|
+
throw new Error('gjsify flatpak check: no manifest path given and could not auto-detect. ' +
|
|
121
|
+
'Pass the manifest as a positional argument.');
|
|
122
|
+
}
|
|
123
|
+
function runLinter(bin, args, verbose) {
|
|
124
|
+
return new Promise((resolveP) => {
|
|
125
|
+
const child = spawn(bin, args, {
|
|
126
|
+
stdio: verbose ? 'inherit' : ['ignore', 'pipe', 'pipe'],
|
|
127
|
+
});
|
|
128
|
+
let stdout = '';
|
|
129
|
+
let stderr = '';
|
|
130
|
+
if (!verbose) {
|
|
131
|
+
child.stdout?.setEncoding('utf-8');
|
|
132
|
+
child.stderr?.setEncoding('utf-8');
|
|
133
|
+
child.stdout?.on('data', (c) => { stdout += c; });
|
|
134
|
+
child.stderr?.on('data', (c) => { stderr += c; });
|
|
135
|
+
}
|
|
136
|
+
child.on('error', (err) => {
|
|
137
|
+
const e = err;
|
|
138
|
+
if (e.code === 'ENOENT') {
|
|
139
|
+
console.error(`[gjsify flatpak check] ${bin} not found in PATH.\n` +
|
|
140
|
+
`Install via:\n` +
|
|
141
|
+
` flatpak install -y flathub org.flatpak.Builder\n` +
|
|
142
|
+
` alias ${bin}="flatpak run --command=${bin} org.flatpak.Builder"`);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.error(`[gjsify flatpak check] ${bin} failed to spawn: ${e.message}`);
|
|
146
|
+
}
|
|
147
|
+
resolveP(false);
|
|
148
|
+
});
|
|
149
|
+
child.on('exit', (code) => {
|
|
150
|
+
const ok = code === 0;
|
|
151
|
+
const tag = ok ? 'OK' : 'FAIL';
|
|
152
|
+
console.log(`[gjsify flatpak check] ${tag}: ${bin} ${args.join(' ')}`);
|
|
153
|
+
if (!ok && !verbose) {
|
|
154
|
+
if (stdout.trim())
|
|
155
|
+
console.log(stdout.trimEnd());
|
|
156
|
+
if (stderr.trim())
|
|
157
|
+
console.error(stderr.trimEnd());
|
|
158
|
+
}
|
|
159
|
+
resolveP(ok);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
void join;
|
|
@@ -3,5 +3,6 @@ import { flatpakInitCommand } from './init.js';
|
|
|
3
3
|
import { flatpakBuildCommand } from './build.js';
|
|
4
4
|
import { flatpakDepsCommand } from './deps.js';
|
|
5
5
|
import { flatpakCiCommand } from './ci.js';
|
|
6
|
+
import { flatpakCheckCommand } from './check.js';
|
|
6
7
|
export declare const flatpakCommand: Command;
|
|
7
|
-
export { flatpakInitCommand, flatpakBuildCommand, flatpakDepsCommand, flatpakCiCommand, };
|
|
8
|
+
export { flatpakInitCommand, flatpakBuildCommand, flatpakDepsCommand, flatpakCiCommand, flatpakCheckCommand, };
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
// `gjsify flatpak` — yargs subcommand-group dispatcher.
|
|
2
2
|
//
|
|
3
|
-
// Wires {init, build, deps, ci}. Each subcommand is a self-contained
|
|
3
|
+
// Wires {init, build, deps, ci, check}. Each subcommand is a self-contained
|
|
4
4
|
// `Command<>` so it composes the same way as `gresource` / `gettext` /
|
|
5
5
|
// `gsettings` at the top level.
|
|
6
6
|
import { flatpakInitCommand } from './init.js';
|
|
7
7
|
import { flatpakBuildCommand } from './build.js';
|
|
8
8
|
import { flatpakDepsCommand } from './deps.js';
|
|
9
9
|
import { flatpakCiCommand } from './ci.js';
|
|
10
|
+
import { flatpakCheckCommand } from './check.js';
|
|
10
11
|
export const flatpakCommand = {
|
|
11
12
|
command: 'flatpak <subcommand>',
|
|
12
|
-
description: 'Flatpak toolchain: init/build/deps/ci subcommands for shipping GJS apps and CLIs as Flatpaks.',
|
|
13
|
+
description: 'Flatpak toolchain: init/build/deps/ci/check subcommands for shipping GJS apps and CLIs as Flatpaks.',
|
|
13
14
|
builder: (yargs) => {
|
|
14
15
|
return yargs
|
|
15
16
|
.command(flatpakInitCommand.command, flatpakInitCommand.description, flatpakInitCommand.builder, flatpakInitCommand.handler)
|
|
16
17
|
.command(flatpakBuildCommand.command, flatpakBuildCommand.description, flatpakBuildCommand.builder, flatpakBuildCommand.handler)
|
|
17
18
|
.command(flatpakDepsCommand.command, flatpakDepsCommand.description, flatpakDepsCommand.builder, flatpakDepsCommand.handler)
|
|
18
19
|
.command(flatpakCiCommand.command, flatpakCiCommand.description, flatpakCiCommand.builder, flatpakCiCommand.handler)
|
|
20
|
+
.command(flatpakCheckCommand.command, flatpakCheckCommand.description, flatpakCheckCommand.builder, flatpakCheckCommand.handler)
|
|
19
21
|
.demandCommand(1)
|
|
20
22
|
.strict();
|
|
21
23
|
},
|
|
22
24
|
};
|
|
23
|
-
export { flatpakInitCommand, flatpakBuildCommand, flatpakDepsCommand, flatpakCiCommand, };
|
|
25
|
+
export { flatpakInitCommand, flatpakBuildCommand, flatpakDepsCommand, flatpakCiCommand, flatpakCheckCommand, };
|
|
@@ -3,8 +3,12 @@ interface FlatpakInitOptions {
|
|
|
3
3
|
appId?: string;
|
|
4
4
|
runtime?: string;
|
|
5
5
|
runtimeVersion?: string;
|
|
6
|
+
kind?: string;
|
|
6
7
|
cliOnly?: boolean;
|
|
7
8
|
manifest?: string;
|
|
9
|
+
metainfo?: string;
|
|
10
|
+
desktop?: string;
|
|
11
|
+
flathubJson?: string;
|
|
8
12
|
command?: string;
|
|
9
13
|
force?: boolean;
|
|
10
14
|
sdkExtension?: string[];
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
// `gjsify flatpak init` — generate a Flatpak manifest from package.json
|
|
2
|
-
// + the `gjsify.flatpak` config namespace.
|
|
2
|
+
// + the `gjsify.flatpak` config namespace, plus (Phase F.9) MetaInfo XML,
|
|
3
|
+
// `.desktop` (app kind only), and `flathub.json` policy stub in the same
|
|
4
|
+
// invocation.
|
|
3
5
|
//
|
|
4
6
|
// Defaults are designed for the two real-world shapes:
|
|
5
|
-
// * GTK4 + Adwaita apps (Learn6502): `gnome`
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
// * `--kind app` (default) — GTK4 + Adwaita apps (Learn6502): `gnome`
|
|
8
|
+
// runtime, GUI finish-args, desktop-application MetaInfo, .desktop +
|
|
9
|
+
// icon required.
|
|
10
|
+
// * `--kind cli` — headless CLI tools (ts-for-gir): same `gnome` runtime
|
|
11
|
+
// (GJS bundles need GLib/GIO at runtime — Freedesktop ships no GJS),
|
|
12
|
+
// but lean finish-args + console-application MetaInfo + flathub.json
|
|
13
|
+
// with `skip-icons-check`.
|
|
14
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { dirname, resolve } from 'node:path';
|
|
12
16
|
import { DEFAULT_CLI_FINISH_ARGS, DEFAULT_GUI_FINISH_ARGS, looksLikeAppId, readPackageJson, resolveRuntime, } from './utils.js';
|
|
17
|
+
import { renderDesktop, renderFlathubJson, renderMetainfoApp, renderMetainfoCli, validateScaffoldInputs, } from './scaffold.js';
|
|
13
18
|
import { Config } from '../../config.js';
|
|
14
19
|
export const flatpakInitCommand = {
|
|
15
20
|
command: 'init',
|
|
16
|
-
description: 'Generate
|
|
21
|
+
description: 'Generate Flatpak manifest + MetaInfo XML + .desktop + flathub.json from `gjsify.flatpak` config.',
|
|
17
22
|
builder: (yargs) => {
|
|
18
23
|
return yargs
|
|
19
24
|
.option('app-id', {
|
|
@@ -27,14 +32,33 @@ export const flatpakInitCommand = {
|
|
|
27
32
|
.option('runtime-version', {
|
|
28
33
|
description: 'Runtime version (default: gnome -> 50, freedesktop -> 24.08)',
|
|
29
34
|
type: 'string',
|
|
35
|
+
})
|
|
36
|
+
.option('kind', {
|
|
37
|
+
description: 'App kind: "app" (default, desktop) or "cli" (console-application MetaInfo, no .desktop)',
|
|
38
|
+
choices: ['app', 'cli'],
|
|
30
39
|
})
|
|
31
40
|
.option('cli-only', {
|
|
32
|
-
description: '
|
|
41
|
+
description: '(Deprecated) Alias for `--kind cli`. Use --kind instead.',
|
|
33
42
|
type: 'boolean',
|
|
34
43
|
default: false,
|
|
35
44
|
})
|
|
36
45
|
.option('manifest', {
|
|
37
|
-
description: 'Output path. Default: `<app-id>.json` in cwd.',
|
|
46
|
+
description: 'Output path for the manifest. Default: `<app-id>.json` in cwd.',
|
|
47
|
+
type: 'string',
|
|
48
|
+
normalize: true,
|
|
49
|
+
})
|
|
50
|
+
.option('metainfo', {
|
|
51
|
+
description: 'Output path for the MetaInfo XML. Default: `data/<app-id>.metainfo.xml.in` in cwd.',
|
|
52
|
+
type: 'string',
|
|
53
|
+
normalize: true,
|
|
54
|
+
})
|
|
55
|
+
.option('desktop', {
|
|
56
|
+
description: 'Output path for the .desktop entry (app kind only). Default: `data/<app-id>.desktop.in`.',
|
|
57
|
+
type: 'string',
|
|
58
|
+
normalize: true,
|
|
59
|
+
})
|
|
60
|
+
.option('flathub-json', {
|
|
61
|
+
description: 'Output path for the flathub.json policy stub. Default: `flathub.json` in cwd.',
|
|
38
62
|
type: 'string',
|
|
39
63
|
normalize: true,
|
|
40
64
|
})
|
|
@@ -53,7 +77,7 @@ export const flatpakInitCommand = {
|
|
|
53
77
|
array: true,
|
|
54
78
|
})
|
|
55
79
|
.option('force', {
|
|
56
|
-
description: 'Overwrite
|
|
80
|
+
description: 'Overwrite existing output files (manifest, metainfo, desktop, flathub.json)',
|
|
57
81
|
type: 'boolean',
|
|
58
82
|
default: false,
|
|
59
83
|
})
|
|
@@ -76,6 +100,9 @@ export const flatpakInitCommand = {
|
|
|
76
100
|
throw new Error('gjsify flatpak init: no app id available. Pass --app-id, set gjsify.flatpak.appId in package.json, ' +
|
|
77
101
|
'or rename the package to a reverse-DNS id like org.example.MyApp.');
|
|
78
102
|
}
|
|
103
|
+
const kind = args.kind ??
|
|
104
|
+
flatpak.kind ??
|
|
105
|
+
(args.cliOnly ? 'cli' : 'app');
|
|
79
106
|
const { runtime, runtimeId, sdk, runtimeVersion } = resolveRuntime(flatpak, {
|
|
80
107
|
runtime: args.runtime,
|
|
81
108
|
runtimeVersion: args.runtimeVersion,
|
|
@@ -84,11 +111,10 @@ export const flatpakInitCommand = {
|
|
|
84
111
|
const appendPath = flatpak.appendPath ?? (sdkExtensions?.length ? deriveAppendPath(sdkExtensions) : undefined);
|
|
85
112
|
const command = args.command ?? flatpak.command ?? appId;
|
|
86
113
|
const explicitFinishArgs = args.finishArg;
|
|
87
|
-
const cliOnly = args.cliOnly === true;
|
|
88
114
|
const finishArgs = explicitFinishArgs !== undefined
|
|
89
115
|
? explicitFinishArgs
|
|
90
116
|
: flatpak.finishArgs ??
|
|
91
|
-
(
|
|
117
|
+
(kind === 'cli' ? DEFAULT_CLI_FINISH_ARGS : DEFAULT_GUI_FINISH_ARGS);
|
|
92
118
|
const manifest = {
|
|
93
119
|
id: appId,
|
|
94
120
|
runtime: runtimeId,
|
|
@@ -105,8 +131,6 @@ export const flatpakInitCommand = {
|
|
|
105
131
|
const cleanup = flatpak.cleanup;
|
|
106
132
|
if (cleanup?.length)
|
|
107
133
|
manifest.cleanup = cleanup;
|
|
108
|
-
// Modules: caller-supplied `extraModules` first, then the app's own
|
|
109
|
-
// meson module pointing at the source dir.
|
|
110
134
|
const modules = [];
|
|
111
135
|
if (flatpak.extraModules?.length)
|
|
112
136
|
modules.push(...flatpak.extraModules);
|
|
@@ -116,27 +140,71 @@ export const flatpakInitCommand = {
|
|
|
116
140
|
sources: [{ type: 'dir', path: '.' }],
|
|
117
141
|
});
|
|
118
142
|
manifest.modules = modules;
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
const manifestOut = args.manifest ?? `${appId}.json`;
|
|
144
|
+
const manifestPath = resolve(cwd, manifestOut);
|
|
145
|
+
writeIfFresh(manifestPath, JSON.stringify(manifest, null, 4) + '\n', args.force ?? false, 'manifest');
|
|
146
|
+
const name = pkg.name ?? appId;
|
|
147
|
+
const scaffold = {
|
|
148
|
+
appId,
|
|
149
|
+
name: friendlyName(name, appId),
|
|
150
|
+
command,
|
|
151
|
+
kind,
|
|
152
|
+
flatpak,
|
|
153
|
+
};
|
|
154
|
+
const missing = validateScaffoldInputs(scaffold);
|
|
155
|
+
if (missing.length > 0) {
|
|
156
|
+
console.warn('[gjsify flatpak init] Manifest written, but MetaInfo / .desktop are skipped — config gaps:');
|
|
157
|
+
for (const m of missing)
|
|
158
|
+
console.warn(` - ${m.field}: ${m.hint}`);
|
|
159
|
+
console.warn('\nFill these fields in package.json#gjsify.flatpak (or .gjsifyrc.*) and re-run with --force.');
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
const metainfoXml = kind === 'cli' ? renderMetainfoCli(scaffold) : renderMetainfoApp(scaffold);
|
|
163
|
+
const metainfoOut = args.metainfo ?? `data/${appId}.metainfo.xml.in`;
|
|
164
|
+
writeIfFresh(resolve(cwd, metainfoOut), metainfoXml, args.force ?? false, 'metainfo');
|
|
165
|
+
if (kind === 'app') {
|
|
166
|
+
const desktopOut = args.desktop ?? `data/${appId}.desktop.in`;
|
|
167
|
+
writeIfFresh(resolve(cwd, desktopOut), renderDesktop(scaffold), args.force ?? false, 'desktop');
|
|
168
|
+
if (!flatpak.icon) {
|
|
169
|
+
console.warn(`[gjsify flatpak init] No gjsify.flatpak.icon set. Flathub requires a scalable SVG at\n` +
|
|
170
|
+
` data/icons/hicolor/scalable/apps/${appId}.svg`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const flathubOut = args.flathubJson ?? 'flathub.json';
|
|
174
|
+
writeIfFresh(resolve(cwd, flathubOut), renderFlathubJson(kind), args.force ?? false, 'flathub.json');
|
|
123
175
|
}
|
|
124
|
-
const json = JSON.stringify(manifest, null, 4) + '\n';
|
|
125
|
-
writeFileSync(outPath, json, 'utf-8');
|
|
126
176
|
if (args.verbose) {
|
|
127
|
-
console.log(`[gjsify flatpak init] runtime=${runtimeId} ${runtimeVersion} sdk=${sdk}`);
|
|
177
|
+
console.log(`[gjsify flatpak init] kind=${kind} runtime=${runtimeId} ${runtimeVersion} sdk=${sdk}`);
|
|
128
178
|
console.log(`[gjsify flatpak init] command=${command} finish-args=${JSON.stringify(finishArgs)}`);
|
|
179
|
+
void runtime;
|
|
129
180
|
}
|
|
130
|
-
console.log(`[gjsify flatpak init] wrote ${outPath}`);
|
|
131
181
|
},
|
|
132
182
|
};
|
|
133
|
-
|
|
183
|
+
function writeIfFresh(path, content, force, label) {
|
|
184
|
+
if (existsSync(path) && !force) {
|
|
185
|
+
console.log(`[gjsify flatpak init] skipped ${label}: ${path} (exists; --force to overwrite)`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
189
|
+
writeFileSync(path, content, 'utf-8');
|
|
190
|
+
console.log(`[gjsify flatpak init] wrote ${label}: ${path}`);
|
|
191
|
+
}
|
|
192
|
+
function friendlyName(pkgName, appId) {
|
|
193
|
+
if (pkgName.startsWith('@')) {
|
|
194
|
+
const base = pkgName.slice(pkgName.indexOf('/') + 1);
|
|
195
|
+
return base;
|
|
196
|
+
}
|
|
197
|
+
if (pkgName === appId) {
|
|
198
|
+
const segs = appId.split('.');
|
|
199
|
+
return segs[segs.length - 1] ?? appId;
|
|
200
|
+
}
|
|
201
|
+
return pkgName;
|
|
202
|
+
}
|
|
134
203
|
function mergeArrays(a, b) {
|
|
135
204
|
if (!a?.length && !b?.length)
|
|
136
205
|
return undefined;
|
|
137
206
|
return [...(a ?? []), ...(b ?? [])];
|
|
138
207
|
}
|
|
139
|
-
/** Map known SDK extension ids to their /usr/lib/sdk/<name>/bin paths. */
|
|
140
208
|
function deriveAppendPath(sdkExtensions) {
|
|
141
209
|
const out = [];
|
|
142
210
|
for (const ext of sdkExtensions) {
|
|
@@ -147,7 +215,6 @@ function deriveAppendPath(sdkExtensions) {
|
|
|
147
215
|
out.push('/app/bin');
|
|
148
216
|
return out;
|
|
149
217
|
}
|
|
150
|
-
/** Last segment of the reverse-DNS id, used as the meson-module name. */
|
|
151
218
|
function deriveModuleName(appId) {
|
|
152
219
|
const parts = appId.split('.');
|
|
153
220
|
return parts[parts.length - 1] || appId;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ConfigDataFlatpak } from '../../types/config-data.js';
|
|
2
|
+
export interface ScaffoldInputs {
|
|
3
|
+
appId: string;
|
|
4
|
+
name: string;
|
|
5
|
+
command: string;
|
|
6
|
+
kind: 'app' | 'cli';
|
|
7
|
+
flatpak: ConfigDataFlatpak;
|
|
8
|
+
}
|
|
9
|
+
export interface MissingFieldError {
|
|
10
|
+
field: string;
|
|
11
|
+
hint: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Validate that the config has the minimum set of fields required for
|
|
15
|
+
* MetaInfo XML rendering. Returns the list of missing fields with
|
|
16
|
+
* actionable hints; empty list means OK.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateScaffoldInputs(inputs: ScaffoldInputs): MissingFieldError[];
|
|
19
|
+
/** Render the MetaInfo XML for a desktop application. */
|
|
20
|
+
export declare function renderMetainfoApp(inputs: ScaffoldInputs): string;
|
|
21
|
+
/** Render the MetaInfo XML for a console application. */
|
|
22
|
+
export declare function renderMetainfoCli(inputs: ScaffoldInputs): string;
|
|
23
|
+
/** Render the .desktop entry (app kind only). */
|
|
24
|
+
export declare function renderDesktop(inputs: ScaffoldInputs): string;
|
|
25
|
+
/** Render the flathub.json policy file. */
|
|
26
|
+
export declare function renderFlathubJson(kind: 'app' | 'cli'): string;
|