@gjsify/cli 0.51.0 → 0.52.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 +505 -490
- package/lib/cli-app.js +3 -1
- 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/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/index.d.ts +1 -0
- package/lib/commands/index.js +1 -0
- package/lib/commands/install.js +76 -0
- 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/ship.js +46 -4
- package/lib/types/config-data.d.ts +1 -1
- package/lib/utils/check-system-deps.d.ts +1 -17
- package/lib/utils/check-system-deps.js +10 -68
- package/lib/utils/dev-link.d.ts +222 -0
- package/lib/utils/dev-link.js +632 -0
- 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 +14 -0
- package/lib/utils/install-backend-native.js +91 -13
- package/lib/utils/install-extraneous.d.ts +90 -0
- package/lib/utils/install-extraneous.js +120 -0
- package/lib/utils/install-tarball-cache.d.ts +37 -9
- package/lib/utils/install-tarball-cache.js +59 -14
- package/lib/utils/normalize-bundler-options.js +11 -0
- 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.js +82 -6
- package/lib/utils/ship/appimage.d.ts +24 -4
- package/lib/utils/ship/appimage.js +51 -6
- package/lib/utils/ship/formats.js +44 -11
- 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 +191 -0
- package/lib/utils/ship/icons.js +398 -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/schemas.d.ts +46 -0
- package/lib/utils/ship/schemas.js +92 -11
- package/lib/utils/ship/settings.js +3 -2
- package/package.json +20 -20
package/lib/commands/ship.js
CHANGED
|
@@ -35,12 +35,13 @@ import { discoverPayload } from '../utils/ship/discover.js';
|
|
|
35
35
|
import { appDirFor, appDirPayload, appImageHostRequirements, appImageRuntimeNotice, buildAppImage, findPinnedRuntime, stampAppDirTimes, } from '../utils/ship/appimage.js';
|
|
36
36
|
import { buildDmgImage, dmgVolumeDir, dmgVolumeName } from '../utils/ship/dmg.js';
|
|
37
37
|
import { buildFlatpakBundle } from '../utils/ship/flatpak.js';
|
|
38
|
+
import { iconSizes, resolveAppIcon } from '../utils/ship/icons.js';
|
|
38
39
|
import { localizeMetadata } from '../utils/ship/localize-metadata.js';
|
|
39
40
|
import { assertHostCanFinish, assertKindCanPack, assertToolsInstalled, canCarryTicket, configuredFormats, defaultFormatIds, formatIdsFor, resolveFormats, windowsProgramDirName, FORMAT_IDS, FORMATS, } from '../utils/ship/formats.js';
|
|
40
41
|
import { assertLayoutSupportsArch, hostLayout, layoutForOs, place, placeStage, resolveLayout, LAYOUT_NAMES, } from '../utils/ship/layout.js';
|
|
41
42
|
import { isNodeRuntimeTarget, resolveNodeRuntime } from '../utils/ship/node-runtime.js';
|
|
42
43
|
import { isUnder, SHARE } from '../utils/ship/share-dirs.js';
|
|
43
|
-
import { compileSchemasForStage } from '../utils/ship/schemas.js';
|
|
44
|
+
import { compileSchemasForPayload, compileSchemasForStage } from '../utils/ship/schemas.js';
|
|
44
45
|
import { buildMsi, MSI_PAYLOAD_DIR } from '../utils/ship/msi.js';
|
|
45
46
|
import { buildZip, zipEntriesFromPayload } from '../utils/ship/zip.js';
|
|
46
47
|
import { assertEntryRunsUnder } from '../utils/ship/entry-interpreter.js';
|
|
@@ -416,7 +417,14 @@ async function assemble(args) {
|
|
|
416
417
|
// `.deb`/`.rpm` postinst compiles the SYSTEM directory at install time
|
|
417
418
|
// (`utils/ship/scripts.ts`), where our schemas merge with every other
|
|
418
419
|
// package's — shipping a prebuilt cache there would be a file the install step
|
|
419
|
-
// overwrites
|
|
420
|
+
// overwrites, and one `rpm -e` takes away with it.
|
|
421
|
+
//
|
|
422
|
+
// WHICH IS WHY THIS CONDITION IS ABOUT THE STAGE AND NOT ABOUT INSTALL STEPS,
|
|
423
|
+
// a distinction that used to be invisible because the two agreed. They stopped
|
|
424
|
+
// agreeing when the AppImage landed: it takes the Linux layout and has no
|
|
425
|
+
// install step at all. It does not get its cache from here — a Linux stage
|
|
426
|
+
// serves three formats and only one of them wants one — it compiles its own
|
|
427
|
+
// into the AppDir, on its own pack path (`packOne`, `case 'appimage'`).
|
|
420
428
|
const planned = [
|
|
421
429
|
...planStage(settings, stageInputs),
|
|
422
430
|
...(layout.os === 'linux'
|
|
@@ -426,7 +434,24 @@ async function assemble(args) {
|
|
|
426
434
|
workDir: join(outRoot, 'schemas'),
|
|
427
435
|
})),
|
|
428
436
|
];
|
|
429
|
-
|
|
437
|
+
// THE APPLICATION ICON, rendered once for the sizes this layout's writers
|
|
438
|
+
// embed — six for the `.exe`'s resource directory, seven for the `.icns` —
|
|
439
|
+
// and nothing for a CLI or for Linux, where the theme carries the SVG the
|
|
440
|
+
// project declared. `resolveAppIcon` REFUSES an app that has no source for a
|
|
441
|
+
// size rather than staging without it: the released artifacts this closes
|
|
442
|
+
// shipped for a year with the generic icon on two platforms, and the only
|
|
443
|
+
// reason was that nothing said so (`utils/ship/icons.ts`).
|
|
444
|
+
const icon = settings.kind === 'app' && layout.icon !== undefined
|
|
445
|
+
? await resolveAppIcon({
|
|
446
|
+
iconFiles: settings.iconFiles,
|
|
447
|
+
appId: settings.appId,
|
|
448
|
+
sizes: layout.icon.sizes,
|
|
449
|
+
target: layout.icon.writes,
|
|
450
|
+
})
|
|
451
|
+
: undefined;
|
|
452
|
+
if (icon !== undefined)
|
|
453
|
+
console.log(`${LOG} icon: ${iconSizes(icon).join('/')} px, ${icon.source}`);
|
|
454
|
+
const staged = placeStage(layout, { ...settings, icon }, planned, runtime.files);
|
|
430
455
|
writeStage(stageDir, staged);
|
|
431
456
|
console.log(`${LOG} staged ${staged.length} file(s) for ${layout.name} in ${relative(projectDir, stageDir)}/`);
|
|
432
457
|
if (args.verbose)
|
|
@@ -988,7 +1013,24 @@ async function packOne(input) {
|
|
|
988
1013
|
bundledTypelibs: facts.bundledTypelibs,
|
|
989
1014
|
});
|
|
990
1015
|
const appDir = appDirFor(outRoot);
|
|
991
|
-
|
|
1016
|
+
// THE ONE FILE THIS FORMAT ADDS TO THE PAYLOAD, and the reason it is
|
|
1017
|
+
// added HERE and not where every other layout's is (the stage, above).
|
|
1018
|
+
// An AppImage has no install step; the Linux layout it inherits assumes
|
|
1019
|
+
// one, because until this format existed every Linux artifact had a
|
|
1020
|
+
// `postinst`. The compile cannot move up into the stage: the Linux stage
|
|
1021
|
+
// is shared with the `.deb` and the `.rpm`, whose `share/glib-2.0/schemas`
|
|
1022
|
+
// is `/usr/share/glib-2.0/schemas` — the SYSTEM directory — and a cache
|
|
1023
|
+
// staged there is this app's 700 bytes installed over every other
|
|
1024
|
+
// package's schemas, then taken away with `rpm -e`.
|
|
1025
|
+
//
|
|
1026
|
+
// FROM THE PAYLOAD, like the host requirements two lines up and for the
|
|
1027
|
+
// same reason: `--from-stage` has the schema BYTES and not the project
|
|
1028
|
+
// directory they were read from.
|
|
1029
|
+
const schemaCache = await compileSchemasForPayload({
|
|
1030
|
+
payload,
|
|
1031
|
+
workDir: join(outRoot, 'appimage-schemas'),
|
|
1032
|
+
});
|
|
1033
|
+
const tree = appDirPayload(settings, payload, hostRequirements, schemaCache);
|
|
992
1034
|
// ONE `writePayload` FOR THE WHOLE AppDir, prefix and root files
|
|
993
1035
|
// together, because that call WIPES: two of them would leave the
|
|
994
1036
|
// previous run's `<appId>.desktop` and icon at a root the second call
|
|
@@ -771,7 +771,7 @@ export interface ConfigDataFlatpak extends AppMetadata {
|
|
|
771
771
|
command?: string;
|
|
772
772
|
/** Finish-args (capabilities). Default depends on `runtime` + `--cli-only`. */
|
|
773
773
|
finishArgs?: string[];
|
|
774
|
-
/** Extra Flatpak modules prepended before the app's own meson/simple module (e.g.
|
|
774
|
+
/** Extra Flatpak modules prepended before the app's own meson/simple module (e.g. a GI library the runtime lacks). */
|
|
775
775
|
extraModules?: unknown[];
|
|
776
776
|
/**
|
|
777
777
|
* Full replacement for the manifest's `modules` array: used verbatim, with
|
|
@@ -118,7 +118,7 @@ export declare const PACKAGE_DEPS: Record<string, string[]>;
|
|
|
118
118
|
* Run all dependency checks. Used by `gjsify check` to show full system status.
|
|
119
119
|
*
|
|
120
120
|
* Required deps (gjs, gtk4, libsoup3, libadwaita, gobject-introspection,
|
|
121
|
-
*
|
|
121
|
+
* pkg-config, meson) are always checked.
|
|
122
122
|
*
|
|
123
123
|
* Optional deps are checked conditionally based on which @gjsify/* packages
|
|
124
124
|
* the project (resolved from cwd) actually consumes. If no project context
|
|
@@ -130,22 +130,6 @@ export declare function runAllChecks(cwd: string): DepCheck[];
|
|
|
130
130
|
* not required). Used by `gjsify showcase` for examples that have no native deps.
|
|
131
131
|
*/
|
|
132
132
|
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
133
|
/** Check gwebgl npm package (project first, CLI fallback). Optional — only needed by @gjsify/webgl users. */
|
|
150
134
|
export declare function checkGwebgl(cwd: string): DepCheck;
|
|
151
135
|
/**
|
|
@@ -15,9 +15,6 @@ 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';
|
|
23
20
|
/** Run a binary and return its stdout trimmed, or null if it fails. */
|
|
@@ -393,7 +390,7 @@ function computeNeededOptionalDeps(cwd) {
|
|
|
393
390
|
* Run all dependency checks. Used by `gjsify check` to show full system status.
|
|
394
391
|
*
|
|
395
392
|
* Required deps (gjs, gtk4, libsoup3, libadwaita, gobject-introspection,
|
|
396
|
-
*
|
|
393
|
+
* pkg-config, meson) are always checked.
|
|
397
394
|
*
|
|
398
395
|
* Optional deps are checked conditionally based on which @gjsify/* packages
|
|
399
396
|
* the project (resolved from cwd) actually consumes. If no project context
|
|
@@ -454,53 +451,19 @@ export function runMinimalChecks() {
|
|
|
454
451
|
results.push(checkMsvcRuntime());
|
|
455
452
|
return results;
|
|
456
453
|
}
|
|
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
454
|
/** Check gwebgl npm package (project first, CLI fallback). Optional — only needed by @gjsify/webgl users. */
|
|
484
455
|
export function checkGwebgl(cwd) {
|
|
485
456
|
return checkNpmPackage('gwebgl', 'gwebgl (@gjsify/webgl)', '@gjsify/webgl', cwd, 'optional', ['@gjsify/webgl']);
|
|
486
457
|
}
|
|
487
458
|
/**
|
|
488
459
|
* Required system dependencies — always checked, missing → exit 1.
|
|
489
|
-
* Includes the core build toolchain (pkg-config, meson
|
|
490
|
-
*
|
|
491
|
-
*
|
|
460
|
+
* Includes the core build toolchain (pkg-config, meson) and the foundational
|
|
461
|
+
* libraries (gtk4, libadwaita, libsoup3, gobject-introspection) that nearly
|
|
462
|
+
* every gjsify app needs.
|
|
492
463
|
*/
|
|
493
464
|
function runRequiredChecks(_cwd) {
|
|
494
465
|
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.
|
|
466
|
+
// Build toolchain.
|
|
504
467
|
results.push(checkBinary('pkg-config', 'pkg-config', 'pkg-config', ['--version'], 'required'));
|
|
505
468
|
results.push(checkBinary('meson', 'Meson', 'meson', ['--version'], 'required'));
|
|
506
469
|
// Foundational libraries — by TYPELIB, the runtime question. See checkGiLibrary.
|
|
@@ -549,13 +512,12 @@ function runNativeBuildToolchainChecks() {
|
|
|
549
512
|
// Narrower on purpose: only the three bridges that link an upstream Rust
|
|
550
513
|
// crate by Cargo path-dependency need a Rust toolchain.
|
|
551
514
|
const rustBridges = ['@gjsify/lightningcss-native', '@gjsify/oxfmt-native', '@gjsify/rolldown-native'];
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
//
|
|
556
|
-
|
|
515
|
+
// NO blueprint-compiler row, and it is a deletion rather than an omission: ADR 0053 clause 5
|
|
516
|
+
// moved the `.blp` transform into `@gjsify/blueprint`, so a `.blp` template asks nothing of
|
|
517
|
+
// this host any more. A row for it would be this command asking for a toolchain the build
|
|
518
|
+
// cannot use — the exact "check failing for the wrong reason" its own history is made of.
|
|
519
|
+
// ADR 0063 is the deletion and what the compiler is still FOR.
|
|
557
520
|
return [
|
|
558
|
-
checkBlueprintCompiler(blueprintConsumers),
|
|
559
521
|
checkBinary('ninja', 'Ninja', 'ninja', ['--version'], 'optional', undefined, valaBridges),
|
|
560
522
|
checkBinary('vala', 'Vala', 'valac', ['--version'], 'optional', (out) => out.replace(/^Vala\s+/i, ''), valaBridges),
|
|
561
523
|
checkBinary('cargo', 'Cargo (Rust)', 'cargo', ['--version'], 'optional', (out) => out.replace(/^cargo\s+/i, '').split(' ')[0] ?? out, rustBridges),
|
|
@@ -596,7 +558,6 @@ const PM_PACKAGES = {
|
|
|
596
558
|
apt: {
|
|
597
559
|
nodejs: 'nodejs',
|
|
598
560
|
gjs: 'gjs',
|
|
599
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
600
561
|
'pkg-config': 'pkg-config',
|
|
601
562
|
meson: 'meson',
|
|
602
563
|
ninja: 'ninja-build',
|
|
@@ -622,7 +583,6 @@ const PM_PACKAGES = {
|
|
|
622
583
|
dnf: {
|
|
623
584
|
nodejs: 'nodejs',
|
|
624
585
|
gjs: 'gjs',
|
|
625
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
626
586
|
'pkg-config': 'pkgconf-pkg-config',
|
|
627
587
|
meson: 'meson',
|
|
628
588
|
ninja: 'ninja-build',
|
|
@@ -648,7 +608,6 @@ const PM_PACKAGES = {
|
|
|
648
608
|
pacman: {
|
|
649
609
|
nodejs: 'nodejs',
|
|
650
610
|
gjs: 'gjs',
|
|
651
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
652
611
|
'pkg-config': 'pkgconf',
|
|
653
612
|
meson: 'meson',
|
|
654
613
|
ninja: 'ninja',
|
|
@@ -674,7 +633,6 @@ const PM_PACKAGES = {
|
|
|
674
633
|
zypper: {
|
|
675
634
|
nodejs: 'nodejs',
|
|
676
635
|
gjs: 'gjs',
|
|
677
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
678
636
|
'pkg-config': 'pkg-config',
|
|
679
637
|
meson: 'meson',
|
|
680
638
|
ninja: 'ninja',
|
|
@@ -700,7 +658,6 @@ const PM_PACKAGES = {
|
|
|
700
658
|
apk: {
|
|
701
659
|
nodejs: 'nodejs',
|
|
702
660
|
gjs: 'gjs',
|
|
703
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
704
661
|
'pkg-config': 'pkgconf',
|
|
705
662
|
meson: 'meson',
|
|
706
663
|
ninja: 'ninja',
|
|
@@ -748,7 +705,6 @@ const PM_PACKAGES = {
|
|
|
748
705
|
brew: {
|
|
749
706
|
nodejs: 'node',
|
|
750
707
|
gjs: 'gjs',
|
|
751
|
-
'blueprint-compiler': 'blueprint-compiler',
|
|
752
708
|
'pkg-config': 'pkgconf',
|
|
753
709
|
meson: 'meson',
|
|
754
710
|
ninja: 'ninja',
|
|
@@ -804,24 +760,11 @@ export function buildInstallCommand(pm, missing) {
|
|
|
804
760
|
const pkgMap = PM_PACKAGES[pm];
|
|
805
761
|
const pkgs = [];
|
|
806
762
|
const npmDeps = [];
|
|
807
|
-
const standalone = [];
|
|
808
763
|
for (const dep of missing) {
|
|
809
764
|
if (dep.id === 'gwebgl') {
|
|
810
765
|
npmDeps.push('@gjsify/webgl');
|
|
811
766
|
continue;
|
|
812
767
|
}
|
|
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
768
|
// No `continue` for `nodejs`. It USED to be unmissable — the row was the
|
|
826
769
|
// literal `found: true` — and since it became a real probe it can report
|
|
827
770
|
// absent under GJS, so skipping it here printed "Missing optional: Node.js"
|
|
@@ -842,7 +785,6 @@ export function buildInstallCommand(pm, missing) {
|
|
|
842
785
|
if (npmDeps.length > 0) {
|
|
843
786
|
lines.push(`npm install ${npmDeps.join(' ')}`);
|
|
844
787
|
}
|
|
845
|
-
lines.push(...standalone);
|
|
846
788
|
return lines.length > 0 ? lines.join('\n ') : null;
|
|
847
789
|
}
|
|
848
790
|
/**
|
|
@@ -0,0 +1,222 @@
|
|
|
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
|
+
* `.git/info/exclude` is git's own per-clone ignore list: it is not committed and
|
|
188
|
+
* not shared, which is exactly the lifetime of the thing it hides. Writing to
|
|
189
|
+
* `.gitignore` instead would put a developer's local override into everyone
|
|
190
|
+
* else's diff — the manifest edit this whole feature exists to avoid, one file
|
|
191
|
+
* over.
|
|
192
|
+
*
|
|
193
|
+
* Returns what it did, so the caller can say so. A consumer that is not a git
|
|
194
|
+
* repository is not an error: nothing can commit the file there either. A
|
|
195
|
+
* consumer whose `.git` POINTER cannot be followed IS worth a word, though —
|
|
196
|
+
* there the file stays visible to `git status` and one `git add -A` commits it.
|
|
197
|
+
*/
|
|
198
|
+
export declare function ensureLocallyIgnored(consumerRoot: string): 'added' | 'already-ignored' | 'no-git' | 'unreadable-git';
|
|
199
|
+
/**
|
|
200
|
+
* Undo {@link ensureLocallyIgnored} — the other half of `unlink`.
|
|
201
|
+
*
|
|
202
|
+
* Measured: the `.git/info/exclude` block outlived `gjsify unlink` (idempotently,
|
|
203
|
+
* so it never grew — it just never left). A command that promises to undo itself
|
|
204
|
+
* and leaves a line behind is not an undo, and the leftover is a rule about a file
|
|
205
|
+
* that no longer exists, which the next reader has to research to delete.
|
|
206
|
+
*
|
|
207
|
+
* ONLY the two lines this module wrote, matched as a pair: a `.gitignore` entry or
|
|
208
|
+
* a hand-written exclude line is someone else's decision, and removing it would be
|
|
209
|
+
* the same overreach `removeDevLinks` refuses.
|
|
210
|
+
*/
|
|
211
|
+
export declare function removeLocalIgnore(consumerRoot: string): 'removed' | 'absent' | 'no-git' | 'unreadable-git';
|
|
212
|
+
/**
|
|
213
|
+
* `--immutable` must never accept an active override — FAIL CLOSED.
|
|
214
|
+
*
|
|
215
|
+
* CI, a Flatpak build and a release all run `--immutable`, and all three exist to
|
|
216
|
+
* build exactly what is committed. An override is a developer's local tree, so
|
|
217
|
+
* consuming one here would produce an artifact whose inputs are not in any
|
|
218
|
+
* commit and whose build reported nothing unusual. Refusing names the file,
|
|
219
|
+
* because the fix is to delete it and the message is the only place its path
|
|
220
|
+
* appears.
|
|
221
|
+
*/
|
|
222
|
+
export declare function assertNoDevLinkUnderImmutable(startDir: string): void;
|