@gjsify/cli 0.3.20 → 0.4.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 +798 -0
- package/lib/actions/build.js +4 -17
- package/lib/bundler-pick.d.ts +79 -0
- package/lib/bundler-pick.js +428 -0
- package/lib/commands/foreach.d.ts +16 -0
- package/lib/commands/foreach.js +268 -0
- package/lib/commands/index.d.ts +2 -0
- package/lib/commands/index.js +2 -0
- package/lib/commands/install.d.ts +1 -0
- package/lib/commands/install.js +222 -26
- package/lib/commands/run.d.ts +1 -1
- package/lib/commands/run.js +133 -20
- package/lib/commands/workspace.d.ts +8 -0
- package/lib/commands/workspace.js +69 -0
- package/lib/config.js +26 -0
- package/lib/index.js +11 -3
- package/lib/types/config-data.d.ts +10 -1
- package/lib/utils/install-backend-native.d.ts +5 -1
- package/lib/utils/install-backend-native.js +88 -11
- package/lib/utils/install-backend.d.ts +11 -1
- package/lib/utils/install-backend.js +4 -2
- package/lib/utils/pkg-json-edit.d.ts +47 -0
- package/lib/utils/pkg-json-edit.js +108 -0
- package/package.json +36 -12
- package/src/actions/build.ts +0 -431
- package/src/actions/index.ts +0 -1
- package/src/commands/build.ts +0 -146
- package/src/commands/check.ts +0 -87
- package/src/commands/create.ts +0 -63
- package/src/commands/dlx.ts +0 -195
- package/src/commands/flatpak/build.ts +0 -225
- package/src/commands/flatpak/ci.ts +0 -173
- package/src/commands/flatpak/deps.ts +0 -120
- package/src/commands/flatpak/index.ts +0 -53
- package/src/commands/flatpak/init.ts +0 -191
- package/src/commands/flatpak/utils.ts +0 -76
- package/src/commands/gettext.ts +0 -258
- package/src/commands/gresource.ts +0 -97
- package/src/commands/gsettings.ts +0 -87
- package/src/commands/index.ts +0 -12
- package/src/commands/info.ts +0 -70
- package/src/commands/install.ts +0 -195
- package/src/commands/run.ts +0 -33
- package/src/commands/showcase.ts +0 -149
- package/src/config.ts +0 -289
- package/src/constants.ts +0 -1
- package/src/index.ts +0 -37
- package/src/types/cli-build-options.ts +0 -100
- package/src/types/command.ts +0 -10
- package/src/types/config-data-library.ts +0 -5
- package/src/types/config-data-typescript.ts +0 -6
- package/src/types/config-data.ts +0 -225
- package/src/types/cosmiconfig-result.ts +0 -5
- package/src/types/index.ts +0 -6
- package/src/utils/check-system-deps.ts +0 -480
- package/src/utils/detect-native-packages.ts +0 -153
- package/src/utils/discover-showcases.ts +0 -75
- package/src/utils/dlx-cache.ts +0 -135
- package/src/utils/install-backend-native.ts +0 -363
- package/src/utils/install-backend.ts +0 -88
- package/src/utils/install-global.ts +0 -182
- package/src/utils/normalize-bundler-options.ts +0 -129
- package/src/utils/parse-spec.ts +0 -48
- package/src/utils/resolve-gjs-entry.ts +0 -96
- package/src/utils/resolve-plugin-by-name.ts +0 -106
- package/src/utils/run-gjs.ts +0 -90
- package/tsconfig.json +0 -16
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
// `gjsify flatpak ci` — scaffold .github/workflows/flatpak.yml in the
|
|
2
|
-
// shape used by Flathub-hosted apps:
|
|
3
|
-
//
|
|
4
|
-
// * upstream `flatpak/flatpak-github-actions/flatpak-builder@v6` action
|
|
5
|
-
// * `ghcr.io/flathub-infra/flatpak-github-actions:<runtime>-<version>` container
|
|
6
|
-
// * cache key keyed by commit SHA
|
|
7
|
-
//
|
|
8
|
-
// Idempotent: refuses to overwrite an existing workflow without `--force`.
|
|
9
|
-
|
|
10
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
|
-
import { dirname, resolve } from 'node:path';
|
|
12
|
-
import type { Command, ConfigData, ConfigDataFlatpak } from '../../types/index.js';
|
|
13
|
-
import { Config } from '../../config.js';
|
|
14
|
-
import { defaultCiContainer, looksLikeAppId, readPackageJson, resolveRuntime } from './utils.js';
|
|
15
|
-
|
|
16
|
-
interface FlatpakCiOptions {
|
|
17
|
-
manifest?: string;
|
|
18
|
-
bundle?: string;
|
|
19
|
-
runtimeImage?: string;
|
|
20
|
-
branches?: string[];
|
|
21
|
-
out?: string;
|
|
22
|
-
force?: boolean;
|
|
23
|
-
cacheKey?: string;
|
|
24
|
-
verbose?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const flatpakCiCommand: Command<unknown, FlatpakCiOptions> = {
|
|
28
|
-
command: 'ci',
|
|
29
|
-
description:
|
|
30
|
-
'Scaffold .github/workflows/flatpak.yml using the flathub-infra container + flatpak-builder@v6 action.',
|
|
31
|
-
builder: (yargs) => {
|
|
32
|
-
return yargs
|
|
33
|
-
.option('manifest', {
|
|
34
|
-
description: 'Manifest path the workflow points at (default: <app-id>.json)',
|
|
35
|
-
type: 'string',
|
|
36
|
-
normalize: true,
|
|
37
|
-
})
|
|
38
|
-
.option('bundle', {
|
|
39
|
-
description: 'Bundle filename produced by the action (default: <app-id>.flatpak)',
|
|
40
|
-
type: 'string',
|
|
41
|
-
normalize: true,
|
|
42
|
-
})
|
|
43
|
-
.option('runtime-image', {
|
|
44
|
-
description:
|
|
45
|
-
'Container image override. Default derived from gjsify.flatpak.runtime + runtimeVersion (e.g. `ghcr.io/flathub-infra/flatpak-github-actions:gnome-50`).',
|
|
46
|
-
type: 'string',
|
|
47
|
-
})
|
|
48
|
-
.option('branches', {
|
|
49
|
-
description: 'Branches the workflow runs on push for (default: main)',
|
|
50
|
-
type: 'string',
|
|
51
|
-
array: true,
|
|
52
|
-
})
|
|
53
|
-
.option('out', {
|
|
54
|
-
description: 'Output path',
|
|
55
|
-
type: 'string',
|
|
56
|
-
default: '.github/workflows/flatpak.yml',
|
|
57
|
-
normalize: true,
|
|
58
|
-
})
|
|
59
|
-
.option('cache-key', {
|
|
60
|
-
description: 'Override the action `cache-key` (default: `flatpak-builder-${{ github.sha }}`)',
|
|
61
|
-
type: 'string',
|
|
62
|
-
})
|
|
63
|
-
.option('force', {
|
|
64
|
-
description: 'Overwrite an existing workflow file',
|
|
65
|
-
type: 'boolean',
|
|
66
|
-
default: false,
|
|
67
|
-
})
|
|
68
|
-
.option('verbose', {
|
|
69
|
-
description: 'Print resolved fields',
|
|
70
|
-
type: 'boolean',
|
|
71
|
-
default: false,
|
|
72
|
-
});
|
|
73
|
-
},
|
|
74
|
-
handler: async (args) => {
|
|
75
|
-
const cwd = process.cwd();
|
|
76
|
-
const cfg = new Config();
|
|
77
|
-
const configData = await cfg.forBuild({} as never).catch(() => ({} as ConfigData));
|
|
78
|
-
const flatpak: ConfigDataFlatpak = configData.flatpak ?? {};
|
|
79
|
-
const pkg = readPackageJson(cwd);
|
|
80
|
-
|
|
81
|
-
const appId =
|
|
82
|
-
flatpak.appId ??
|
|
83
|
-
(looksLikeAppId(pkg.name) ? (pkg.name as string) : undefined);
|
|
84
|
-
if (!appId) {
|
|
85
|
-
throw new Error(
|
|
86
|
-
'gjsify flatpak ci: no app id available. Set gjsify.flatpak.appId in package.json ' +
|
|
87
|
-
'or rename the package to a reverse-DNS id.',
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const manifest = (args.manifest as string | undefined) ?? `${appId}.json`;
|
|
92
|
-
const bundle = (args.bundle as string | undefined) ?? `${appId}.flatpak`;
|
|
93
|
-
|
|
94
|
-
const { runtime, runtimeVersion } = resolveRuntime(flatpak, {});
|
|
95
|
-
const runtimeImage =
|
|
96
|
-
(args.runtimeImage as string | undefined) ??
|
|
97
|
-
flatpak.ciContainer ??
|
|
98
|
-
defaultCiContainer(runtime, runtimeVersion);
|
|
99
|
-
|
|
100
|
-
const branches = (args.branches as string[] | undefined) ?? flatpak.ciBranches ?? ['main'];
|
|
101
|
-
const cacheKey = args.cacheKey ?? 'flatpak-builder-${{ github.sha }}';
|
|
102
|
-
|
|
103
|
-
const out = resolve(cwd, args.out ?? '.github/workflows/flatpak.yml');
|
|
104
|
-
if (existsSync(out) && !args.force) {
|
|
105
|
-
// Same content → silently skip; different content → fail with a hint.
|
|
106
|
-
const existing = readFileSync(out, 'utf-8');
|
|
107
|
-
const next = renderWorkflow({ manifest, bundle, runtimeImage, branches, cacheKey });
|
|
108
|
-
if (existing === next) {
|
|
109
|
-
console.log(`[gjsify flatpak ci] ${out} already up to date`);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
throw new Error(
|
|
113
|
-
`gjsify flatpak ci: ${out} exists with different content. Pass --force to overwrite.`,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const content = renderWorkflow({ manifest, bundle, runtimeImage, branches, cacheKey });
|
|
118
|
-
mkdirSync(dirname(out), { recursive: true });
|
|
119
|
-
writeFileSync(out, content, 'utf-8');
|
|
120
|
-
|
|
121
|
-
if (args.verbose) {
|
|
122
|
-
console.log(
|
|
123
|
-
`[gjsify flatpak ci] runtime-image=${runtimeImage} manifest=${manifest} bundle=${bundle}`,
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
console.log(`[gjsify flatpak ci] wrote ${out}`);
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
interface RenderInput {
|
|
131
|
-
manifest: string;
|
|
132
|
-
bundle: string;
|
|
133
|
-
runtimeImage: string;
|
|
134
|
-
branches: string[];
|
|
135
|
-
cacheKey: string;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Render the workflow YAML. Format string built explicitly (no template
|
|
140
|
-
* library) so the output is byte-stable for diff-based code review.
|
|
141
|
-
*/
|
|
142
|
-
function renderWorkflow(input: RenderInput): string {
|
|
143
|
-
const branchesYaml = `[${input.branches.map((b) => JSON.stringify(b)).join(', ')}]`;
|
|
144
|
-
return `name: Flatpak
|
|
145
|
-
|
|
146
|
-
on:
|
|
147
|
-
push:
|
|
148
|
-
branches: ${branchesYaml}
|
|
149
|
-
pull_request:
|
|
150
|
-
branches: ${branchesYaml}
|
|
151
|
-
|
|
152
|
-
jobs:
|
|
153
|
-
flatpak:
|
|
154
|
-
name: Flatpak Build
|
|
155
|
-
runs-on: ubuntu-latest
|
|
156
|
-
container:
|
|
157
|
-
image: ${input.runtimeImage}
|
|
158
|
-
options: --privileged
|
|
159
|
-
|
|
160
|
-
steps:
|
|
161
|
-
- name: Checkout repository
|
|
162
|
-
uses: actions/checkout@v4
|
|
163
|
-
with:
|
|
164
|
-
submodules: false
|
|
165
|
-
|
|
166
|
-
- name: Build Flatpak
|
|
167
|
-
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
|
168
|
-
with:
|
|
169
|
-
manifest-path: ${input.manifest}
|
|
170
|
-
bundle: ${input.bundle}
|
|
171
|
-
cache-key: ${input.cacheKey}
|
|
172
|
-
`;
|
|
173
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// `gjsify flatpak deps` — wrap `flatpak-node-generator` to convert a
|
|
2
|
-
// yarn.lock / package-lock.json into the JSON sources file that the
|
|
3
|
-
// Flatpak manifest references for offline `yarn install` inside the
|
|
4
|
-
// build sandbox.
|
|
5
|
-
//
|
|
6
|
-
// flatpak-node-generator is a Python tool from
|
|
7
|
-
// https://github.com/flatpak/flatpak-builder-tools — installed via
|
|
8
|
-
// `pipx install flatpak-node-generator` or `pip install --user
|
|
9
|
-
// flatpak-node-generator`.
|
|
10
|
-
|
|
11
|
-
import { spawn } from 'node:child_process';
|
|
12
|
-
import { existsSync } from 'node:fs';
|
|
13
|
-
import { dirname, resolve } from 'node:path';
|
|
14
|
-
import { mkdirSync } from 'node:fs';
|
|
15
|
-
import type { Command } from '../../types/index.js';
|
|
16
|
-
|
|
17
|
-
interface FlatpakDepsOptions {
|
|
18
|
-
lockfile?: string;
|
|
19
|
-
type?: 'yarn' | 'npm';
|
|
20
|
-
out?: string;
|
|
21
|
-
xdgLayout?: boolean;
|
|
22
|
-
nodeChromedriverFromElectron?: string;
|
|
23
|
-
electronNodeHeaders?: boolean;
|
|
24
|
-
verbose?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const flatpakDepsCommand: Command<unknown, FlatpakDepsOptions> = {
|
|
28
|
-
command: 'deps',
|
|
29
|
-
description:
|
|
30
|
-
'Generate Flatpak offline-cache sources from a yarn.lock / package-lock.json (wraps `flatpak-node-generator`).',
|
|
31
|
-
builder: (yargs) => {
|
|
32
|
-
return yargs
|
|
33
|
-
.option('lockfile', {
|
|
34
|
-
description: 'Path to lockfile (default: yarn.lock or package-lock.json in cwd)',
|
|
35
|
-
type: 'string',
|
|
36
|
-
normalize: true,
|
|
37
|
-
})
|
|
38
|
-
.option('type', {
|
|
39
|
-
description: 'Lockfile type. Default: detected from filename.',
|
|
40
|
-
choices: ['yarn', 'npm'] as const,
|
|
41
|
-
})
|
|
42
|
-
.option('out', {
|
|
43
|
-
description: 'Output JSON sources file',
|
|
44
|
-
type: 'string',
|
|
45
|
-
default: 'flatpak-node-sources.json',
|
|
46
|
-
normalize: true,
|
|
47
|
-
})
|
|
48
|
-
.option('xdg-layout', {
|
|
49
|
-
description: 'Pass --xdg-layout (recommended for Yarn Berry / PnP setups)',
|
|
50
|
-
type: 'boolean',
|
|
51
|
-
default: true,
|
|
52
|
-
})
|
|
53
|
-
.option('electron-node-headers', {
|
|
54
|
-
description: 'Pass --electron-node-headers',
|
|
55
|
-
type: 'boolean',
|
|
56
|
-
default: false,
|
|
57
|
-
})
|
|
58
|
-
.option('verbose', {
|
|
59
|
-
description: 'Print the underlying flatpak-node-generator invocation',
|
|
60
|
-
type: 'boolean',
|
|
61
|
-
default: false,
|
|
62
|
-
});
|
|
63
|
-
},
|
|
64
|
-
handler: async (args) => {
|
|
65
|
-
const cwd = process.cwd();
|
|
66
|
-
const lockfile = resolve(
|
|
67
|
-
cwd,
|
|
68
|
-
(args.lockfile as string | undefined) ?? detectLockfile(cwd),
|
|
69
|
-
);
|
|
70
|
-
if (!existsSync(lockfile)) {
|
|
71
|
-
throw new Error(
|
|
72
|
-
`gjsify flatpak deps: lockfile ${lockfile} not found (use --lockfile to override)`,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const type =
|
|
77
|
-
(args.type as 'yarn' | 'npm' | undefined) ??
|
|
78
|
-
(lockfile.endsWith('package-lock.json') ? 'npm' : 'yarn');
|
|
79
|
-
|
|
80
|
-
const out = resolve(cwd, args.out ?? 'flatpak-node-sources.json');
|
|
81
|
-
mkdirSync(dirname(out), { recursive: true });
|
|
82
|
-
|
|
83
|
-
const cmdArgs = [type, lockfile, '-o', out];
|
|
84
|
-
if (args.xdgLayout !== false) cmdArgs.push('--xdg-layout');
|
|
85
|
-
if (args.electronNodeHeaders) cmdArgs.push('--electron-node-headers');
|
|
86
|
-
|
|
87
|
-
if (args.verbose) {
|
|
88
|
-
console.log(`[gjsify flatpak deps] flatpak-node-generator ${cmdArgs.join(' ')}`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
await new Promise<void>((res, rej) => {
|
|
92
|
-
const child = spawn('flatpak-node-generator', cmdArgs, { stdio: 'inherit' });
|
|
93
|
-
child.on('error', (err: NodeJS.ErrnoException) => {
|
|
94
|
-
if (err.code === 'ENOENT') {
|
|
95
|
-
rej(
|
|
96
|
-
new Error(
|
|
97
|
-
'gjsify flatpak deps: flatpak-node-generator not found. ' +
|
|
98
|
-
'Install via `pipx install flatpak-node-generator` ' +
|
|
99
|
-
'(see https://github.com/flatpak/flatpak-builder-tools/tree/master/node).',
|
|
100
|
-
),
|
|
101
|
-
);
|
|
102
|
-
} else {
|
|
103
|
-
rej(err);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
child.on('exit', (code) => {
|
|
107
|
-
if (code === 0) res();
|
|
108
|
-
else rej(new Error(`gjsify flatpak deps: flatpak-node-generator exited with status ${code}`));
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
console.log(`[gjsify flatpak deps] wrote ${out}`);
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
function detectLockfile(cwd: string): string {
|
|
117
|
-
if (existsSync(resolve(cwd, 'yarn.lock'))) return 'yarn.lock';
|
|
118
|
-
if (existsSync(resolve(cwd, 'package-lock.json'))) return 'package-lock.json';
|
|
119
|
-
return 'yarn.lock'; // surfaces a clear "not found" later
|
|
120
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// `gjsify flatpak` — yargs subcommand-group dispatcher.
|
|
2
|
-
//
|
|
3
|
-
// Wires {init, build, deps, ci}. Each subcommand is a self-contained
|
|
4
|
-
// `Command<>` so it composes the same way as `gresource` / `gettext` /
|
|
5
|
-
// `gsettings` at the top level.
|
|
6
|
-
|
|
7
|
-
import type { Command } from '../../types/index.js';
|
|
8
|
-
import { flatpakInitCommand } from './init.js';
|
|
9
|
-
import { flatpakBuildCommand } from './build.js';
|
|
10
|
-
import { flatpakDepsCommand } from './deps.js';
|
|
11
|
-
import { flatpakCiCommand } from './ci.js';
|
|
12
|
-
|
|
13
|
-
export const flatpakCommand: Command = {
|
|
14
|
-
command: 'flatpak <subcommand>',
|
|
15
|
-
description:
|
|
16
|
-
'Flatpak toolchain: init/build/deps/ci subcommands for shipping GJS apps and CLIs as Flatpaks.',
|
|
17
|
-
builder: (yargs) => {
|
|
18
|
-
return yargs
|
|
19
|
-
.command(
|
|
20
|
-
flatpakInitCommand.command as string,
|
|
21
|
-
flatpakInitCommand.description,
|
|
22
|
-
flatpakInitCommand.builder!,
|
|
23
|
-
flatpakInitCommand.handler!,
|
|
24
|
-
)
|
|
25
|
-
.command(
|
|
26
|
-
flatpakBuildCommand.command as string,
|
|
27
|
-
flatpakBuildCommand.description,
|
|
28
|
-
flatpakBuildCommand.builder!,
|
|
29
|
-
flatpakBuildCommand.handler!,
|
|
30
|
-
)
|
|
31
|
-
.command(
|
|
32
|
-
flatpakDepsCommand.command as string,
|
|
33
|
-
flatpakDepsCommand.description,
|
|
34
|
-
flatpakDepsCommand.builder!,
|
|
35
|
-
flatpakDepsCommand.handler!,
|
|
36
|
-
)
|
|
37
|
-
.command(
|
|
38
|
-
flatpakCiCommand.command as string,
|
|
39
|
-
flatpakCiCommand.description,
|
|
40
|
-
flatpakCiCommand.builder!,
|
|
41
|
-
flatpakCiCommand.handler!,
|
|
42
|
-
)
|
|
43
|
-
.demandCommand(1)
|
|
44
|
-
.strict();
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export {
|
|
49
|
-
flatpakInitCommand,
|
|
50
|
-
flatpakBuildCommand,
|
|
51
|
-
flatpakDepsCommand,
|
|
52
|
-
flatpakCiCommand,
|
|
53
|
-
};
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
// `gjsify flatpak init` — generate a Flatpak manifest from package.json
|
|
2
|
-
// + the `gjsify.flatpak` config namespace.
|
|
3
|
-
//
|
|
4
|
-
// Defaults are designed for the two real-world shapes:
|
|
5
|
-
// * GTK4 + Adwaita apps (Learn6502): `gnome` runtime, GUI finish-args
|
|
6
|
-
// * Headless CLI tools (ts-for-gir): same `gnome` runtime (GJS bundles
|
|
7
|
-
// need GLib/GIO at runtime — Freedesktop ships no GJS), but lean
|
|
8
|
-
// finish-args via `--cli-only`. Memory file
|
|
9
|
-
// `project_flatpak_runtime_choice.md` documents this trade-off.
|
|
10
|
-
|
|
11
|
-
import { existsSync, writeFileSync } from 'node:fs';
|
|
12
|
-
import { resolve } from 'node:path';
|
|
13
|
-
import type { Command, ConfigData, ConfigDataFlatpak } from '../../types/index.js';
|
|
14
|
-
import {
|
|
15
|
-
DEFAULT_CLI_FINISH_ARGS,
|
|
16
|
-
DEFAULT_GUI_FINISH_ARGS,
|
|
17
|
-
looksLikeAppId,
|
|
18
|
-
readPackageJson,
|
|
19
|
-
resolveRuntime,
|
|
20
|
-
} from './utils.js';
|
|
21
|
-
import { Config } from '../../config.js';
|
|
22
|
-
|
|
23
|
-
interface FlatpakInitOptions {
|
|
24
|
-
appId?: string;
|
|
25
|
-
runtime?: string;
|
|
26
|
-
runtimeVersion?: string;
|
|
27
|
-
cliOnly?: boolean;
|
|
28
|
-
manifest?: string;
|
|
29
|
-
command?: string;
|
|
30
|
-
force?: boolean;
|
|
31
|
-
sdkExtension?: string[];
|
|
32
|
-
finishArg?: string[];
|
|
33
|
-
verbose?: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const flatpakInitCommand: Command<unknown, FlatpakInitOptions> = {
|
|
37
|
-
command: 'init',
|
|
38
|
-
description:
|
|
39
|
-
'Generate a Flatpak manifest from package.json + `gjsify.flatpak` config.',
|
|
40
|
-
builder: (yargs) => {
|
|
41
|
-
return yargs
|
|
42
|
-
.option('app-id', {
|
|
43
|
-
description: 'Reverse-DNS app id (default: `gjsify.flatpak.appId` or package.json#name)',
|
|
44
|
-
type: 'string',
|
|
45
|
-
})
|
|
46
|
-
.option('runtime', {
|
|
47
|
-
description: 'Runtime family',
|
|
48
|
-
choices: ['gnome', 'freedesktop'] as const,
|
|
49
|
-
})
|
|
50
|
-
.option('runtime-version', {
|
|
51
|
-
description: 'Runtime version (default: gnome -> 50, freedesktop -> 24.08)',
|
|
52
|
-
type: 'string',
|
|
53
|
-
})
|
|
54
|
-
.option('cli-only', {
|
|
55
|
-
description: 'Strip GUI finish-args; keep `gnome` runtime so GJS is available at runtime',
|
|
56
|
-
type: 'boolean',
|
|
57
|
-
default: false,
|
|
58
|
-
})
|
|
59
|
-
.option('manifest', {
|
|
60
|
-
description: 'Output path. Default: `<app-id>.json` in cwd.',
|
|
61
|
-
type: 'string',
|
|
62
|
-
normalize: true,
|
|
63
|
-
})
|
|
64
|
-
.option('command', {
|
|
65
|
-
description: 'Binary name in /app/bin (default: app id)',
|
|
66
|
-
type: 'string',
|
|
67
|
-
})
|
|
68
|
-
.option('sdk-extension', {
|
|
69
|
-
description: 'Extra SDK extension (repeatable)',
|
|
70
|
-
type: 'string',
|
|
71
|
-
array: true,
|
|
72
|
-
})
|
|
73
|
-
.option('finish-arg', {
|
|
74
|
-
description: 'Extra finish-arg (repeatable). Override defaults entirely with multiple --finish-arg.',
|
|
75
|
-
type: 'string',
|
|
76
|
-
array: true,
|
|
77
|
-
})
|
|
78
|
-
.option('force', {
|
|
79
|
-
description: 'Overwrite an existing manifest',
|
|
80
|
-
type: 'boolean',
|
|
81
|
-
default: false,
|
|
82
|
-
})
|
|
83
|
-
.option('verbose', {
|
|
84
|
-
description: 'Print the resolved manifest fields before writing',
|
|
85
|
-
type: 'boolean',
|
|
86
|
-
default: false,
|
|
87
|
-
});
|
|
88
|
-
},
|
|
89
|
-
handler: async (args) => {
|
|
90
|
-
const cfg = new Config();
|
|
91
|
-
const configData = await cfg.forBuild({} as never).catch(() => ({} as ConfigData));
|
|
92
|
-
const flatpak: ConfigDataFlatpak = configData.flatpak ?? {};
|
|
93
|
-
const cwd = process.cwd();
|
|
94
|
-
const pkg = readPackageJson(cwd);
|
|
95
|
-
|
|
96
|
-
const appId =
|
|
97
|
-
(args.appId as string | undefined) ??
|
|
98
|
-
flatpak.appId ??
|
|
99
|
-
(looksLikeAppId(pkg.name) ? (pkg.name as string) : undefined);
|
|
100
|
-
if (!appId) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
'gjsify flatpak init: no app id available. Pass --app-id, set gjsify.flatpak.appId in package.json, ' +
|
|
103
|
-
'or rename the package to a reverse-DNS id like org.example.MyApp.',
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const { runtime, runtimeId, sdk, runtimeVersion } = resolveRuntime(flatpak, {
|
|
108
|
-
runtime: args.runtime,
|
|
109
|
-
runtimeVersion: args.runtimeVersion,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const sdkExtensions = mergeArrays(flatpak.sdkExtensions, args.sdkExtension);
|
|
113
|
-
const appendPath = flatpak.appendPath ?? (sdkExtensions?.length ? deriveAppendPath(sdkExtensions) : undefined);
|
|
114
|
-
const command = (args.command as string | undefined) ?? flatpak.command ?? appId;
|
|
115
|
-
|
|
116
|
-
const explicitFinishArgs = args.finishArg as string[] | undefined;
|
|
117
|
-
const cliOnly = args.cliOnly === true;
|
|
118
|
-
const finishArgs =
|
|
119
|
-
explicitFinishArgs !== undefined
|
|
120
|
-
? explicitFinishArgs
|
|
121
|
-
: flatpak.finishArgs ??
|
|
122
|
-
(cliOnly ? DEFAULT_CLI_FINISH_ARGS : DEFAULT_GUI_FINISH_ARGS);
|
|
123
|
-
|
|
124
|
-
const manifest: Record<string, unknown> = {
|
|
125
|
-
id: appId,
|
|
126
|
-
runtime: runtimeId,
|
|
127
|
-
'runtime-version': runtimeVersion,
|
|
128
|
-
sdk,
|
|
129
|
-
};
|
|
130
|
-
if (sdkExtensions?.length) manifest['sdk-extensions'] = sdkExtensions;
|
|
131
|
-
if (appendPath?.length) {
|
|
132
|
-
manifest['build-options'] = { 'append-path': appendPath.join(':') };
|
|
133
|
-
}
|
|
134
|
-
manifest.command = command;
|
|
135
|
-
manifest['finish-args'] = finishArgs;
|
|
136
|
-
|
|
137
|
-
const cleanup = flatpak.cleanup;
|
|
138
|
-
if (cleanup?.length) manifest.cleanup = cleanup;
|
|
139
|
-
|
|
140
|
-
// Modules: caller-supplied `extraModules` first, then the app's own
|
|
141
|
-
// meson module pointing at the source dir.
|
|
142
|
-
const modules: unknown[] = [];
|
|
143
|
-
if (flatpak.extraModules?.length) modules.push(...flatpak.extraModules);
|
|
144
|
-
modules.push({
|
|
145
|
-
name: deriveModuleName(appId),
|
|
146
|
-
buildsystem: 'meson',
|
|
147
|
-
sources: [{ type: 'dir', path: '.' }],
|
|
148
|
-
});
|
|
149
|
-
manifest.modules = modules;
|
|
150
|
-
|
|
151
|
-
const out = (args.manifest as string | undefined) ?? `${appId}.json`;
|
|
152
|
-
const outPath = resolve(cwd, out);
|
|
153
|
-
if (existsSync(outPath) && !args.force) {
|
|
154
|
-
throw new Error(
|
|
155
|
-
`gjsify flatpak init: ${outPath} exists. Pass --force to overwrite.`,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const json = JSON.stringify(manifest, null, 4) + '\n';
|
|
160
|
-
writeFileSync(outPath, json, 'utf-8');
|
|
161
|
-
|
|
162
|
-
if (args.verbose) {
|
|
163
|
-
console.log(`[gjsify flatpak init] runtime=${runtimeId} ${runtimeVersion} sdk=${sdk}`);
|
|
164
|
-
console.log(`[gjsify flatpak init] command=${command} finish-args=${JSON.stringify(finishArgs)}`);
|
|
165
|
-
}
|
|
166
|
-
console.log(`[gjsify flatpak init] wrote ${outPath}`);
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
/** Concatenate two optional arrays, dropping `undefined`. */
|
|
171
|
-
function mergeArrays(a: string[] | undefined, b: string[] | undefined): string[] | undefined {
|
|
172
|
-
if (!a?.length && !b?.length) return undefined;
|
|
173
|
-
return [...(a ?? []), ...(b ?? [])];
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/** Map known SDK extension ids to their /usr/lib/sdk/<name>/bin paths. */
|
|
177
|
-
function deriveAppendPath(sdkExtensions: string[]): string[] {
|
|
178
|
-
const out: string[] = [];
|
|
179
|
-
for (const ext of sdkExtensions) {
|
|
180
|
-
const m = /^org\.freedesktop\.Sdk\.Extension\.([A-Za-z0-9-]+)$/.exec(ext);
|
|
181
|
-
if (m) out.push(`/usr/lib/sdk/${m[1]}/bin`);
|
|
182
|
-
}
|
|
183
|
-
out.push('/app/bin');
|
|
184
|
-
return out;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/** Last segment of the reverse-DNS id, used as the meson-module name. */
|
|
188
|
-
function deriveModuleName(appId: string): string {
|
|
189
|
-
const parts = appId.split('.');
|
|
190
|
-
return parts[parts.length - 1] || appId;
|
|
191
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// Shared helpers for the `gjsify flatpak <sub>` subcommand group.
|
|
2
|
-
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
4
|
-
import { resolve } from 'node:path';
|
|
5
|
-
import type { ConfigDataFlatpak } from '../../types/config-data.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Default GNOME-Platform runtime version. Bumped per release window.
|
|
9
|
-
* GNOME 50 = April 2026 stable; tracked in
|
|
10
|
-
* https://docs.flathub.org/docs/for-app-authors/requirements.
|
|
11
|
-
*/
|
|
12
|
-
export const DEFAULT_GNOME_RUNTIME_VERSION = '50';
|
|
13
|
-
|
|
14
|
-
/** Default Freedesktop-Platform runtime version (LTS-ish). */
|
|
15
|
-
export const DEFAULT_FREEDESKTOP_RUNTIME_VERSION = '24.08';
|
|
16
|
-
|
|
17
|
-
/** Permissive GUI defaults for GTK4 + Adwaita apps. */
|
|
18
|
-
export const DEFAULT_GUI_FINISH_ARGS = [
|
|
19
|
-
'--device=dri',
|
|
20
|
-
'--share=ipc',
|
|
21
|
-
'--socket=fallback-x11',
|
|
22
|
-
'--socket=wayland',
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
/** Lean defaults for headless CLI tools — no display, no GPU. */
|
|
26
|
-
export const DEFAULT_CLI_FINISH_ARGS: string[] = [];
|
|
27
|
-
|
|
28
|
-
/** Read package.json from a directory. Throws a helpful error if missing/invalid. */
|
|
29
|
-
export function readPackageJson(dir: string): Record<string, unknown> {
|
|
30
|
-
const path = resolve(dir, 'package.json');
|
|
31
|
-
let raw: string;
|
|
32
|
-
try {
|
|
33
|
-
raw = readFileSync(path, 'utf-8');
|
|
34
|
-
} catch {
|
|
35
|
-
throw new Error(`gjsify flatpak: no package.json found at ${path}`);
|
|
36
|
-
}
|
|
37
|
-
try {
|
|
38
|
-
return JSON.parse(raw) as Record<string, unknown>;
|
|
39
|
-
} catch (err) {
|
|
40
|
-
throw new Error(`gjsify flatpak: package.json at ${path} is not valid JSON: ${(err as Error).message}`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** True if a name string looks like a reverse-DNS Flatpak app id. */
|
|
45
|
-
export function looksLikeAppId(value: unknown): value is string {
|
|
46
|
-
return typeof value === 'string' && /^[A-Za-z][A-Za-z0-9_-]*(\.[A-Za-z][A-Za-z0-9_-]*){2,}$/.test(value);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Pick the runtime + sdk + version triple from config + CLI overrides.
|
|
51
|
-
* `--runtime` and `--runtime-version` flags win over config values.
|
|
52
|
-
*/
|
|
53
|
-
export function resolveRuntime(
|
|
54
|
-
flatpak: ConfigDataFlatpak | undefined,
|
|
55
|
-
overrides: { runtime?: string; runtimeVersion?: string },
|
|
56
|
-
): { runtime: 'gnome' | 'freedesktop'; runtimeId: string; sdk: string; runtimeVersion: string } {
|
|
57
|
-
const runtime = (overrides.runtime ?? flatpak?.runtime ?? 'gnome') as 'gnome' | 'freedesktop';
|
|
58
|
-
if (runtime !== 'gnome' && runtime !== 'freedesktop') {
|
|
59
|
-
throw new Error(`gjsify flatpak: unknown runtime "${runtime}" (expected "gnome" or "freedesktop")`);
|
|
60
|
-
}
|
|
61
|
-
const runtimeVersion =
|
|
62
|
-
overrides.runtimeVersion ??
|
|
63
|
-
flatpak?.runtimeVersion ??
|
|
64
|
-
(runtime === 'gnome' ? DEFAULT_GNOME_RUNTIME_VERSION : DEFAULT_FREEDESKTOP_RUNTIME_VERSION);
|
|
65
|
-
|
|
66
|
-
if (runtime === 'gnome') {
|
|
67
|
-
return { runtime, runtimeId: 'org.gnome.Platform', sdk: 'org.gnome.Sdk', runtimeVersion };
|
|
68
|
-
}
|
|
69
|
-
return { runtime, runtimeId: 'org.freedesktop.Platform', sdk: 'org.freedesktop.Sdk', runtimeVersion };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Default container image for the GitHub Actions workflow. */
|
|
73
|
-
export function defaultCiContainer(runtime: 'gnome' | 'freedesktop', runtimeVersion: string): string {
|
|
74
|
-
const tag = `${runtime}-${runtimeVersion}`;
|
|
75
|
-
return `ghcr.io/flathub-infra/flatpak-github-actions:${tag}`;
|
|
76
|
-
}
|