@gtkx/cli 2.0.0-beta.7 → 2.0.0-beta.9

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.
Files changed (155) hide show
  1. package/dist/commands/deploy.d.ts +4 -0
  2. package/dist/commands/deploy.d.ts.map +1 -1
  3. package/dist/commands/deploy.js +6 -0
  4. package/dist/commands/deploy.js.map +1 -1
  5. package/dist/deploy/depends.d.ts.map +1 -1
  6. package/dist/deploy/depends.js +24 -2
  7. package/dist/deploy/depends.js.map +1 -1
  8. package/dist/deploy/download.d.ts +7 -3
  9. package/dist/deploy/download.d.ts.map +1 -1
  10. package/dist/deploy/download.js +19 -15
  11. package/dist/deploy/download.js.map +1 -1
  12. package/dist/deploy/native-addon.d.ts +5 -0
  13. package/dist/deploy/native-addon.d.ts.map +1 -0
  14. package/dist/deploy/native-addon.js +134 -0
  15. package/dist/deploy/native-addon.js.map +1 -0
  16. package/dist/deploy/node-runtime/download.js +2 -2
  17. package/dist/deploy/node-runtime/download.js.map +1 -1
  18. package/dist/deploy/node-runtime/elf.d.ts +3 -1
  19. package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
  20. package/dist/deploy/node-runtime/elf.js +3 -1
  21. package/dist/deploy/node-runtime/elf.js.map +1 -1
  22. package/dist/deploy/node-runtime/guard.d.ts.map +1 -1
  23. package/dist/deploy/node-runtime/guard.js +7 -14
  24. package/dist/deploy/node-runtime/guard.js.map +1 -1
  25. package/dist/deploy/node-runtime/index.d.ts +2 -1
  26. package/dist/deploy/node-runtime/index.d.ts.map +1 -1
  27. package/dist/deploy/node-runtime/index.js +29 -6
  28. package/dist/deploy/node-runtime/index.js.map +1 -1
  29. package/dist/deploy/node-runtime/sonames.d.ts +5 -0
  30. package/dist/deploy/node-runtime/sonames.d.ts.map +1 -0
  31. package/dist/deploy/node-runtime/sonames.js +13 -0
  32. package/dist/deploy/node-runtime/sonames.js.map +1 -0
  33. package/dist/deploy/payload/stage.d.ts +2 -1
  34. package/dist/deploy/payload/stage.d.ts.map +1 -1
  35. package/dist/deploy/payload/stage.js +22 -2
  36. package/dist/deploy/payload/stage.js.map +1 -1
  37. package/dist/deploy/run-deploy.d.ts +1 -0
  38. package/dist/deploy/run-deploy.d.ts.map +1 -1
  39. package/dist/deploy/run-deploy.js +139 -80
  40. package/dist/deploy/run-deploy.js.map +1 -1
  41. package/dist/deploy/settings/arch.d.ts +9 -3
  42. package/dist/deploy/settings/arch.d.ts.map +1 -1
  43. package/dist/deploy/settings/arch.js +27 -6
  44. package/dist/deploy/settings/arch.js.map +1 -1
  45. package/dist/deploy/settings/index.d.ts +2 -1
  46. package/dist/deploy/settings/index.d.ts.map +1 -1
  47. package/dist/deploy/settings/index.js +2 -1
  48. package/dist/deploy/settings/index.js.map +1 -1
  49. package/dist/deploy/settings/paths.d.ts +2 -1
  50. package/dist/deploy/settings/paths.d.ts.map +1 -1
  51. package/dist/deploy/settings/paths.js +6 -5
  52. package/dist/deploy/settings/paths.js.map +1 -1
  53. package/dist/deploy/targets/appimage.d.ts.map +1 -1
  54. package/dist/deploy/targets/appimage.js +1 -0
  55. package/dist/deploy/targets/appimage.js.map +1 -1
  56. package/dist/deploy/targets/flatpak-pnpm.js +4 -4
  57. package/dist/deploy/targets/flatpak-pnpm.js.map +1 -1
  58. package/dist/deploy/targets/flatpak.d.ts.map +1 -1
  59. package/dist/deploy/targets/flatpak.js +1 -0
  60. package/dist/deploy/targets/flatpak.js.map +1 -1
  61. package/dist/deploy/targets/nfpm-target.d.ts.map +1 -1
  62. package/dist/deploy/targets/nfpm-target.js +1 -0
  63. package/dist/deploy/targets/nfpm-target.js.map +1 -1
  64. package/dist/deploy/types.d.ts +4 -2
  65. package/dist/deploy/types.d.ts.map +1 -1
  66. package/dist/deploy/types.js.map +1 -1
  67. package/dist/deploy/vendored/appimagetool.js +2 -2
  68. package/dist/deploy/vendored/appimagetool.js.map +1 -1
  69. package/dist/deploy/vendored/nfpm.js +1 -1
  70. package/dist/deploy/vendored/nfpm.js.map +1 -1
  71. package/dist/dev/font-dir.d.ts +1 -1
  72. package/dist/dev/font-dir.d.ts.map +1 -1
  73. package/dist/dev/font-dir.js +0 -3
  74. package/dist/dev/font-dir.js.map +1 -1
  75. package/dist/dev/runner.d.ts.map +1 -1
  76. package/dist/dev/runner.js +19 -6
  77. package/dist/dev/runner.js.map +1 -1
  78. package/dist/internal/font-staging.d.ts +5 -2
  79. package/dist/internal/font-staging.d.ts.map +1 -1
  80. package/dist/internal/font-staging.js +76 -27
  81. package/dist/internal/font-staging.js.map +1 -1
  82. package/dist/internal/icon-staging.d.ts +3 -0
  83. package/dist/internal/icon-staging.d.ts.map +1 -0
  84. package/dist/internal/icon-staging.js +40 -0
  85. package/dist/internal/icon-staging.js.map +1 -0
  86. package/dist/internal/source-imports.js +1 -1
  87. package/dist/internal/source-imports.js.map +1 -1
  88. package/dist/vite-plugins/font-worker-env.d.ts.map +1 -1
  89. package/dist/vite-plugins/font-worker-env.js +2 -5
  90. package/dist/vite-plugins/font-worker-env.js.map +1 -1
  91. package/dist/vite-plugins/font.d.ts.map +1 -1
  92. package/dist/vite-plugins/font.js +16 -4
  93. package/dist/vite-plugins/font.js.map +1 -1
  94. package/dist/vite-plugins/icon-worker-env.d.ts +4 -0
  95. package/dist/vite-plugins/icon-worker-env.d.ts.map +1 -0
  96. package/dist/vite-plugins/icon-worker-env.js +23 -0
  97. package/dist/vite-plugins/icon-worker-env.js.map +1 -0
  98. package/dist/vite-plugins/icons.js +2 -2
  99. package/dist/vite-plugins/icons.js.map +1 -1
  100. package/dist/vite-plugins/react-compiler.js +2 -2
  101. package/dist/vite-plugins/react-compiler.js.map +1 -1
  102. package/dist/vite-plugins/resources.js +2 -2
  103. package/dist/vite-plugins/resources.js.map +1 -1
  104. package/dist/vite-plugins/settings-worker-env.js +2 -2
  105. package/dist/vite-plugins/settings-worker-env.js.map +1 -1
  106. package/dist/vite-plugins/store-links.d.ts.map +1 -1
  107. package/dist/vite-plugins/store-links.js +2 -1
  108. package/dist/vite-plugins/store-links.js.map +1 -1
  109. package/dist/vite-plugins/undeclared-library.js +2 -2
  110. package/dist/vite-plugins/undeclared-library.js.map +1 -1
  111. package/dist/vite-plugins/worker.d.ts.map +1 -1
  112. package/dist/vite-plugins/worker.js +21 -13
  113. package/dist/vite-plugins/worker.js.map +1 -1
  114. package/dist/vitest-plugin.d.ts +2 -2
  115. package/dist/vitest-plugin.d.ts.map +1 -1
  116. package/dist/vitest-plugin.js +4 -2
  117. package/dist/vitest-plugin.js.map +1 -1
  118. package/package.json +13 -13
  119. package/src/commands/deploy.ts +6 -0
  120. package/src/deploy/depends.ts +30 -3
  121. package/src/deploy/download.ts +33 -17
  122. package/src/deploy/native-addon.ts +183 -0
  123. package/src/deploy/node-runtime/download.ts +2 -2
  124. package/src/deploy/node-runtime/elf.ts +4 -1
  125. package/src/deploy/node-runtime/guard.ts +10 -14
  126. package/src/deploy/node-runtime/index.ts +42 -7
  127. package/src/deploy/node-runtime/sonames.ts +17 -0
  128. package/src/deploy/payload/stage.ts +34 -2
  129. package/src/deploy/run-deploy.ts +209 -94
  130. package/src/deploy/settings/arch.ts +40 -8
  131. package/src/deploy/settings/index.ts +4 -1
  132. package/src/deploy/settings/paths.ts +8 -6
  133. package/src/deploy/targets/appimage.ts +1 -0
  134. package/src/deploy/targets/flatpak-pnpm.ts +4 -4
  135. package/src/deploy/targets/flatpak.ts +1 -0
  136. package/src/deploy/targets/nfpm-target.ts +1 -0
  137. package/src/deploy/types.ts +4 -1
  138. package/src/deploy/vendored/appimagetool.ts +2 -2
  139. package/src/deploy/vendored/nfpm.ts +1 -1
  140. package/src/dev/font-dir.ts +1 -6
  141. package/src/dev/runner.ts +24 -6
  142. package/src/internal/font-staging.ts +99 -27
  143. package/src/internal/icon-staging.ts +58 -0
  144. package/src/internal/source-imports.ts +1 -1
  145. package/src/vite-plugins/font-worker-env.ts +2 -6
  146. package/src/vite-plugins/font.ts +21 -3
  147. package/src/vite-plugins/icon-worker-env.ts +36 -0
  148. package/src/vite-plugins/icons.ts +2 -2
  149. package/src/vite-plugins/react-compiler.ts +2 -2
  150. package/src/vite-plugins/resources.ts +2 -2
  151. package/src/vite-plugins/settings-worker-env.ts +2 -2
  152. package/src/vite-plugins/store-links.ts +2 -1
  153. package/src/vite-plugins/undeclared-library.ts +2 -2
  154. package/src/vite-plugins/worker.ts +31 -15
  155. package/src/vitest-plugin.ts +4 -2
