@gjsify/cli 0.51.1 → 0.53.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 +539 -493
- package/lib/actions/build.d.ts +22 -0
- package/lib/actions/build.js +37 -9
- package/lib/bundler-pick.d.ts +37 -1
- package/lib/bundler-pick.js +108 -17
- package/lib/cli-app.js +7 -2
- package/lib/commands/affected-classify.d.ts +7 -1
- package/lib/commands/affected-classify.js +66 -9
- package/lib/commands/affected-script-refs.d.ts +20 -0
- package/lib/commands/affected-script-refs.js +218 -0
- package/lib/commands/affected.js +24 -2
- package/lib/commands/env.d.ts +31 -0
- package/lib/commands/env.js +114 -0
- package/lib/commands/exec.d.ts +10 -0
- package/lib/commands/exec.js +208 -0
- package/lib/commands/flatpak/diff.js +8 -2
- package/lib/commands/flatpak/init.js +4 -1
- package/lib/commands/flatpak/sources.js +4 -3
- package/lib/commands/flatpak/sync-flathub.d.ts +2 -0
- package/lib/commands/flatpak/sync-flathub.js +149 -7
- package/lib/commands/flatpak/utils.d.ts +10 -0
- package/lib/commands/flatpak/utils.js +10 -0
- package/lib/commands/foreach.js +5 -97
- package/lib/commands/format.js +26 -6
- package/lib/commands/index.d.ts +4 -0
- package/lib/commands/index.js +4 -0
- package/lib/commands/install.d.ts +2 -2
- package/lib/commands/install.js +81 -5
- package/lib/commands/link.d.ts +13 -0
- package/lib/commands/link.js +243 -0
- package/lib/commands/onboard.js +18 -2
- package/lib/commands/publish.d.ts +34 -0
- package/lib/commands/publish.js +153 -8
- package/lib/commands/self-update.js +2 -1
- package/lib/commands/ship.js +19 -1
- package/lib/commands/test.d.ts +18 -9
- package/lib/commands/test.js +56 -11
- package/lib/commands/tsc.js +4 -4
- package/lib/commands/upgrade.d.ts +15 -0
- package/lib/commands/upgrade.js +76 -2
- package/lib/commands/webext/index.d.ts +2 -0
- package/lib/commands/webext/index.js +15 -0
- package/lib/commands/webext/subcommands.d.ts +16 -0
- package/lib/commands/webext/subcommands.js +204 -0
- package/lib/types/config-data.d.ts +2 -2
- package/lib/utils/bin-shim.d.ts +8 -2
- package/lib/utils/bin-shim.js +6 -5
- package/lib/utils/bundle-inputs.d.ts +84 -0
- package/lib/utils/bundle-inputs.js +268 -0
- package/lib/utils/check-system-deps.d.ts +5 -19
- package/lib/utils/check-system-deps.js +31 -94
- package/lib/utils/dev-link.d.ts +225 -0
- package/lib/utils/dev-link.js +684 -0
- package/lib/utils/exec-bin.d.ts +137 -0
- package/lib/utils/exec-bin.js +321 -0
- package/lib/utils/gi-runtime-paths.js +3 -2
- package/lib/utils/gitignore.d.ts +15 -0
- package/lib/utils/gitignore.js +178 -0
- package/lib/utils/gjsify-shim.d.ts +47 -0
- package/lib/utils/gjsify-shim.js +97 -8
- package/lib/utils/hang-watchdog.d.ts +95 -0
- package/lib/utils/hang-watchdog.js +194 -0
- package/lib/utils/install-backend-native.d.ts +33 -1
- package/lib/utils/install-backend-native.js +184 -20
- package/lib/utils/install-extraneous.d.ts +90 -0
- package/lib/utils/install-extraneous.js +120 -0
- package/lib/utils/install-lock.js +4 -25
- package/lib/utils/install-tarball-cache.d.ts +37 -9
- package/lib/utils/install-tarball-cache.js +59 -14
- package/lib/utils/native-skip-scan.d.ts +20 -0
- package/lib/utils/native-skip-scan.js +343 -0
- package/lib/utils/node-script.js +1 -1
- package/lib/utils/normalize-bundler-options.js +11 -0
- package/lib/utils/oxc-resolve.js +42 -3
- package/lib/utils/process-table.d.ts +22 -0
- package/lib/utils/process-table.js +188 -0
- package/lib/utils/prune-prefix.js +1 -1
- package/lib/utils/publish-pins.d.ts +38 -0
- package/lib/utils/publish-pins.js +47 -0
- package/lib/utils/publish-readback.d.ts +103 -17
- package/lib/utils/publish-readback.js +326 -47
- package/lib/utils/run-gjs.d.ts +15 -1
- package/lib/utils/run-gjs.js +98 -13
- package/lib/utils/run-node.d.ts +2 -0
- package/lib/utils/run-node.js +2 -1
- package/lib/utils/runtimes.js +14 -13
- package/lib/utils/ship/gzip.js +1 -1
- package/lib/utils/ship/icns.d.ts +14 -0
- package/lib/utils/ship/icns.js +83 -0
- package/lib/utils/ship/ico.d.ts +25 -0
- package/lib/utils/ship/ico.js +120 -0
- package/lib/utils/ship/icons.d.ts +197 -0
- package/lib/utils/ship/icons.js +399 -0
- package/lib/utils/ship/launcher.js +16 -1
- package/lib/utils/ship/layout.d.ts +32 -0
- package/lib/utils/ship/layout.js +112 -38
- package/lib/utils/ship/msi.d.ts +1 -1
- package/lib/utils/ship/msi.js +30 -5
- package/lib/utils/ship/pe-launcher.d.ts +18 -0
- package/lib/utils/ship/pe-launcher.js +125 -4
- package/lib/utils/ship/plan.d.ts +1 -34
- package/lib/utils/ship/plan.js +7 -56
- package/lib/utils/ship/plist.d.ts +20 -10
- package/lib/utils/ship/plist.js +29 -12
- package/lib/utils/ship/settings.js +3 -2
- package/lib/utils/spawn.d.ts +13 -0
- package/lib/utils/spawn.js +10 -5
- package/lib/utils/watch-loop.d.ts +15 -1
- package/lib/utils/watch-loop.js +9 -5
- package/lib/utils/webext/build.d.ts +42 -0
- package/lib/utils/webext/build.js +120 -0
- package/lib/utils/webext/config.d.ts +72 -0
- package/lib/utils/webext/config.js +234 -0
- package/lib/utils/webext/icons.d.ts +24 -0
- package/lib/utils/webext/icons.js +83 -0
- package/lib/utils/webext/launch.d.ts +32 -0
- package/lib/utils/webext/launch.js +77 -0
- package/lib/utils/webext/manifest.d.ts +53 -0
- package/lib/utils/webext/manifest.js +219 -0
- package/lib/utils/webext/pages.d.ts +26 -0
- package/lib/utils/webext/pages.js +61 -0
- package/lib/utils/webext/targets.d.ts +13 -0
- package/lib/utils/webext/targets.js +36 -0
- package/lib/utils/win32-command.d.ts +17 -0
- package/lib/utils/win32-command.js +21 -6
- package/package.json +20 -20
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Win32ResolveContext } from './win32-command.js';
|
|
1
2
|
export type DepSeverity = 'required' | 'optional';
|
|
2
3
|
export interface DepCheck {
|
|
3
4
|
/** Stable key used for install command lookup, e.g. "gjs" */
|
|
@@ -15,7 +16,8 @@ export interface DepCheck {
|
|
|
15
16
|
export type PackageManager = 'apt' | 'dnf' | 'pacman' | 'zypper' | 'apk' | 'brew' | 'winget' | 'unknown';
|
|
16
17
|
/**
|
|
17
18
|
* True when `cmd` is on PATH. Walks `process.env.PATH` with `existsSync`
|
|
18
|
-
* instead of shelling out to `which`(1)
|
|
19
|
+
* instead of shelling out to `which`(1), honouring `PATHEXT` on win32 — see
|
|
20
|
+
* `findOnPath` in `win32-command.ts`, which owns the walk.
|
|
19
21
|
*
|
|
20
22
|
* `which` is NOT a probe you can rely on: the Fedora 43/44 minimal containers
|
|
21
23
|
* CI runs in ship without it (only the `which-2.x` rpm provides it), so a
|
|
@@ -31,7 +33,7 @@ export type PackageManager = 'apt' | 'dnf' | 'pacman' | 'zypper' | 'apk' | 'brew
|
|
|
31
33
|
* reason. It stays a second copy on purpose: it is `.mjs` under `tests/` and
|
|
32
34
|
* cannot be imported from the shipped CLI.
|
|
33
35
|
*/
|
|
34
|
-
export declare function isOnPath(cmd: string): boolean;
|
|
36
|
+
export declare function isOnPath(cmd: string, ctx?: Win32ResolveContext): boolean;
|
|
35
37
|
/**
|
|
36
38
|
* The package manager whose install command we may suggest.
|
|
37
39
|
*
|
|
@@ -118,7 +120,7 @@ export declare const PACKAGE_DEPS: Record<string, string[]>;
|
|
|
118
120
|
* Run all dependency checks. Used by `gjsify check` to show full system status.
|
|
119
121
|
*
|
|
120
122
|
* Required deps (gjs, gtk4, libsoup3, libadwaita, gobject-introspection,
|
|
121
|
-
*
|
|
123
|
+
* pkg-config, meson) are always checked.
|
|
122
124
|
*
|
|
123
125
|
* Optional deps are checked conditionally based on which @gjsify/* packages
|
|
124
126
|
* the project (resolved from cwd) actually consumes. If no project context
|
|
@@ -130,22 +132,6 @@ export declare function runAllChecks(cwd: string): DepCheck[];
|
|
|
130
132
|
* not required). Used by `gjsify showcase` for examples that have no native deps.
|
|
131
133
|
*/
|
|
132
134
|
export declare function runMinimalChecks(): DepCheck[];
|
|
133
|
-
/**
|
|
134
|
-
* Is a blueprint-compiler reachable, by the SAME rule the build uses?
|
|
135
|
-
*
|
|
136
|
-
* Delegates to `@gjsify/vite-plugin-blueprint/resolve` rather than probing PATH
|
|
137
|
-
* here, because the two answers must not be able to disagree: on win32 the
|
|
138
|
-
* compiler is normally an MSYS2 script that is deliberately NOT on PATH, so a
|
|
139
|
-
* PATH-only check would report "missing" on a host where every `.blp` builds
|
|
140
|
-
* fine — a check failing for the wrong reason, which is the failure mode this
|
|
141
|
-
* file's own history is made of.
|
|
142
|
-
*
|
|
143
|
-
* `--version` is not run. MSYS2 ships blueprint-compiler as a shebang script
|
|
144
|
-
* with no `.exe`, so `checkBinary` cannot execute it on Windows; presence of the
|
|
145
|
-
* resolved pair is the honest answer, and the `source` is worth reporting
|
|
146
|
-
* because "found via msys2" explains an install PATH does not show.
|
|
147
|
-
*/
|
|
148
|
-
export declare function checkBlueprintCompiler(requiredBy?: string[]): DepCheck;
|
|
149
135
|
/** Check gwebgl npm package (project first, CLI fallback). Optional — only needed by @gjsify/webgl users. */
|
|
150
136
|
export declare function checkGwebgl(cwd: string): DepCheck;
|
|
151
137
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// System dependency checker for gjsify CLI.
|
|
2
|
-
// Uses
|
|
2
|
+
// Uses spawnSync with explicit argument arrays — no shell injection possible.
|
|
3
3
|
// All binary names are hardcoded constants, never derived from user input.
|
|
4
4
|
//
|
|
5
5
|
// Severity model:
|
|
@@ -10,28 +10,31 @@
|
|
|
10
10
|
// optional system deps are only checked if the corresponding @gjsify/* package
|
|
11
11
|
// is in the project's dependency tree. A user with only @gjsify/fs in their
|
|
12
12
|
// project never sees a warning about libmanette.
|
|
13
|
-
import {
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
14
|
import { dirname, join, resolve } from 'node:path';
|
|
15
15
|
import { createRequire } from 'node:module';
|
|
16
16
|
import { pathToFileURL } from 'node:url';
|
|
17
17
|
import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
|
18
|
-
// The zero-dependency subpath, deliberately: importing the plugin root would
|
|
19
|
-
// pull vite/execa/minify-xml into a system CHECK.
|
|
20
|
-
import { resolveBlueprintCompiler } from '@gjsify/vite-plugin-blueprint/resolve';
|
|
21
18
|
import { isNode } from '@gjsify/rolldown-plugin-gjsify/runtime';
|
|
22
19
|
import { findSystemTypelib } from './gi-typelib.js';
|
|
20
|
+
import { toSpawnable } from './spawn.js';
|
|
21
|
+
import { findOnPath } from './win32-command.js';
|
|
23
22
|
/** Run a binary and return its stdout trimmed, or null if it fails. */
|
|
24
23
|
function tryExecFile(binary, args) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
// `spawnSync`, not `execFileSync`: only the former takes the verbatim-argv
|
|
25
|
+
// flag the cmd.exe route of `toSpawnable` needs.
|
|
26
|
+
const inv = toSpawnable(binary, args);
|
|
27
|
+
const r = spawnSync(inv.cmd, inv.args, {
|
|
28
|
+
encoding: 'utf-8',
|
|
29
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
30
|
+
windowsVerbatimArguments: inv.windowsVerbatimArguments,
|
|
31
|
+
});
|
|
32
|
+
return r.error || r.status !== 0 ? null : r.stdout.trim();
|
|
31
33
|
}
|
|
32
34
|
/**
|
|
33
35
|
* True when `cmd` is on PATH. Walks `process.env.PATH` with `existsSync`
|
|
34
|
-
* instead of shelling out to `which`(1)
|
|
36
|
+
* instead of shelling out to `which`(1), honouring `PATHEXT` on win32 — see
|
|
37
|
+
* `findOnPath` in `win32-command.ts`, which owns the walk.
|
|
35
38
|
*
|
|
36
39
|
* `which` is NOT a probe you can rely on: the Fedora 43/44 minimal containers
|
|
37
40
|
* CI runs in ship without it (only the `which-2.x` rpm provides it), so a
|
|
@@ -47,23 +50,12 @@ function tryExecFile(binary, args) {
|
|
|
47
50
|
* reason. It stays a second copy on purpose: it is `.mjs` under `tests/` and
|
|
48
51
|
* cannot be imported from the shipped CLI.
|
|
49
52
|
*/
|
|
50
|
-
export function isOnPath(cmd) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (!dir)
|
|
57
|
-
continue;
|
|
58
|
-
try {
|
|
59
|
-
if (existsSync(join(dir, cmd)))
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
// An inaccessible PATH entry is not an answer about `cmd`.
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
53
|
+
export function isOnPath(cmd, ctx = hostPathContext()) {
|
|
54
|
+
return findOnPath(cmd, ctx) !== undefined;
|
|
55
|
+
}
|
|
56
|
+
/** This process's PATH, filesystem and platform — what {@link isOnPath} asks by default. */
|
|
57
|
+
function hostPathContext() {
|
|
58
|
+
return { platform: process.platform, env: process.env, exists: existsSync, join };
|
|
67
59
|
}
|
|
68
60
|
/** Check if a binary exists and optionally capture its version output. */
|
|
69
61
|
function checkBinary(id, name, binary, versionArgs, severity, parseVersion, requiredBy) {
|
|
@@ -393,7 +385,7 @@ function computeNeededOptionalDeps(cwd) {
|
|
|
393
385
|
* Run all dependency checks. Used by `gjsify check` to show full system status.
|
|
394
386
|
*
|
|
395
387
|
* Required deps (gjs, gtk4, libsoup3, libadwaita, gobject-introspection,
|
|
396
|
-
*
|
|
388
|
+
* pkg-config, meson) are always checked.
|
|
397
389
|
*
|
|
398
390
|
* Optional deps are checked conditionally based on which @gjsify/* packages
|
|
399
391
|
* the project (resolved from cwd) actually consumes. If no project context
|
|
@@ -454,53 +446,19 @@ export function runMinimalChecks() {
|
|
|
454
446
|
results.push(checkMsvcRuntime());
|
|
455
447
|
return results;
|
|
456
448
|
}
|
|
457
|
-
/**
|
|
458
|
-
* Is a blueprint-compiler reachable, by the SAME rule the build uses?
|
|
459
|
-
*
|
|
460
|
-
* Delegates to `@gjsify/vite-plugin-blueprint/resolve` rather than probing PATH
|
|
461
|
-
* here, because the two answers must not be able to disagree: on win32 the
|
|
462
|
-
* compiler is normally an MSYS2 script that is deliberately NOT on PATH, so a
|
|
463
|
-
* PATH-only check would report "missing" on a host where every `.blp` builds
|
|
464
|
-
* fine — a check failing for the wrong reason, which is the failure mode this
|
|
465
|
-
* file's own history is made of.
|
|
466
|
-
*
|
|
467
|
-
* `--version` is not run. MSYS2 ships blueprint-compiler as a shebang script
|
|
468
|
-
* with no `.exe`, so `checkBinary` cannot execute it on Windows; presence of the
|
|
469
|
-
* resolved pair is the honest answer, and the `source` is worth reporting
|
|
470
|
-
* because "found via msys2" explains an install PATH does not show.
|
|
471
|
-
*/
|
|
472
|
-
export function checkBlueprintCompiler(requiredBy) {
|
|
473
|
-
const resolved = resolveBlueprintCompiler();
|
|
474
|
-
return {
|
|
475
|
-
id: 'blueprint-compiler',
|
|
476
|
-
name: 'blueprint-compiler (.blp templates)',
|
|
477
|
-
found: resolved !== null,
|
|
478
|
-
version: resolved ? `found via ${resolved.source}` : undefined,
|
|
479
|
-
severity: 'optional',
|
|
480
|
-
requiredBy,
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
449
|
/** Check gwebgl npm package (project first, CLI fallback). Optional — only needed by @gjsify/webgl users. */
|
|
484
450
|
export function checkGwebgl(cwd) {
|
|
485
451
|
return checkNpmPackage('gwebgl', 'gwebgl (@gjsify/webgl)', '@gjsify/webgl', cwd, 'optional', ['@gjsify/webgl']);
|
|
486
452
|
}
|
|
487
453
|
/**
|
|
488
454
|
* Required system dependencies — always checked, missing → exit 1.
|
|
489
|
-
* Includes the core build toolchain (pkg-config, meson
|
|
490
|
-
*
|
|
491
|
-
*
|
|
455
|
+
* Includes the core build toolchain (pkg-config, meson) and the foundational
|
|
456
|
+
* libraries (gtk4, libadwaita, libsoup3, gobject-introspection) that nearly
|
|
457
|
+
* every gjsify app needs.
|
|
492
458
|
*/
|
|
493
459
|
function runRequiredChecks(_cwd) {
|
|
494
460
|
const results = [];
|
|
495
|
-
// Build toolchain.
|
|
496
|
-
// `checkBlueprintCompiler()` among the build toolchain below, through the
|
|
497
|
-
// SAME resolver the build uses. A second `checkBinary` probe lived here and
|
|
498
|
-
// was wrong twice over — it reported a PATH miss on win32, where the
|
|
499
|
-
// compiler is normally an MSYS2 script deliberately off PATH (the exact case
|
|
500
|
-
// that function's comment exists to explain), and it made `system-check`
|
|
501
|
-
// exit 1 on any host without it, `.blp` files in the project or not. It also
|
|
502
|
-
// printed a second entry under a second display name and put
|
|
503
|
-
// `blueprint-compiler` into the install hint twice.
|
|
461
|
+
// Build toolchain.
|
|
504
462
|
results.push(checkBinary('pkg-config', 'pkg-config', 'pkg-config', ['--version'], 'required'));
|
|
505
463
|
results.push(checkBinary('meson', 'Meson', 'meson', ['--version'], 'required'));
|
|
506
464
|
// Foundational libraries — by TYPELIB, the runtime question. See checkGiLibrary.
|
|
@@ -549,13 +507,12 @@ function runNativeBuildToolchainChecks() {
|
|
|
549
507
|
// Narrower on purpose: only the three bridges that link an upstream Rust
|
|
550
508
|
// crate by Cargo path-dependency need a Rust toolchain.
|
|
551
509
|
const rustBridges = ['@gjsify/lightningcss-native', '@gjsify/oxfmt-native', '@gjsify/rolldown-native'];
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
//
|
|
556
|
-
|
|
510
|
+
// NO blueprint-compiler row, and it is a deletion rather than an omission: ADR 0053 clause 5
|
|
511
|
+
// moved the `.blp` transform into `@gjsify/blueprint`, so a `.blp` template asks nothing of
|
|
512
|
+
// this host any more. A row for it would be this command asking for a toolchain the build
|
|
513
|
+
// cannot use — the exact "check failing for the wrong reason" its own history is made of.
|
|
514
|
+
// ADR 0063 is the deletion and what the compiler is still FOR.
|
|
557
515
|
return [
|
|
558
|
-
checkBlueprintCompiler(blueprintConsumers),
|
|
559
516
|
checkBinary('ninja', 'Ninja', 'ninja', ['--version'], 'optional', undefined, valaBridges),
|
|
560
517
|
checkBinary('vala', 'Vala', 'valac', ['--version'], 'optional', (out) => out.replace(/^Vala\s+/i, ''), valaBridges),
|
|
561
518
|
checkBinary('cargo', 'Cargo (Rust)', 'cargo', ['--version'], 'optional', (out) => out.replace(/^cargo\s+/i, '').split(' ')[0] ?? out, rustBridges),
|
|
@@ -596,7 +553,6 @@ const PM_PACKAGES = {
|
|
|
596
553
|
apt: {
|
|
597
554
|
nodejs: 'nodejs',
|
|
598
555
|
gjs: 'gjs',
|
|
599
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
600
556
|
'pkg-config': 'pkg-config',
|
|
601
557
|
meson: 'meson',
|
|
602
558
|
ninja: 'ninja-build',
|
|
@@ -622,7 +578,6 @@ const PM_PACKAGES = {
|
|
|
622
578
|
dnf: {
|
|
623
579
|
nodejs: 'nodejs',
|
|
624
580
|
gjs: 'gjs',
|
|
625
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
626
581
|
'pkg-config': 'pkgconf-pkg-config',
|
|
627
582
|
meson: 'meson',
|
|
628
583
|
ninja: 'ninja-build',
|
|
@@ -648,7 +603,6 @@ const PM_PACKAGES = {
|
|
|
648
603
|
pacman: {
|
|
649
604
|
nodejs: 'nodejs',
|
|
650
605
|
gjs: 'gjs',
|
|
651
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
652
606
|
'pkg-config': 'pkgconf',
|
|
653
607
|
meson: 'meson',
|
|
654
608
|
ninja: 'ninja',
|
|
@@ -674,7 +628,6 @@ const PM_PACKAGES = {
|
|
|
674
628
|
zypper: {
|
|
675
629
|
nodejs: 'nodejs',
|
|
676
630
|
gjs: 'gjs',
|
|
677
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
678
631
|
'pkg-config': 'pkg-config',
|
|
679
632
|
meson: 'meson',
|
|
680
633
|
ninja: 'ninja',
|
|
@@ -700,7 +653,6 @@ const PM_PACKAGES = {
|
|
|
700
653
|
apk: {
|
|
701
654
|
nodejs: 'nodejs',
|
|
702
655
|
gjs: 'gjs',
|
|
703
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
704
656
|
'pkg-config': 'pkgconf',
|
|
705
657
|
meson: 'meson',
|
|
706
658
|
ninja: 'ninja',
|
|
@@ -748,7 +700,6 @@ const PM_PACKAGES = {
|
|
|
748
700
|
brew: {
|
|
749
701
|
nodejs: 'node',
|
|
750
702
|
gjs: 'gjs',
|
|
751
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
752
703
|
'pkg-config': 'pkgconf',
|
|
753
704
|
meson: 'meson',
|
|
754
705
|
ninja: 'ninja',
|
|
@@ -804,24 +755,11 @@ export function buildInstallCommand(pm, missing) {
|
|
|
804
755
|
const pkgMap = PM_PACKAGES[pm];
|
|
805
756
|
const pkgs = [];
|
|
806
757
|
const npmDeps = [];
|
|
807
|
-
const standalone = [];
|
|
808
758
|
for (const dep of missing) {
|
|
809
759
|
if (dep.id === 'gwebgl') {
|
|
810
760
|
npmDeps.push('@gjsify/webgl');
|
|
811
761
|
continue;
|
|
812
762
|
}
|
|
813
|
-
// blueprint-compiler on Windows is the one dep whose install command is
|
|
814
|
-
// not this host's package manager. winget has no package for it, and it
|
|
815
|
-
// cannot get one that works: the tool needs PyGObject, which publishes
|
|
816
|
-
// no Windows wheel, so MSYS2 — which ships Python, PyGObject and the
|
|
817
|
-
// typelibs already fitted together — is the only source. Its command is
|
|
818
|
-
// not `winget install`-shaped, so it cannot live in PM_PACKAGES without
|
|
819
|
-
// producing a line that looks right and fails.
|
|
820
|
-
if (dep.id === 'blueprint-compiler' && process.platform === 'win32') {
|
|
821
|
-
standalone.push('pacman -S mingw-w64-ucrt-x86_64-blueprint-compiler mingw-w64-ucrt-x86_64-gtk4 ' +
|
|
822
|
-
'mingw-w64-ucrt-x86_64-libadwaita # inside MSYS2; found automatically afterwards');
|
|
823
|
-
continue;
|
|
824
|
-
}
|
|
825
763
|
// No `continue` for `nodejs`. It USED to be unmissable — the row was the
|
|
826
764
|
// literal `found: true` — and since it became a real probe it can report
|
|
827
765
|
// absent under GJS, so skipping it here printed "Missing optional: Node.js"
|
|
@@ -842,7 +780,6 @@ export function buildInstallCommand(pm, missing) {
|
|
|
842
780
|
if (npmDeps.length > 0) {
|
|
843
781
|
lines.push(`npm install ${npmDeps.join(' ')}`);
|
|
844
782
|
}
|
|
845
|
-
lines.push(...standalone);
|
|
846
783
|
return lines.length > 0 ? lines.join('\n ') : null;
|
|
847
784
|
}
|
|
848
785
|
/**
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { type Workspace } from '@gjsify/workspace';
|
|
2
|
+
/** The consumer-local override file. Git-ignored; never committed. */
|
|
3
|
+
export declare const DEV_LINK_FILE = ".gjsify-link.json";
|
|
4
|
+
/**
|
|
5
|
+
* What `.gjsify-link.json` holds.
|
|
6
|
+
*
|
|
7
|
+
* A POINTER plus a selector, never a materialised list of package names: `link`
|
|
8
|
+
* and `install` then derive the same set from the same two inputs, so a checkout
|
|
9
|
+
* that gains or loses a workspace package cannot leave the two disagreeing about
|
|
10
|
+
* what is linked.
|
|
11
|
+
*/
|
|
12
|
+
export interface DevLinkOverride {
|
|
13
|
+
/** Format version — an unknown one is refused rather than guessed at. */
|
|
14
|
+
version: 1;
|
|
15
|
+
/** The gjsify checkout to link from. Absolute, as written by `gjsify link`. */
|
|
16
|
+
checkout: string;
|
|
17
|
+
/**
|
|
18
|
+
* Name globs selecting which of its workspace packages take part. EMPTY means
|
|
19
|
+
* every one of them — deliberately not `["*"]`, which would select NOTHING:
|
|
20
|
+
* measured, `@gjsify/workspace`'s glob dialect maps `*` to `[^/]*`, so a bare
|
|
21
|
+
* star never matches a SCOPED name. The spelling for a whole scope is
|
|
22
|
+
* `@gjsify/*`, the same dialect `gjsify foreach --include` takes.
|
|
23
|
+
*/
|
|
24
|
+
packages: string[];
|
|
25
|
+
}
|
|
26
|
+
/** One `node_modules/<name>` → checkout package directory link. */
|
|
27
|
+
export interface DevLink {
|
|
28
|
+
name: string;
|
|
29
|
+
/** Absolute path of the workspace package in the checkout. */
|
|
30
|
+
target: string;
|
|
31
|
+
/** Absolute path of the link inside the consumer's `node_modules`. */
|
|
32
|
+
linkPath: string;
|
|
33
|
+
}
|
|
34
|
+
/** An override that has been read, validated and turned into a link plan. */
|
|
35
|
+
export interface ActiveDevLinks {
|
|
36
|
+
/** Absolute path of the override file, for every message that names it. */
|
|
37
|
+
overridePath: string;
|
|
38
|
+
/** The consumer root the override belongs to. */
|
|
39
|
+
consumerRoot: string;
|
|
40
|
+
/** The validated checkout it points at. */
|
|
41
|
+
checkout: string;
|
|
42
|
+
links: DevLink[];
|
|
43
|
+
/** Just the names — what the installer excludes from its fetch set. */
|
|
44
|
+
names: Set<string>;
|
|
45
|
+
}
|
|
46
|
+
export declare function devLinkPath(root: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Read the override at `root`, or `null` when there is none.
|
|
49
|
+
*
|
|
50
|
+
* A file that exists but does not parse is an ERROR, not a `null`: this decides
|
|
51
|
+
* where a build's inputs come from, and "unreadable" must never be answered with
|
|
52
|
+
* the registry's copy while the developer believes their checkout is in play.
|
|
53
|
+
*/
|
|
54
|
+
export declare function readDevLinkOverride(root: string): DevLinkOverride | null;
|
|
55
|
+
export declare function writeDevLinkOverride(root: string, override: DevLinkOverride): string;
|
|
56
|
+
/** Remove the override file; returns its path when one was there. */
|
|
57
|
+
export declare function removeDevLinkOverride(root: string): string | null;
|
|
58
|
+
/**
|
|
59
|
+
* Which directory's override governs an install started in `startDir`.
|
|
60
|
+
*
|
|
61
|
+
* Same walk `projectInstallNative` does for the install itself: a member of a
|
|
62
|
+
* workspace installs the workspace, so the override that applies is the
|
|
63
|
+
* workspace root's — otherwise `gjsify install` inside a member would silently
|
|
64
|
+
* ignore a link the root declares.
|
|
65
|
+
*/
|
|
66
|
+
export declare function devLinkRoot(startDir: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Turn `override.checkout` into the workspace list behind it, or refuse.
|
|
69
|
+
*
|
|
70
|
+
* A DEAD LINK IS AN ERROR WITH A PATH, never a quiet fall back to the registry:
|
|
71
|
+
* the developer asked for their checkout, and installing the published copy
|
|
72
|
+
* instead produces a build that looks like the one they wanted and is not. Both
|
|
73
|
+
* refusals print the measured path, because "it points somewhere wrong" is only
|
|
74
|
+
* actionable with the somewhere in it.
|
|
75
|
+
*/
|
|
76
|
+
export declare function resolveCheckoutWorkspaces(checkout: string, overridePath: string): Workspace[];
|
|
77
|
+
/**
|
|
78
|
+
* The dependency names the consumer would otherwise take from the registry.
|
|
79
|
+
*
|
|
80
|
+
* Two readers, one answer: what its manifests DECLARE (so a fresh clone can be
|
|
81
|
+
* linked before it has ever installed) and what its `node_modules` already HOLDS
|
|
82
|
+
* (so transitive `@gjsify/*` packages — the ones nobody declares and every build
|
|
83
|
+
* loads — are covered too).
|
|
84
|
+
*/
|
|
85
|
+
export declare function consumerKnownNames(consumerRoot: string): Set<string>;
|
|
86
|
+
/**
|
|
87
|
+
* The links an override asks for: the checkout's workspace packages, narrowed by
|
|
88
|
+
* the name globs, INTERSECTED with what the consumer actually depends on.
|
|
89
|
+
*
|
|
90
|
+
* The intersection is the point. Linking every workspace package of a 200-member
|
|
91
|
+
* monorepo into a consumer that uses eight would put 200 directories it never
|
|
92
|
+
* declared into its tree, and leave `gjsify unlink` with no honest answer about
|
|
93
|
+
* what to restore. Pure, so every selection rule is decidable without a
|
|
94
|
+
* filesystem.
|
|
95
|
+
*/
|
|
96
|
+
export declare function planDevLinks(opts: {
|
|
97
|
+
consumerRoot: string;
|
|
98
|
+
workspaces: readonly Workspace[];
|
|
99
|
+
patterns: readonly string[];
|
|
100
|
+
knownNames: ReadonlySet<string>;
|
|
101
|
+
}): DevLink[];
|
|
102
|
+
/**
|
|
103
|
+
* Read + validate the override at `consumerRoot` and plan its links, or `null`
|
|
104
|
+
* when no override is there. Throws for every other shape — see
|
|
105
|
+
* {@link resolveCheckoutWorkspaces}.
|
|
106
|
+
*/
|
|
107
|
+
export declare function prepareDevLinks(consumerRoot: string): ActiveDevLinks | null;
|
|
108
|
+
/**
|
|
109
|
+
* (Re)create every planned link. Idempotent — a link already pointing at the
|
|
110
|
+
* right target is left alone, so a re-run costs no unlink/relink race against a
|
|
111
|
+
* process reading through it.
|
|
112
|
+
*
|
|
113
|
+
* Returns the links it actually wrote.
|
|
114
|
+
*/
|
|
115
|
+
export declare function applyDevLinks(links: readonly DevLink[]): DevLink[];
|
|
116
|
+
/**
|
|
117
|
+
* Remove the links an override produced.
|
|
118
|
+
*
|
|
119
|
+
* ONLY a symlink whose target is inside the checkout is removed. A real
|
|
120
|
+
* directory at that path is the registry copy — some other tool's, or an install
|
|
121
|
+
* that ran with the override already gone — and deleting it would turn `unlink`
|
|
122
|
+
* into a destructive command for a tree it did not create. Same asymmetry
|
|
123
|
+
* `install-extraneous.ts` reasons from: a wrong deletion loses work, a wrong
|
|
124
|
+
* refusal costs one message.
|
|
125
|
+
*/
|
|
126
|
+
export declare function removeDevLinks(links: readonly DevLink[]): DevLink[];
|
|
127
|
+
/**
|
|
128
|
+
* Every `node_modules/<name>` symlink that resolves INSIDE one of `checkouts`.
|
|
129
|
+
*
|
|
130
|
+
* The PLAN is not a census. `removeDevLinks` only ever visits the links the
|
|
131
|
+
* CURRENT override asks for, so a link the previous override made and the new one
|
|
132
|
+
* dropped is invisible to it — measured: link everything, relink with
|
|
133
|
+
* `--packages 'is-odd'`, and `node_modules/is-number` stays pointing into the
|
|
134
|
+
* checkout while nothing in the plan names it. From there `assertNodeModulesDest`
|
|
135
|
+
* aborted EVERY later `gjsify install`, and `gjsify unlink` could not help because
|
|
136
|
+
* it removed the override (the escape route) before hitting the same abort. Only a
|
|
137
|
+
* hand-written `rm` got the project back.
|
|
138
|
+
*
|
|
139
|
+
* So the ground truth for "what is linked" is the tree, not the file. Reads one
|
|
140
|
+
* level of `node_modules` plus one level into each `@scope/`, which is where
|
|
141
|
+
* top-level links live; `.bin` and real directories are skipped by construction.
|
|
142
|
+
*/
|
|
143
|
+
export declare function scanDevLinks(consumerRoot: string, checkouts: readonly string[]): DevLink[];
|
|
144
|
+
/**
|
|
145
|
+
* Remove every dev link into `checkouts` that `keep` does not name.
|
|
146
|
+
*
|
|
147
|
+
* What makes re-linking with a narrower `--packages` a RE-selection rather than an
|
|
148
|
+
* addition, and what makes `unlink` leave the tree as it found it. Pass an empty
|
|
149
|
+
* `keep` to retire all of them.
|
|
150
|
+
*/
|
|
151
|
+
export declare function retireDevLinks(consumerRoot: string, checkouts: readonly string[], keep: ReadonlySet<string>): DevLink[];
|
|
152
|
+
/** A linked package that cannot be imported, and why not. */
|
|
153
|
+
export interface UnbuiltDevLink {
|
|
154
|
+
link: DevLink;
|
|
155
|
+
reason: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Which of these links point at something that is not built.
|
|
159
|
+
*
|
|
160
|
+
* Candidates are the string entry points a manifest can carry — `main`, `module`
|
|
161
|
+
* and the string leaves under `exports["."]`. ANY of them existing is enough: a
|
|
162
|
+
* package legitimately declares entries it does not ship on every platform, and a
|
|
163
|
+
* refusal that fires on a healthy tree is a refusal people learn to route around.
|
|
164
|
+
* An entry-LESS manifest is fine, because nothing was promised that could be
|
|
165
|
+
* missing.
|
|
166
|
+
*
|
|
167
|
+
* An UNREADABLE manifest is NOT fine, and that is a flip from the first draft,
|
|
168
|
+
* which answered "built" for it. "I could not tell" is not "yes" in a check whose
|
|
169
|
+
* whole job is to stop a silently unusable tree.
|
|
170
|
+
*/
|
|
171
|
+
export declare function unbuiltDevLinks(links: readonly DevLink[]): UnbuiltDevLink[];
|
|
172
|
+
/** The refusal text for {@link unbuiltDevLinks}, naming every path and the build. */
|
|
173
|
+
export declare function formatUnbuiltDevLinks(unbuilt: readonly UnbuiltDevLink[]): string;
|
|
174
|
+
/**
|
|
175
|
+
* FAIL CLOSED on a link to something unbuilt.
|
|
176
|
+
*
|
|
177
|
+
* `dist/`/`lib/` are git-ignored in a gjsify checkout, so "the entry point is not
|
|
178
|
+
* there right now" is the ordinary consequence of a branch switch, not an exotic
|
|
179
|
+
* state. Measured: with the entry file deleted, `gjsify install` re-linked and
|
|
180
|
+
* printed only "development link ACTIVE"; the consumer then died on
|
|
181
|
+
* MODULE_NOT_FOUND with a message naming the consumer, not the checkout.
|
|
182
|
+
*/
|
|
183
|
+
export declare function assertDevLinksBuilt(links: readonly DevLink[]): void;
|
|
184
|
+
/**
|
|
185
|
+
* Make `.gjsify-link.json` invisible to git WITHOUT editing a tracked file.
|
|
186
|
+
*
|
|
187
|
+
* `info/exclude` is git's own per-clone ignore list: it is not committed and
|
|
188
|
+
* not shared between clones, which is exactly the lifetime of the thing it
|
|
189
|
+
* hides. Writing to `.gitignore` instead would put a developer's local override
|
|
190
|
+
* into everyone else's diff — the manifest edit this whole feature exists to
|
|
191
|
+
* avoid, one file over. A WORKTREE is the case to get right: the file is
|
|
192
|
+
* written under the repository's COMMON dir, because `info/exclude` is shared
|
|
193
|
+
* across a repository's worktrees and the worktree's own gitdir is not read
|
|
194
|
+
* (see {@link resolveGitDir}).
|
|
195
|
+
*
|
|
196
|
+
* Returns what it did, so the caller can say so. A consumer that is not a git
|
|
197
|
+
* repository is not an error: nothing can commit the file there either. A
|
|
198
|
+
* consumer whose `.git` POINTER cannot be followed IS worth a word, though —
|
|
199
|
+
* there the file stays visible to `git status` and one `git add -A` commits it.
|
|
200
|
+
*/
|
|
201
|
+
export declare function ensureLocallyIgnored(consumerRoot: string): 'added' | 'already-ignored' | 'no-git' | 'unreadable-git';
|
|
202
|
+
/**
|
|
203
|
+
* Undo {@link ensureLocallyIgnored} — the other half of `unlink`.
|
|
204
|
+
*
|
|
205
|
+
* Measured: the `info/exclude` block outlived `gjsify unlink` (idempotently,
|
|
206
|
+
* so it never grew — it just never left). A command that promises to undo itself
|
|
207
|
+
* and leaves a line behind is not an undo, and the leftover is a rule about a file
|
|
208
|
+
* that no longer exists, which the next reader has to research to delete.
|
|
209
|
+
*
|
|
210
|
+
* ONLY the two lines this module wrote, matched as a pair: a `.gitignore` entry or
|
|
211
|
+
* a hand-written exclude line is someone else's decision, and removing it would be
|
|
212
|
+
* the same overreach `removeDevLinks` refuses.
|
|
213
|
+
*/
|
|
214
|
+
export declare function removeLocalIgnore(consumerRoot: string): 'removed' | 'absent' | 'no-git' | 'unreadable-git';
|
|
215
|
+
/**
|
|
216
|
+
* `--immutable` must never accept an active override — FAIL CLOSED.
|
|
217
|
+
*
|
|
218
|
+
* CI, a Flatpak build and a release all run `--immutable`, and all three exist to
|
|
219
|
+
* build exactly what is committed. An override is a developer's local tree, so
|
|
220
|
+
* consuming one here would produce an artifact whose inputs are not in any
|
|
221
|
+
* commit and whose build reported nothing unusual. Refusing names the file,
|
|
222
|
+
* because the fix is to delete it and the message is the only place its path
|
|
223
|
+
* appears.
|
|
224
|
+
*/
|
|
225
|
+
export declare function assertNoDevLinkUnderImmutable(startDir: string): void;
|