@gtkx/cli 1.6.0 → 2.0.0-beta.2
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/README.md +5 -5
- package/dist/builder.d.ts +1 -0
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +17 -5
- package/dist/builder.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/codegen/freshness.d.ts.map +1 -1
- package/dist/codegen/freshness.js +45 -16
- package/dist/codegen/freshness.js.map +1 -1
- package/dist/codegen/reference.d.ts.map +1 -1
- package/dist/codegen/reference.js +1 -7
- package/dist/codegen/reference.js.map +1 -1
- package/dist/codegen/report.d.ts.map +1 -1
- package/dist/codegen/report.js +5 -16
- package/dist/codegen/report.js.map +1 -1
- package/dist/codegen/run-codegen.d.ts +7 -7
- package/dist/codegen/run-codegen.d.ts.map +1 -1
- package/dist/codegen/run-codegen.js +35 -107
- package/dist/codegen/run-codegen.js.map +1 -1
- package/dist/codegen/store-resolver.d.ts +1 -2
- package/dist/codegen/store-resolver.d.ts.map +1 -1
- package/dist/codegen/store-resolver.js +10 -19
- package/dist/codegen/store-resolver.js.map +1 -1
- package/dist/commands/build.d.ts +5 -0
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +83 -10
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/codegen.d.ts +1 -0
- package/dist/commands/codegen.d.ts.map +1 -1
- package/dist/commands/codegen.js +6 -5
- package/dist/commands/codegen.js.map +1 -1
- package/dist/commands/deploy.d.ts +1 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +4 -2
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +8 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +19 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +5 -15
- package/dist/commands/docs.js.map +1 -1
- package/dist/deploy/freedesktop/copyright.d.ts.map +1 -1
- package/dist/deploy/freedesktop/copyright.js +2 -13
- package/dist/deploy/freedesktop/copyright.js.map +1 -1
- package/dist/deploy/freedesktop/metainfo.d.ts.map +1 -1
- package/dist/deploy/freedesktop/metainfo.js +41 -2
- package/dist/deploy/freedesktop/metainfo.js.map +1 -1
- package/dist/deploy/freedesktop/xml.d.ts.map +1 -1
- package/dist/deploy/freedesktop/xml.js +21 -25
- package/dist/deploy/freedesktop/xml.js.map +1 -1
- package/dist/deploy/nfpm/config.d.ts.map +1 -1
- package/dist/deploy/nfpm/config.js +5 -2
- package/dist/deploy/nfpm/config.js.map +1 -1
- package/dist/deploy/nfpm/contents.d.ts.map +1 -1
- package/dist/deploy/nfpm/contents.js +8 -0
- package/dist/deploy/nfpm/contents.js.map +1 -1
- package/dist/deploy/node-runtime/elf.d.ts +2 -1
- package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
- package/dist/deploy/node-runtime/elf.js +32 -5
- package/dist/deploy/node-runtime/elf.js.map +1 -1
- package/dist/deploy/node-runtime/index.d.ts +2 -1
- package/dist/deploy/node-runtime/index.d.ts.map +1 -1
- package/dist/deploy/node-runtime/index.js +73 -4
- package/dist/deploy/node-runtime/index.js.map +1 -1
- package/dist/deploy/node-runtime/license.d.ts.map +1 -1
- package/dist/deploy/node-runtime/license.js +2 -9
- package/dist/deploy/node-runtime/license.js.map +1 -1
- package/dist/deploy/notices/node-runtime.js +2 -2
- package/dist/deploy/notices/node-runtime.js.map +1 -1
- package/dist/deploy/notices/packages.d.ts.map +1 -1
- package/dist/deploy/notices/packages.js +3 -10
- package/dist/deploy/notices/packages.js.map +1 -1
- package/dist/deploy/payload/copy-tree.d.ts.map +1 -1
- package/dist/deploy/payload/copy-tree.js +3 -3
- package/dist/deploy/payload/copy-tree.js.map +1 -1
- package/dist/deploy/payload/launcher.d.ts.map +1 -1
- package/dist/deploy/payload/launcher.js +14 -1
- package/dist/deploy/payload/launcher.js.map +1 -1
- package/dist/deploy/payload/stage.d.ts.map +1 -1
- package/dist/deploy/payload/stage.js +2 -4
- package/dist/deploy/payload/stage.js.map +1 -1
- package/dist/deploy/run-deploy.d.ts +1 -0
- package/dist/deploy/run-deploy.d.ts.map +1 -1
- package/dist/deploy/run-deploy.js +100 -14
- package/dist/deploy/run-deploy.js.map +1 -1
- package/dist/deploy/settings/build-manifest.d.ts +6 -1
- package/dist/deploy/settings/build-manifest.d.ts.map +1 -1
- package/dist/deploy/settings/build-manifest.js +17 -17
- package/dist/deploy/settings/build-manifest.js.map +1 -1
- package/dist/deploy/settings/extra-files.d.ts +1 -1
- package/dist/deploy/settings/extra-files.d.ts.map +1 -1
- package/dist/deploy/settings/extra-files.js +22 -1
- package/dist/deploy/settings/extra-files.js.map +1 -1
- package/dist/deploy/settings/index.d.ts +1 -0
- package/dist/deploy/settings/index.d.ts.map +1 -1
- package/dist/deploy/settings/index.js +2 -1
- package/dist/deploy/settings/index.js.map +1 -1
- package/dist/deploy/settings/libraries.d.ts.map +1 -1
- package/dist/deploy/settings/libraries.js +2 -19
- package/dist/deploy/settings/libraries.js.map +1 -1
- package/dist/deploy/settings/paths.d.ts +2 -2
- package/dist/deploy/settings/paths.d.ts.map +1 -1
- package/dist/deploy/settings/paths.js +110 -12
- package/dist/deploy/settings/paths.js.map +1 -1
- package/dist/deploy/settings/screenshots.d.ts.map +1 -1
- package/dist/deploy/settings/screenshots.js +6 -31
- package/dist/deploy/settings/screenshots.js.map +1 -1
- package/dist/deploy/targets/flatpak-pnpm.js +4 -4
- package/dist/deploy/targets/flatpak-pnpm.js.map +1 -1
- package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
- package/dist/deploy/targets/flatpak-source.js +15 -6
- package/dist/deploy/targets/flatpak-source.js.map +1 -1
- package/dist/deploy/targets/flatpak-sources.js +1 -1
- package/dist/deploy/targets/flatpak-sources.js.map +1 -1
- package/dist/deploy/types.d.ts +1 -0
- package/dist/deploy/types.d.ts.map +1 -1
- package/dist/deploy/types.js.map +1 -1
- package/dist/dev/headless.d.ts +3 -0
- package/dist/dev/headless.d.ts.map +1 -0
- package/dist/dev/headless.js +35 -0
- package/dist/dev/headless.js.map +1 -0
- package/dist/dev/runner-deps.js +1 -1
- package/dist/dev/runner-deps.js.map +1 -1
- package/dist/dev/runner-main.d.ts.map +1 -1
- package/dist/dev/runner-main.js +1 -2
- package/dist/dev/runner-main.js.map +1 -1
- package/dist/dev/schema-dir.d.ts +1 -1
- package/dist/dev/schema-dir.d.ts.map +1 -1
- package/dist/dev/schema-dir.js +2 -4
- package/dist/dev/schema-dir.js.map +1 -1
- package/dist/i18n/catalogs.d.ts.map +1 -1
- package/dist/i18n/catalogs.js +2 -1
- package/dist/i18n/catalogs.js.map +1 -1
- package/dist/i18n/metadata-templates.d.ts.map +1 -1
- package/dist/i18n/metadata-templates.js +2 -1
- package/dist/i18n/metadata-templates.js.map +1 -1
- package/dist/i18n/source-messages.d.ts +3 -21
- package/dist/i18n/source-messages.d.ts.map +1 -1
- package/dist/i18n/source-messages.js +900 -85
- package/dist/i18n/source-messages.js.map +1 -1
- package/dist/i18n/types.d.ts +6 -7
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/i18n/types.js +83 -96
- package/dist/i18n/types.js.map +1 -1
- package/dist/internal/build-manifest.d.ts +5 -2
- package/dist/internal/build-manifest.d.ts.map +1 -1
- package/dist/internal/build-manifest.js +15 -2
- package/dist/internal/build-manifest.js.map +1 -1
- package/dist/internal/build-output.d.ts +8 -0
- package/dist/internal/build-output.d.ts.map +1 -0
- package/dist/internal/build-output.js +69 -0
- package/dist/internal/build-output.js.map +1 -0
- package/dist/internal/docs-elements.js +2 -2
- package/dist/internal/docs-elements.js.map +1 -1
- package/dist/internal/entry-arg.d.ts +4 -1
- package/dist/internal/entry-arg.d.ts.map +1 -1
- package/dist/internal/entry-arg.js +7 -1
- package/dist/internal/entry-arg.js.map +1 -1
- package/dist/internal/icon-path.d.ts.map +1 -1
- package/dist/internal/icon-path.js +5 -16
- package/dist/internal/icon-path.js.map +1 -1
- package/dist/internal/output-directory.d.ts +15 -0
- package/dist/internal/output-directory.d.ts.map +1 -0
- package/dist/internal/output-directory.js +490 -0
- package/dist/internal/output-directory.js.map +1 -0
- package/dist/internal/prepare-project.d.ts +2 -0
- package/dist/internal/prepare-project.d.ts.map +1 -1
- package/dist/internal/prepare-project.js +3 -3
- package/dist/internal/prepare-project.js.map +1 -1
- package/dist/internal/source-imports.d.ts.map +1 -1
- package/dist/internal/source-imports.js +10 -41
- package/dist/internal/source-imports.js.map +1 -1
- package/dist/mcp/client.js +2 -2
- package/dist/mcp/client.js.map +1 -1
- package/dist/settings/render.d.ts +0 -1
- package/dist/settings/render.d.ts.map +1 -1
- package/dist/settings/render.js +1 -11
- package/dist/settings/render.js.map +1 -1
- package/dist/settings/schema.d.ts +2 -2
- package/dist/settings/schema.d.ts.map +1 -1
- package/dist/settings/schema.js +21 -62
- package/dist/settings/schema.js.map +1 -1
- package/dist/vite-plugins/asset-imports.d.ts +1 -2
- package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
- package/dist/vite-plugins/asset-imports.js +19 -32
- package/dist/vite-plugins/asset-imports.js.map +1 -1
- package/dist/vite-plugins/asset-specifier.d.ts +1 -3
- package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
- package/dist/vite-plugins/asset-specifier.js +1 -4
- package/dist/vite-plugins/asset-specifier.js.map +1 -1
- package/dist/vite-plugins/build-manifest.d.ts +5 -1
- package/dist/vite-plugins/build-manifest.d.ts.map +1 -1
- package/dist/vite-plugins/build-manifest.js +2 -1
- package/dist/vite-plugins/build-manifest.js.map +1 -1
- package/dist/vite-plugins/i18n.d.ts.map +1 -1
- package/dist/vite-plugins/i18n.js +59 -6
- package/dist/vite-plugins/i18n.js.map +1 -1
- package/dist/vite-plugins/index.d.ts +8 -1
- package/dist/vite-plugins/index.d.ts.map +1 -1
- package/dist/vite-plugins/index.js +8 -6
- package/dist/vite-plugins/index.js.map +1 -1
- package/dist/vite-plugins/resources.d.ts.map +1 -1
- package/dist/vite-plugins/resources.js +32 -97
- package/dist/vite-plugins/resources.js.map +1 -1
- package/dist/vite-plugins/self-contained.d.ts.map +1 -1
- package/dist/vite-plugins/self-contained.js +159 -158
- package/dist/vite-plugins/self-contained.js.map +1 -1
- package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
- package/dist/vite-plugins/settings-worker-env.js +2 -4
- package/dist/vite-plugins/settings-worker-env.js.map +1 -1
- package/dist/vite-plugins/settings.d.ts +1 -2
- package/dist/vite-plugins/settings.d.ts.map +1 -1
- package/dist/vite-plugins/settings.js +8 -14
- package/dist/vite-plugins/settings.js.map +1 -1
- package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
- package/dist/vite-plugins/undeclared-library.js +10 -13
- package/dist/vite-plugins/undeclared-library.js.map +1 -1
- package/dist/vite-plugins/worker.d.ts.map +1 -1
- package/dist/vite-plugins/worker.js +0 -1
- package/dist/vite-plugins/worker.js.map +1 -1
- package/package.json +21 -15
- package/src/builder.ts +18 -5
- package/src/cli.ts +3 -0
- package/src/codegen/freshness.ts +66 -17
- package/src/codegen/reference.ts +1 -8
- package/src/codegen/report.ts +5 -21
- package/src/codegen/run-codegen.ts +42 -151
- package/src/codegen/store-resolver.ts +10 -26
- package/src/commands/build.ts +13 -2
- package/src/commands/codegen.ts +6 -5
- package/src/commands/deploy.ts +4 -2
- package/src/commands/dev.ts +20 -1
- package/src/commands/docs.ts +5 -17
- package/src/deploy/freedesktop/copyright.ts +2 -14
- package/src/deploy/freedesktop/metainfo.ts +73 -21
- package/src/deploy/freedesktop/xml.ts +24 -32
- package/src/deploy/nfpm/config.ts +5 -2
- package/src/deploy/nfpm/contents.ts +8 -0
- package/src/deploy/node-runtime/elf.ts +43 -5
- package/src/deploy/node-runtime/index.ts +105 -5
- package/src/deploy/node-runtime/license.ts +2 -8
- package/src/deploy/notices/node-runtime.ts +2 -2
- package/src/deploy/notices/packages.ts +3 -11
- package/src/deploy/payload/copy-tree.ts +3 -4
- package/src/deploy/payload/launcher.ts +20 -1
- package/src/deploy/payload/stage.ts +3 -7
- package/src/deploy/run-deploy.ts +56 -16
- package/src/deploy/settings/build-manifest.ts +30 -17
- package/src/deploy/settings/extra-files.ts +26 -2
- package/src/deploy/settings/index.ts +3 -1
- package/src/deploy/settings/libraries.ts +1 -22
- package/src/deploy/settings/paths.ts +68 -13
- package/src/deploy/settings/screenshots.ts +8 -46
- package/src/deploy/targets/flatpak-pnpm.ts +4 -4
- package/src/deploy/targets/flatpak-source.ts +17 -6
- package/src/deploy/targets/flatpak-sources.ts +1 -1
- package/src/deploy/types.ts +1 -0
- package/src/dev/headless.ts +40 -0
- package/src/dev/runner-deps.ts +1 -1
- package/src/dev/runner-main.ts +1 -2
- package/src/dev/schema-dir.ts +2 -4
- package/src/i18n/catalogs.ts +2 -1
- package/src/i18n/metadata-templates.ts +2 -1
- package/src/i18n/source-messages.ts +1442 -262
- package/src/i18n/types.ts +97 -131
- package/src/internal/build-manifest.ts +25 -1
- package/src/internal/build-output.ts +99 -0
- package/src/internal/docs-elements.ts +2 -2
- package/src/internal/entry-arg.ts +8 -1
- package/src/internal/icon-path.ts +6 -19
- package/src/internal/output-directory.ts +699 -0
- package/src/internal/prepare-project.ts +5 -5
- package/src/internal/source-imports.ts +14 -50
- package/src/mcp/client.ts +2 -2
- package/src/settings/render.ts +1 -13
- package/src/settings/schema.ts +19 -81
- package/src/vite-plugins/asset-imports.ts +20 -44
- package/src/vite-plugins/asset-specifier.ts +0 -5
- package/src/vite-plugins/build-manifest.ts +7 -1
- package/src/vite-plugins/i18n.ts +87 -5
- package/src/vite-plugins/index.ts +16 -11
- package/src/vite-plugins/resources.ts +37 -140
- package/src/vite-plugins/self-contained.ts +184 -185
- package/src/vite-plugins/settings-worker-env.ts +2 -4
- package/src/vite-plugins/settings.ts +11 -20
- package/src/vite-plugins/undeclared-library.ts +14 -20
- package/src/vite-plugins/worker.ts +0 -1
- package/dist/i18n/binding-extractor.d.ts +0 -30
- package/dist/i18n/binding-extractor.d.ts.map +0 -1
- package/dist/i18n/binding-extractor.js +0 -1324
- package/dist/i18n/binding-extractor.js.map +0 -1
- package/dist/i18n/extractor-plugin.d.ts +0 -8
- package/dist/i18n/extractor-plugin.d.ts.map +0 -1
- package/dist/i18n/extractor-plugin.js +0 -247
- package/dist/i18n/extractor-plugin.js.map +0 -1
- package/dist/internal/data-dir.d.ts +0 -4
- package/dist/internal/data-dir.d.ts.map +0 -1
- package/dist/internal/data-dir.js +0 -52
- package/dist/internal/data-dir.js.map +0 -1
- package/dist/vite-plugins/animated.d.ts +0 -5
- package/dist/vite-plugins/animated.d.ts.map +0 -1
- package/dist/vite-plugins/animated.js +0 -325
- package/dist/vite-plugins/animated.js.map +0 -1
- package/src/i18n/binding-extractor.ts +0 -1969
- package/src/i18n/extractor-plugin.ts +0 -413
- package/src/internal/data-dir.ts +0 -70
- package/src/vite-plugins/animated.ts +0 -486
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import type { DeploySettings, Notice, NoticeSection } from "../types.js";
|
|
3
2
|
import { BUNDLE_FILENAME } from "../../vite-plugins/esm-extension.js";
|
|
3
|
+
import { readLicenseText } from "../notices/text.js";
|
|
4
4
|
|
|
5
5
|
type FileStanza = {
|
|
6
6
|
settings: DeploySettings;
|
|
@@ -30,18 +30,6 @@ const foldedField = (name: string, lines: string[]): string[] => {
|
|
|
30
30
|
return first === undefined ? [] : [`${name}: ${first}`, ...rest.map((line) => indentLine(line))];
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
const licenseText = (licenseFile: string | null): string | null => {
|
|
34
|
-
if (licenseFile === null) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
return readFileSync(licenseFile, "utf8").trimEnd();
|
|
40
|
-
} catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
33
|
const shortName = (license: string): string =>
|
|
46
34
|
license
|
|
47
35
|
.replaceAll(SPDX_GROUPING, " ")
|
|
@@ -159,7 +147,7 @@ const applicationStanza = (settings: DeploySettings, text: string | null): strin
|
|
|
159
147
|
];
|
|
160
148
|
|
|
161
149
|
const renderCopyright = (settings: DeploySettings, sections: NoticeSection[]): string => {
|
|
162
|
-
const own =
|
|
150
|
+
const own = settings.paths.licenseFile === null ? null : readLicenseText(settings.paths.licenseFile);
|
|
163
151
|
const reproduced: Set<string> = new Set(own === null ? [] : [own]);
|
|
164
152
|
|
|
165
153
|
const stanzas = filePatterns(sections).flatMap((files) =>
|
|
@@ -14,6 +14,54 @@ import { element, renderDocument, text, type XmlNode } from "./xml.js";
|
|
|
14
14
|
|
|
15
15
|
const COMPONENT_TYPE = "desktop-application";
|
|
16
16
|
const DESKTOP_SUFFIX = ".desktop";
|
|
17
|
+
const COMPONENT_CLOSE = "</component>\n";
|
|
18
|
+
const PROVIDES_CLOSE = " </provides>\n";
|
|
19
|
+
const PROVIDES_FRAGMENT = /^<provides\s*>([\s\S]*)<\/provides>$/;
|
|
20
|
+
|
|
21
|
+
const normalizeExtraFragment = (fragment: string, index: number): string => {
|
|
22
|
+
const normalized = fragment.trim();
|
|
23
|
+
|
|
24
|
+
if (normalized.length === 0) {
|
|
25
|
+
throw new Error(`Cannot render deploy.metainfoExtra entry ${String(index + 1)}: it is empty`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return normalized;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const indentFragment = (fragment: string, depth: number): string => {
|
|
32
|
+
const indentation = " ".repeat(depth * 4);
|
|
33
|
+
|
|
34
|
+
return fragment.split(/\r?\n/).map((line) => `${indentation}${line}`).join("\n");
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const appendExtraFragments = (document: string, fragments: string[]): string => {
|
|
38
|
+
if (fragments.length === 0) {
|
|
39
|
+
return document;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let merged = document;
|
|
43
|
+
const componentFragments: string[] = [];
|
|
44
|
+
|
|
45
|
+
for (const [index, rawFragment] of fragments.entries()) {
|
|
46
|
+
const fragment = normalizeExtraFragment(rawFragment, index);
|
|
47
|
+
const provides = PROVIDES_FRAGMENT.exec(fragment)?.[1]?.trim();
|
|
48
|
+
|
|
49
|
+
if (provides === undefined) {
|
|
50
|
+
componentFragments.push(fragment);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
merged = merged.replace(PROVIDES_CLOSE, () => `${indentFragment(provides, 2)}\n${PROVIDES_CLOSE}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (componentFragments.length === 0) {
|
|
58
|
+
return merged;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const extra = componentFragments.map((fragment) => indentFragment(fragment, 1)).join("\n");
|
|
62
|
+
|
|
63
|
+
return merged.replace(COMPONENT_CLOSE, () => `${extra}\n${COMPONENT_CLOSE}`);
|
|
64
|
+
};
|
|
17
65
|
|
|
18
66
|
const launchable = (applicationId: string): XmlNode => ({
|
|
19
67
|
tag: "launchable",
|
|
@@ -21,26 +69,30 @@ const launchable = (applicationId: string): XmlNode => ({
|
|
|
21
69
|
text: `${applicationId}${DESKTOP_SUFFIX}`,
|
|
22
70
|
});
|
|
23
71
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
72
|
+
const metainfoRoot = (settings: DeploySettings): XmlNode =>
|
|
73
|
+
element("component", { type: COMPONENT_TYPE }, [
|
|
74
|
+
text("id", settings.applicationId),
|
|
75
|
+
text("name", settings.name),
|
|
76
|
+
text("summary", settings.summary),
|
|
77
|
+
text("metadata_license", settings.metadataLicense),
|
|
78
|
+
text("project_license", settings.license),
|
|
79
|
+
...developerSection(settings),
|
|
80
|
+
...descriptionSection(settings),
|
|
81
|
+
launchable(settings.applicationId),
|
|
82
|
+
...providesSection(settings),
|
|
83
|
+
...listSection("categories", "category", settings.categories),
|
|
84
|
+
...listSection("keywords", "keyword", settings.keywords),
|
|
85
|
+
...urlsSection(settings),
|
|
86
|
+
...screenshotsSection(settings),
|
|
87
|
+
...releasesSection(settings),
|
|
88
|
+
...contentRatingSection(settings),
|
|
89
|
+
...brandingSection(settings),
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
const renderMetainfo = (settings: DeploySettings): string => {
|
|
93
|
+
const document = renderDocument(metainfoRoot(settings));
|
|
94
|
+
|
|
95
|
+
return appendExtraFragments(document, settings.deploy.metainfoExtra ?? []);
|
|
96
|
+
};
|
|
45
97
|
|
|
46
98
|
export { renderMetainfo };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import XMLBuilder from "fast-xml-builder";
|
|
2
|
+
|
|
1
3
|
type XmlNode = {
|
|
2
4
|
tag: string;
|
|
3
5
|
attributes?: Record<string, string>;
|
|
@@ -5,23 +7,26 @@ type XmlNode = {
|
|
|
5
7
|
text?: string;
|
|
6
8
|
};
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
const INDENT = " ".repeat(4);
|
|
10
|
+
type OrderedNode = Record<string, unknown>;
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
-
'"': """,
|
|
13
|
-
"&": "&",
|
|
14
|
-
"<": "<",
|
|
15
|
-
">": ">",
|
|
16
|
-
};
|
|
12
|
+
const XML_ENCODING = ["UTF", "8"].join("-");
|
|
17
13
|
|
|
18
|
-
const
|
|
19
|
-
|
|
14
|
+
const builder = new XMLBuilder({
|
|
15
|
+
format: true,
|
|
16
|
+
ignoreAttributes: false,
|
|
17
|
+
indentBy: " ".repeat(4),
|
|
18
|
+
preserveOrder: true,
|
|
19
|
+
suppressEmptyNode: true,
|
|
20
|
+
});
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
.map((
|
|
24
|
-
|
|
22
|
+
const orderedNode = (node: XmlNode): OrderedNode => ({
|
|
23
|
+
[node.tag]: node.text === undefined
|
|
24
|
+
? (node.children ?? []).map((child) => orderedNode(child))
|
|
25
|
+
: [{ "#text": node.text }],
|
|
26
|
+
...(node.attributes && {
|
|
27
|
+
":@": Object.fromEntries(Object.entries(node.attributes).map(([key, value]) => [`@_${key}`, value])),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
25
30
|
|
|
26
31
|
const element = (tag: string, attributes: Record<string, string>, children: XmlNode[]): XmlNode => ({
|
|
27
32
|
tag,
|
|
@@ -31,23 +36,10 @@ const element = (tag: string, attributes: Record<string, string>, children: XmlN
|
|
|
31
36
|
|
|
32
37
|
const text = (tag: string, value: string): XmlNode => ({ tag, text: value });
|
|
33
38
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return [`${open}>${escapeXml(node.text)}</${node.tag}>`];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const children = node.children ?? [];
|
|
43
|
-
|
|
44
|
-
if (children.length === 0) {
|
|
45
|
-
return [`${open}/>`];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return [`${open}>`, ...children.flatMap((child) => renderNode(child, depth + 1)), `${padding}</${node.tag}>`];
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const renderDocument = (root: XmlNode): string => [XML_DECLARATION, ...renderNode(root, 0), ""].join("\n");
|
|
39
|
+
const renderDocument = (root: XmlNode): string =>
|
|
40
|
+
`${builder.build([
|
|
41
|
+
{ "?xml": [{ "#text": "" }], ":@": { "@_version": "1.0", "@_encoding": XML_ENCODING } },
|
|
42
|
+
orderedNode(root),
|
|
43
|
+
])}\n`;
|
|
52
44
|
|
|
53
45
|
export { element, renderDocument, text, type XmlNode };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DeployPayload, DeploySettings, StagedFile } from "../types.js";
|
|
2
2
|
import { resolveDepends } from "../depends.js";
|
|
3
|
+
import { glibcMinimumForFiles } from "../node-runtime/elf.js";
|
|
3
4
|
import { groupForCategories, sectionForCategories } from "../settings/categories.js";
|
|
4
5
|
import { nfpmContents } from "./contents.js";
|
|
5
6
|
import { debDescription, rpmDescription } from "./description.js";
|
|
@@ -125,7 +126,9 @@ const descriptionFor = (settings: DeploySettings, packager: NfpmPackager): strin
|
|
|
125
126
|
const renderNfpmConfig = (payload: DeployPayload, packager: NfpmPackager): NfpmConfig => {
|
|
126
127
|
const settings = payload.settings;
|
|
127
128
|
const isRpm = packager === "rpm";
|
|
128
|
-
const
|
|
129
|
+
const staged = stagedFilesFor(payload, packager);
|
|
130
|
+
const glibcMinimum = glibcMinimumForFiles(staged.map((file) => file.abs));
|
|
131
|
+
const depends = resolveDepends(settings, glibcMinimum);
|
|
129
132
|
|
|
130
133
|
return {
|
|
131
134
|
name: packageNameFor(settings, packager),
|
|
@@ -146,7 +149,7 @@ const renderNfpmConfig = (payload: DeployPayload, packager: NfpmPackager): NfpmC
|
|
|
146
149
|
...relationsFor(settings, packager),
|
|
147
150
|
...optional("scripts", scriptsFor(settings)),
|
|
148
151
|
[packager]: packagerSettings(settings, packager),
|
|
149
|
-
contents: nfpmContents(PREFIX,
|
|
152
|
+
contents: nfpmContents(PREFIX, staged, isRpm),
|
|
150
153
|
};
|
|
151
154
|
};
|
|
152
155
|
|
|
@@ -13,10 +13,16 @@ const FILESYSTEM_OWNED_PREFIXES = new Set([
|
|
|
13
13
|
"/usr",
|
|
14
14
|
"/usr/bin",
|
|
15
15
|
"/usr/lib",
|
|
16
|
+
"/usr/lib/systemd",
|
|
17
|
+
"/usr/lib/systemd/system",
|
|
18
|
+
"/usr/lib/systemd/user",
|
|
19
|
+
"/usr/libexec",
|
|
16
20
|
"/usr/share",
|
|
17
21
|
"/usr/share/applications",
|
|
18
22
|
"/usr/share/dbus-1",
|
|
19
23
|
"/usr/share/dbus-1/services",
|
|
24
|
+
"/usr/share/dbus-1/system-services",
|
|
25
|
+
"/usr/share/dbus-1/system.d",
|
|
20
26
|
"/usr/share/doc",
|
|
21
27
|
"/usr/share/glib-2.0",
|
|
22
28
|
"/usr/share/glib-2.0/schemas",
|
|
@@ -25,6 +31,8 @@ const FILESYSTEM_OWNED_PREFIXES = new Set([
|
|
|
25
31
|
"/usr/share/metainfo",
|
|
26
32
|
"/usr/share/mime",
|
|
27
33
|
"/usr/share/mime/packages",
|
|
34
|
+
"/usr/share/polkit-1",
|
|
35
|
+
"/usr/share/polkit-1/actions",
|
|
28
36
|
]);
|
|
29
37
|
|
|
30
38
|
const ICON_THEME_PREFIX = "/usr/share/icons/";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { closeSync, openSync, readFileSync, readSync } from "node:fs";
|
|
2
2
|
|
|
3
3
|
type ElfSection = {
|
|
4
4
|
name: string;
|
|
@@ -17,6 +17,7 @@ type DynamicEntry = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const ELF_MAGIC = "ELF";
|
|
20
|
+
const ELF_MAGIC_SIZE = 4;
|
|
20
21
|
const CLASS_64 = 2;
|
|
21
22
|
const LITTLE_ENDIAN = 1;
|
|
22
23
|
const OFFSET_CLASS = 4;
|
|
@@ -35,8 +36,11 @@ const DYNAMIC_VALUE_OFFSET = 8;
|
|
|
35
36
|
const GLIBC_VERSION = /GLIBC_(\d+)\.(\d+)/g;
|
|
36
37
|
const VERSION_RADIX = 1000;
|
|
37
38
|
|
|
39
|
+
const hasElfMagic = (buffer: Buffer): boolean =>
|
|
40
|
+
buffer.length >= OFFSET_CLASS && buffer.subarray(0, 4).toString("latin1") === ELF_MAGIC;
|
|
41
|
+
|
|
38
42
|
const assertElf64 = (buffer: Buffer, path: string): void => {
|
|
39
|
-
if (buffer.length < OFFSET_SECTION_NAME_INDEX || buffer
|
|
43
|
+
if (buffer.length < OFFSET_SECTION_NAME_INDEX || !hasElfMagic(buffer)) {
|
|
40
44
|
throw new Error(`Cannot read ${path}: it is not an ELF binary`);
|
|
41
45
|
}
|
|
42
46
|
|
|
@@ -130,8 +134,7 @@ const readGlibcMinimum = (strings: Buffer): string | null => {
|
|
|
130
134
|
const stringTable = (buffer: Buffer, dynstr: ElfSection | undefined): Buffer =>
|
|
131
135
|
dynstr === undefined ? Buffer.alloc(0) : buffer.subarray(dynstr.offset, dynstr.offset + dynstr.size);
|
|
132
136
|
|
|
133
|
-
const
|
|
134
|
-
const buffer = readFileSync(path);
|
|
137
|
+
const readElfBuffer = (buffer: Buffer, path: string): ElfInfo => {
|
|
135
138
|
assertElf64(buffer, path);
|
|
136
139
|
const sections = readSections(buffer);
|
|
137
140
|
const strings = stringTable(buffer, sectionFor(sections, ".dynstr"));
|
|
@@ -142,4 +145,39 @@ const readElfInfo = (path: string): ElfInfo => {
|
|
|
142
145
|
};
|
|
143
146
|
};
|
|
144
147
|
|
|
145
|
-
|
|
148
|
+
const readElfInfo = (path: string): ElfInfo => readElfBuffer(readFileSync(path), path);
|
|
149
|
+
|
|
150
|
+
const readFilePrefix = (descriptor: number, size: number): Buffer => {
|
|
151
|
+
const buffer = Buffer.alloc(size);
|
|
152
|
+
const bytesRead = readSync(descriptor, buffer, 0, size, 0);
|
|
153
|
+
|
|
154
|
+
return buffer.subarray(0, bytesRead);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const readOptionalElfInfo = (path: string): ElfInfo | null => {
|
|
158
|
+
const descriptor = openSync(path, "r");
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const prefix = readFilePrefix(descriptor, ELF_MAGIC_SIZE);
|
|
162
|
+
|
|
163
|
+
return hasElfMagic(prefix) ? readElfBuffer(readFileSync(descriptor), path) : null;
|
|
164
|
+
} finally {
|
|
165
|
+
closeSync(descriptor);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const glibcMinimumForFiles = (paths: Iterable<string>): string | null => {
|
|
170
|
+
const versions: number[][] = [];
|
|
171
|
+
|
|
172
|
+
for (const path of paths) {
|
|
173
|
+
const minimum = readOptionalElfInfo(path)?.glibcMinimum;
|
|
174
|
+
|
|
175
|
+
if (minimum !== undefined && minimum !== null) {
|
|
176
|
+
versions.push(minimum.split(".").map(Number));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return formatVersion(highestVersion(versions));
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export { type ElfInfo, glibcMinimumForFiles, readElfInfo };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { MINIMUM_NODE_VERSION } from "@gtkx/config/internal";
|
|
1
2
|
import { info, tryResolveExecutable } from "@gtkx/utils";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
2
4
|
import { chmodSync, copyFileSync, mkdirSync, statSync } from "node:fs";
|
|
3
5
|
import { join, resolve } from "node:path";
|
|
4
6
|
import type { DeploySettings, NodeRuntime } from "../types.js";
|
|
@@ -13,13 +15,92 @@ type StagedRuntime = {
|
|
|
13
15
|
licenseFile: string | null;
|
|
14
16
|
};
|
|
15
17
|
|
|
18
|
+
type NodeSource = "download" | "host" | "path";
|
|
19
|
+
|
|
16
20
|
const BYTES_PER_MIB = 1024 * 1024;
|
|
17
21
|
const EXECUTABLE_MODE = 0o755;
|
|
18
22
|
const NODE_FILENAME = "node";
|
|
23
|
+
const NODE_VERSION_PATTERN = /^v?(\d+)\.(\d+)\.(\d+)$/;
|
|
24
|
+
const VERSION_PROBE_TIMEOUT_MS = 10_000;
|
|
25
|
+
const VERSION_PROBE_MAX_BUFFER = 1024;
|
|
26
|
+
|
|
27
|
+
const nodeSourceFor = (settings: DeploySettings): NodeSource => settings.deploy.node?.source ?? "download";
|
|
28
|
+
|
|
29
|
+
const parseNodeVersion = (value: string, subject: string): { parts: number[]; version: string } => {
|
|
30
|
+
const match = NODE_VERSION_PATTERN.exec(value.trim());
|
|
31
|
+
|
|
32
|
+
if (match === null) {
|
|
33
|
+
throw new Error(`Cannot determine the Node.js version for ${subject}: expected a version such as 26.7.0`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const parts = match.slice(1).map(Number);
|
|
37
|
+
|
|
38
|
+
return { parts, version: parts.map(String).join(".") };
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const compareVersions = (left: number[], right: number[]): number => {
|
|
42
|
+
for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
|
|
43
|
+
const difference = (left[index] ?? 0) - (right[index] ?? 0);
|
|
44
|
+
|
|
45
|
+
if (difference !== 0) {
|
|
46
|
+
return difference;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return 0;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const supportedNodeVersion = (value: string, subject: string): string => {
|
|
54
|
+
const parsed = parseNodeVersion(value, subject);
|
|
55
|
+
const minimum = parseNodeVersion(MINIMUM_NODE_VERSION, "GTKX");
|
|
56
|
+
|
|
57
|
+
if (compareVersions(parsed.parts, minimum.parts) < 0) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Cannot bundle Node.js ${parsed.version} for ${subject}: GTKX requires ${MINIMUM_NODE_VERSION} or newer`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return parsed.version;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const probeNodeVersion = (path: string): string => {
|
|
67
|
+
try {
|
|
68
|
+
const output = execFileSync(path, ["--version"], {
|
|
69
|
+
encoding: "utf8",
|
|
70
|
+
env: { ...process.env, NODE_OPTIONS: "" },
|
|
71
|
+
maxBuffer: VERSION_PROBE_MAX_BUFFER,
|
|
72
|
+
timeout: VERSION_PROBE_TIMEOUT_MS,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return supportedNodeVersion(output, path);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (error instanceof Error && error.message.startsWith("Cannot bundle Node.js")) {
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw new Error(`Cannot determine the Node.js version from ${path}`, { cause: error });
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const assertExpectedVersion = (configured: string | undefined, actual: string, source: NodeSource): string => {
|
|
86
|
+
if (configured === undefined) {
|
|
87
|
+
return actual;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const expected = parseNodeVersion(configured, `deploy.node.source: "${source}"`).version;
|
|
91
|
+
|
|
92
|
+
if (expected !== actual) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`The Node.js runtime from deploy.node.source "${source}" is ${actual}, not the configured ${expected}`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return actual;
|
|
99
|
+
};
|
|
19
100
|
|
|
20
101
|
const sourcePathFor = (settings: DeploySettings): string => {
|
|
21
102
|
const node = settings.deploy.node ?? {};
|
|
22
|
-
const source =
|
|
103
|
+
const source = nodeSourceFor(settings);
|
|
23
104
|
|
|
24
105
|
if (source === "host") {
|
|
25
106
|
return process.execPath;
|
|
@@ -32,6 +113,21 @@ const sourcePathFor = (settings: DeploySettings): string => {
|
|
|
32
113
|
return resolve(settings.paths.root, node.path);
|
|
33
114
|
};
|
|
34
115
|
|
|
116
|
+
const resolveNodeVersion = (settings: DeploySettings): string => {
|
|
117
|
+
const node = settings.deploy.node ?? {};
|
|
118
|
+
const source = nodeSourceFor(settings);
|
|
119
|
+
|
|
120
|
+
if (source === "download") {
|
|
121
|
+
return supportedNodeVersion(node.version ?? MINIMUM_NODE_VERSION, 'deploy.node.source: "download"');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const actual = source === "host"
|
|
125
|
+
? supportedNodeVersion(process.versions.node, 'deploy.node.source: "host"')
|
|
126
|
+
: probeNodeVersion(sourcePathFor(settings));
|
|
127
|
+
|
|
128
|
+
return assertExpectedVersion(node.version, actual, source);
|
|
129
|
+
};
|
|
130
|
+
|
|
35
131
|
const didStripBinary = (path: string): boolean => {
|
|
36
132
|
if (tryResolveExecutable("strip") === undefined) {
|
|
37
133
|
return false;
|
|
@@ -60,7 +156,11 @@ const stageDownloadedNode = async (settings: DeploySettings, version: string): P
|
|
|
60
156
|
return downloaded;
|
|
61
157
|
};
|
|
62
158
|
|
|
63
|
-
const stageFromSource = async (
|
|
159
|
+
const stageFromSource = async (
|
|
160
|
+
settings: DeploySettings,
|
|
161
|
+
version: string,
|
|
162
|
+
source: NodeSource,
|
|
163
|
+
): Promise<StagedRuntime> => {
|
|
64
164
|
if (source === "download") {
|
|
65
165
|
return stageDownloadedNode(settings, version);
|
|
66
166
|
}
|
|
@@ -73,8 +173,8 @@ const stageFromSource = async (settings: DeploySettings, version: string, source
|
|
|
73
173
|
|
|
74
174
|
const resolveNodeRuntime = async (settings: DeploySettings): Promise<NodeRuntime> => {
|
|
75
175
|
const node = settings.deploy.node ?? {};
|
|
76
|
-
const source =
|
|
77
|
-
const version =
|
|
176
|
+
const source = nodeSourceFor(settings);
|
|
177
|
+
const version = resolveNodeVersion(settings);
|
|
78
178
|
const staged = await stageFromSource(settings, version, source);
|
|
79
179
|
const isStripped = node.shouldStrip === false ? false : didStripBinary(staged.path);
|
|
80
180
|
const elf = readElfInfo(staged.path);
|
|
@@ -83,4 +183,4 @@ const resolveNodeRuntime = async (settings: DeploySettings): Promise<NodeRuntime
|
|
|
83
183
|
return { ...staged, version, glibcMinimum: elf.glibcMinimum, isStripped };
|
|
84
184
|
};
|
|
85
185
|
|
|
86
|
-
export { resolveNodeRuntime, sourcePathFor };
|
|
186
|
+
export { resolveNodeRuntime, resolveNodeVersion, sourcePathFor };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { dirname, join } from "node:path";
|
|
2
|
+
import { readLicenseText } from "../notices/text.js";
|
|
3
3
|
|
|
4
4
|
const LICENSE_FILENAME = "LICENSE";
|
|
5
5
|
const NODE_MARKER = "Node.js";
|
|
@@ -10,13 +10,7 @@ const licenseCandidates = (binary: string): string[] => {
|
|
|
10
10
|
return [join(dir, LICENSE_FILENAME), join(dir, "..", LICENSE_FILENAME)];
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
const isNodeLicense = (path: string): boolean =>
|
|
14
|
-
try {
|
|
15
|
-
return readFileSync(path, "utf8").includes(NODE_MARKER);
|
|
16
|
-
} catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
};
|
|
13
|
+
const isNodeLicense = (path: string): boolean => readLicenseText(path)?.includes(NODE_MARKER) === true;
|
|
20
14
|
|
|
21
15
|
const licenseBesideNode = (binary: string): string | null =>
|
|
22
16
|
licenseCandidates(binary).find((candidate) => isNodeLicense(candidate)) ?? null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { warn } from "@gtkx/utils";
|
|
2
2
|
import type { DeploySettings, NodeRuntime, NoticeSection } from "../types.js";
|
|
3
|
-
import { sourcePathFor } from "../node-runtime/index.js";
|
|
3
|
+
import { resolveNodeVersion, sourcePathFor } from "../node-runtime/index.js";
|
|
4
4
|
import { licenseBesideNode } from "../node-runtime/license.js";
|
|
5
5
|
import { NODE_FILENAME } from "../payload/launcher.js";
|
|
6
6
|
import { nodeLicenseDestination } from "../payload/stage.js";
|
|
@@ -32,7 +32,7 @@ const MISSING_LICENSE =
|
|
|
32
32
|
const isSourceMode = (settings: DeploySettings): boolean => settings.deploy.flatpak?.mode === "source";
|
|
33
33
|
|
|
34
34
|
const versionFor = (settings: DeploySettings, node: NodeRuntime | null): string =>
|
|
35
|
-
node?.version ?? settings
|
|
35
|
+
node?.version ?? resolveNodeVersion(settings);
|
|
36
36
|
|
|
37
37
|
const licenseFileFor = (settings: DeploySettings, node: NodeRuntime | null): string | null => {
|
|
38
38
|
if (node !== null) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { sortStringsBy, warn } from "@gtkx/utils";
|
|
2
|
+
import hostedGitInfo from "hosted-git-info";
|
|
2
3
|
import { existsSync, realpathSync } from "node:fs";
|
|
3
4
|
import { join, resolve } from "node:path";
|
|
4
5
|
import type { RecordedPackage } from "../../internal/build-manifest.js";
|
|
@@ -17,10 +18,6 @@ type BundledPackage = {
|
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
const MANIFEST_FILENAME = "package.json";
|
|
20
|
-
const GIT_PREFIX = /^git\+/;
|
|
21
|
-
const GIT_SUFFIX = /\.git$/;
|
|
22
|
-
const GIT_SCHEME = /^git:\/\//;
|
|
23
|
-
const GITHUB_SLUG = /^(?:github:)?(?<slug>[\w.-]+\/[\w.-]+)$/;
|
|
24
21
|
|
|
25
22
|
const realPath = (path: string): string => {
|
|
26
23
|
try {
|
|
@@ -47,14 +44,9 @@ const sourceUrl = (manifest: PackageManifest): string | null => {
|
|
|
47
44
|
return null;
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
const url = configured.replace(
|
|
51
|
-
const slug = GITHUB_SLUG.exec(url)?.groups?.slug;
|
|
47
|
+
const url = configured.replace(/^git\+/, "").replace(/\.git$/, "").replace(/^git:\/\//, "https://");
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
return `https://github.com/${slug}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return url.startsWith("http") ? url : null;
|
|
49
|
+
return hostedGitInfo.fromUrl(url)?.browse() ?? (url.startsWith("http") ? url : null);
|
|
58
50
|
};
|
|
59
51
|
|
|
60
52
|
const missingPackage = (entry: RecordedPackage): BundledPackage => ({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { isPathInside } from "@gtkx/utils";
|
|
1
2
|
import { chmodSync, copyFileSync, mkdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname,
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
3
4
|
import type { StagedFile } from "../types.js";
|
|
4
5
|
import { listFilesRecursive } from "../../internal/list-files.js";
|
|
5
6
|
|
|
@@ -16,9 +17,7 @@ const modeFor = (rel: string): number => {
|
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
const assertInsideRoot = (root: string, rel: string, abs: string): void => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (escape.length === 0 || escape.startsWith("..") || isAbsolute(escape)) {
|
|
20
|
+
if (!isPathInside(root, abs)) {
|
|
22
21
|
throw new Error(`Cannot stage "${rel}": it resolves outside the staging directory`);
|
|
23
22
|
}
|
|
24
23
|
};
|
|
@@ -2,6 +2,8 @@ import type { DeploySettings } from "../types.js";
|
|
|
2
2
|
import { BUNDLE_FILENAME } from "../../vite-plugins/esm-extension.js";
|
|
3
3
|
|
|
4
4
|
const NODE_FILENAME = "node";
|
|
5
|
+
const SHELL_SINGLE_QUOTE = "'";
|
|
6
|
+
const SHELL_SINGLE_QUOTE_ESCAPE = "'\"'\"'";
|
|
5
7
|
|
|
6
8
|
const compileCacheLines = (binaryName: string): string[] => [
|
|
7
9
|
"cache_home=${XDG_CACHE_HOME:-${HOME:-/tmp}/.cache}",
|
|
@@ -9,6 +11,22 @@ const compileCacheLines = (binaryName: string): string[] => [
|
|
|
9
11
|
"export NODE_COMPILE_CACHE",
|
|
10
12
|
];
|
|
11
13
|
|
|
14
|
+
const shellQuote = (value: string): string =>
|
|
15
|
+
SHELL_SINGLE_QUOTE + value.split(SHELL_SINGLE_QUOTE).join(SHELL_SINGLE_QUOTE_ESCAPE) + SHELL_SINGLE_QUOTE;
|
|
16
|
+
|
|
17
|
+
const launcherEnvLines = (settings: DeploySettings): string[] =>
|
|
18
|
+
Object.entries(settings.deploy.launcherEnv ?? {})
|
|
19
|
+
.toSorted(([left], [right]) => left.localeCompare(right))
|
|
20
|
+
.map(([name, value]) => `export ${name}=${shellQuote(value)}`);
|
|
21
|
+
|
|
22
|
+
const launcherCommand = (settings: DeploySettings, libDir: string): string =>
|
|
23
|
+
[
|
|
24
|
+
`"${libDir}/${NODE_FILENAME}"`,
|
|
25
|
+
...(settings.deploy.nodeFlags ?? []).map((flag) => shellQuote(flag)),
|
|
26
|
+
`"${libDir}/${BUNDLE_FILENAME}"`,
|
|
27
|
+
'"$@"',
|
|
28
|
+
].join(" ");
|
|
29
|
+
|
|
12
30
|
const renderLauncher = (settings: DeploySettings): string => {
|
|
13
31
|
const libDir = `$prefix/lib/${settings.binaryName}`;
|
|
14
32
|
const shouldUseCompileCache = settings.deploy.node?.shouldUseCompileCache !== false;
|
|
@@ -21,7 +39,8 @@ const renderLauncher = (settings: DeploySettings): string => {
|
|
|
21
39
|
'GTKX_LOCALE_DIR="$prefix/share/locale"',
|
|
22
40
|
"export GTKX_LOCALE_DIR",
|
|
23
41
|
...(shouldUseCompileCache ? compileCacheLines(settings.binaryName) : []),
|
|
24
|
-
|
|
42
|
+
...launcherEnvLines(settings),
|
|
43
|
+
`exec ${launcherCommand(settings, libDir)}`,
|
|
25
44
|
"",
|
|
26
45
|
].join("\n");
|
|
27
46
|
};
|