@@ -44,8 +44,8 @@ const downloadNode = async (version: string, arch: string, destDir: string): Pro
44
44
  url: `${DIST_BASE_URL}/v${version}/${assetName}`,
45
45
  dest: join(dir, assetName),
46
46
  label: `Node.js ${version} for linux-${arch}`,
47
- sha256: await cachedDigest(request),
48
- freshSha256: () => publishedDigest(request),
47
+ digest: await cachedDigest(request),
48
+ freshDigest: () => publishedDigest(request),
49
49
  });
50
50
 
51
51
  mkdirSync(destDir, { recursive: true });
@@ -7,6 +7,7 @@ type ElfSection = {
7
7
  };
8
8
 
9
9
  type ElfInfo = {
10
+ machine: number;
10
11
  needed: string[];
11
12
  glibcMinimum: string | null;
12
13
  };
@@ -22,6 +23,7 @@ const CLASS_64 = 2;
22
23
  const LITTLE_ENDIAN = 1;
23
24
  const OFFSET_CLASS = 4;
24
25
  const OFFSET_DATA = 5;
26
+ const OFFSET_MACHINE = 0x12;
25
27
  const OFFSET_SECTION_HEADERS = 0x28;
26
28
  const OFFSET_SECTION_ENTRY_SIZE = 0x3A;
27
29
  const OFFSET_SECTION_COUNT = 0x3C;
@@ -140,6 +142,7 @@ const readElfBuffer = (buffer: Buffer, path: string): ElfInfo => {
140
142
  const strings = stringTable(buffer, sectionFor(sections, ".dynstr"));
141
143
 
142
144
  return {
145
+ machine: buffer.readUInt16LE(OFFSET_MACHINE),
143
146
  needed: readNeeded(buffer, sectionFor(sections, ".dynamic"), strings),
144
147
  glibcMinimum: readGlibcMinimum(strings),
145
148
  };
@@ -180,4 +183,4 @@ const glibcMinimumForFiles = (paths: Iterable<string>): string | null => {
180
183
  return formatVersion(highestVersion(versions));
181
184
  };
182
185
 
183
- export { type ElfInfo, glibcMinimumForFiles, readElfInfo };
186
+ export { type ElfInfo, glibcMinimumForFiles, readElfInfo, readOptionalElfInfo };
@@ -1,19 +1,16 @@
1
1
  import type { ElfInfo } from "./elf.js";
2
+ import { RUNTIME_SONAMES } from "./sonames.js";
2
3
 
3
- const PORTABLE_LIBRARIES = new Set([
4
- "ld-linux-aarch64.so.1",
5
- "ld-linux-x86-64.so.2",
6
- "libc.so.6",
7
- "libdl.so.2",
8
- "libgcc_s.so.1",
9
- "libm.so.6",
10
- "libpthread.so.0",
11
- "librt.so.1",
12
- "libstdc++.so.6",
13
- ]);
4
+ const DOWNLOAD_REMEDY =
5
+ "The packages GTKX generates declare the libraries an official release links against, and this release " +
6
+ "links against more. Report it to GTKX, and pin `deploy.node.version` to a release it already packages.";
7
+
8
+ const SOURCE_REMEDY = 'Use `deploy.node.source: "download"` to fetch an official self-contained build instead.';
9
+
10
+ const remedyFor = (source: string): string => (source === "download" ? DOWNLOAD_REMEDY : SOURCE_REMEDY);
14
11
 
15
12
  const assertPortableNode = (info: ElfInfo, source: string): void => {
16
- const foreign = info.needed.filter((library) => !PORTABLE_LIBRARIES.has(library));
13
+ const foreign = info.needed.filter((library) => !RUNTIME_SONAMES.has(library));
17
14
 
18
15
  if (foreign.length === 0) {
19
16
  return;
@@ -21,8 +18,7 @@ const assertPortableNode = (info: ElfInfo, source: string): void => {
21
18
 
22
19
  throw new Error(
23
20
  `Cannot bundle this Node.js binary: \`deploy.node.source: "${source}"\` picked one linked against ` +
24
- `${foreign.join(", ")}, which the target machine will not have. ` +
25
- 'Use `deploy.node.source: "download"` to fetch an official self-contained build instead.',
21
+ `${foreign.join(", ")}, which the packages GTKX generates do not require. ${remedyFor(source)}`,
26
22
  );
27
23
  };
28
24
 
@@ -1,12 +1,13 @@
1
1
  import { MINIMUM_NODE_VERSION } from "@gtkx/config/internal";
2
- import { info, tryResolveExecutable } from "@gtkx/utils";
2
+ import { info, tryResolveExecutable, warn } from "@gtkx/utils";
3
3
  import { execFileSync } from "node:child_process";
4
- import { chmodSync, copyFileSync, mkdirSync, statSync } from "node:fs";
4
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, statSync } from "node:fs";
5
5
  import { join, resolve } from "node:path";
6
- import type { DeploySettings, NodeRuntime } from "../types.js";
6
+ import type { DeployConfig, DeploySettings, NodeRuntime } from "../types.js";
7
7
  import { runCliTool } from "../../internal/run-cli-tool.js";
8
+ import { elfMachineFor, hostArchName } from "../settings/arch.js";
8
9
  import { downloadNode } from "./download.js";
9
- import { readElfInfo } from "./elf.js";
10
+ import { type ElfInfo, readElfInfo, readOptionalElfInfo } from "./elf.js";
10
11
  import { assertPortableNode } from "./guard.js";
11
12
  import { licenseBesideNode } from "./license.js";
12
13
 
@@ -113,6 +114,21 @@ const sourcePathFor = (settings: DeploySettings): string => {
113
114
  return resolve(settings.paths.root, node.path);
114
115
  };
115
116
 
117
+ const assertPortableRuntimeSource = (settings: DeploySettings): void => {
118
+ const source = nodeSourceFor(settings);
119
+
120
+ if (source === "download") {
121
+ return;
122
+ }
123
+
124
+ const sourcePath = sourcePathFor(settings);
125
+ const elf = existsSync(sourcePath) ? readOptionalElfInfo(sourcePath) : null;
126
+
127
+ if (elf !== null) {
128
+ assertPortableNode(elf, source);
129
+ }
130
+ };
131
+
116
132
  const resolveNodeVersion = (settings: DeploySettings): string => {
117
133
  const node = settings.deploy.node ?? {};
118
134
  const source = nodeSourceFor(settings);
@@ -166,22 +182,41 @@ const stageFromSource = async (
166
182
  }
167
183
 
168
184
  const sourcePath = sourcePathFor(settings);
169
- assertPortableNode(readElfInfo(sourcePath), source);
170
185
 
171
186
  return { path: stageNode(settings, sourcePath), licenseFile: licenseBesideNode(sourcePath) };
172
187
  };
173
188
 
189
+ type DeployNodeConfig = NonNullable<DeployConfig["node"]>;
190
+
191
+ const shouldStripRuntime = (settings: DeploySettings, node: DeployNodeConfig, elf: ElfInfo): boolean => {
192
+ if (node.shouldStrip === false) {
193
+ return false;
194
+ }
195
+
196
+ if (elf.machine === elfMachineFor(hostArchName())) {
197
+ return true;
198
+ }
199
+
200
+ warn(
201
+ `Skipping \`strip\` on the bundled Node.js: it was built for ${settings.arch.node} and \`strip\` reads ` +
202
+ `only ${hostArchName()}. The ${settings.arch.node} packages carry an unstripped runtime.`,
203
+ );
204
+
205
+ return false;
206
+ };
207
+
174
208
  const resolveNodeRuntime = async (settings: DeploySettings): Promise<NodeRuntime> => {
175
209
  const node = settings.deploy.node ?? {};
176
210
  const source = nodeSourceFor(settings);
177
211
  const version = resolveNodeVersion(settings);
178
212
  const staged = await stageFromSource(settings, version, source);
179
- const isStripped = node.shouldStrip === false ? false : didStripBinary(staged.path);
180
213
  const elf = readElfInfo(staged.path);
214
+ assertPortableNode(elf, source);
215
+ const isStripped = shouldStripRuntime(settings, node, elf) && didStripBinary(staged.path);
181
216
  const glibcMinimum = elf.glibcMinimum ?? "unknown";
182
217
  info(`Bundled Node.js v${version} (${megabytes(staged.path)} MiB, runtime glibc >= ${glibcMinimum})`);
183
218
 
184
219
  return { ...staged, version, glibcMinimum: elf.glibcMinimum, isStripped };
185
220
  };
186
221
 
187
- export { resolveNodeRuntime, resolveNodeVersion, sourcePathFor };
222
+ export { assertPortableRuntimeSource, resolveNodeRuntime, resolveNodeVersion, sourcePathFor };
@@ -0,0 +1,17 @@
1
+ const GLIBC_SONAMES = [
2
+ "ld-linux-aarch64.so.1",
3
+ "ld-linux-x86-64.so.2",
4
+ "libc.so.6",
5
+ "libdl.so.2",
6
+ "libm.so.6",
7
+ "libpthread.so.0",
8
+ "librt.so.1",
9
+ ] as const;
10
+
11
+ const PACKAGED_SONAMES = ["libatomic.so.1", "libgcc_s.so.1", "libstdc++.so.6"] as const;
12
+
13
+ type PackagedSoname = (typeof PACKAGED_SONAMES)[number];
14
+
15
+ const RUNTIME_SONAMES: Set<string> = new Set([...GLIBC_SONAMES, ...PACKAGED_SONAMES]);
16
+
17
+ export { PACKAGED_SONAMES, type PackagedSoname, RUNTIME_SONAMES };
@@ -8,7 +8,10 @@ import { listFilesRecursive } from "../../internal/list-files.js";
8
8
  import { BUNDLE_FILENAME } from "../../vite-plugins/esm-extension.js";
9
9
  import { renderCopyright } from "../freedesktop/copyright.js";
10
10
  import { renderDbusService } from "../freedesktop/dbus-service.js";
11
+ import { BINDING_FILENAME } from "../native-addon.js";
12
+ import { readOptionalElfInfo } from "../node-runtime/elf.js";
11
13
  import { renderNotices } from "../notices/render.js";
14
+ import { elfMachineFor } from "../settings/arch.js";
12
15
  import { copyInto, EXECUTABLE_MODE, executableModeFor, writeInto } from "./copy-tree.js";
13
16
  import { stageIcons } from "./icons.js";
14
17
  import { NODE_FILENAME, renderLauncher } from "./launcher.js";
@@ -17,6 +20,7 @@ import { stageSchemas } from "./schemas.js";
17
20
  type StageRequest = {
18
21
  settings: DeploySettings;
19
22
  node: NodeRuntime | null;
23
+ addon: string | null;
20
24
  metadata: StagedMetadata;
21
25
  };
22
26
 
@@ -67,6 +71,29 @@ const stageRuntimeFiles = (settings: DeploySettings, root: string): StagedFile[]
67
71
  .map((file) => copyInto(root, join(libDirFor(settings), file.rel), file.absPath));
68
72
  };
69
73
 
74
+ const stageAddon = (settings: DeploySettings, root: string, addon: string | null): StagedFile[] =>
75
+ addon === null ? [] : [copyInto(root, join(libDirFor(settings), BINDING_FILENAME), addon)];
76
+
77
+ const architectureMismatch = (settings: DeploySettings, file: StagedFile): Error =>
78
+ new Error(
79
+ `Cannot deploy ${file.rel} for ${settings.arch.node}: it was built for another architecture. ` +
80
+ "Run `gtkx build` again, or drop --skip-build.",
81
+ );
82
+
83
+ const assertStagedArchitecture = (settings: DeploySettings, staged: StagedFile[]): void => {
84
+ const expected = elfMachineFor(settings.arch.node);
85
+ const lib = libDirFor(settings);
86
+ const checked = new Set([join(lib, BINDING_FILENAME), join(lib, NODE_FILENAME)]);
87
+
88
+ const binaries = staged.filter((entry) => checked.has(entry.rel));
89
+
90
+ for (const file of binaries) {
91
+ if (readOptionalElfInfo(file.abs)?.machine !== expected) {
92
+ throw architectureMismatch(settings, file);
93
+ }
94
+ }
95
+ };
96
+
70
97
  const stageCatalogs = (settings: DeploySettings, root: string): StagedFile[] =>
71
98
  listFilesRecursive(join(settings.paths.dist, LOCALE_DIRNAME))
72
99
  .map((file) => copyInto(root, join(SHARE_LOCALE, file.rel), file.absPath));
@@ -138,20 +165,25 @@ const byRelativePath = (files: StagedFile[]): StagedFile[] => {
138
165
  return sortStringsBy(latest.values(), (file) => file.rel);
139
166
  };
140
167
 
141
- const stagePayload = ({ settings, node, metadata }: StageRequest): StagedFile[] => {
168
+ const stagePayload = ({ settings, node, addon, metadata }: StageRequest): StagedFile[] => {
142
169
  const root = settings.paths.stage;
143
170
  rmSync(root, { recursive: true, force: true, maxRetries: 5 });
144
171
 
145
- return byRelativePath([
172
+ const staged = byRelativePath([
146
173
  writeInto(root, join("bin", settings.binaryName), renderLauncher(settings), EXECUTABLE_MODE),
147
174
  ...stageNodeBinary(settings, root, node),
148
175
  ...stageRuntimeFiles(settings, root),
176
+ ...stageAddon(settings, root, addon),
149
177
  ...stageCatalogs(settings, root),
150
178
  ...stageExtraFiles(settings, root, metadata),
151
179
  ...stageMetadata(settings, root, metadata),
152
180
  ...stageIcons(settings, root),
153
181
  ...stageSchemas(settings, root),
154
182
  ]);
183
+
184
+ assertStagedArchitecture(settings, staged);
185
+
186
+ return staged;
155
187
  };
156
188
 
157
189
  const withoutDbusActivation = (desktopEntry: string): string =>