@dbx-tools/projen 0.9.21 → 0.9.29

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 (111) hide show
  1. package/README.md +77 -207
  2. package/index.ts +10 -14
  3. package/package.json +4 -4
  4. package/src/barrels.ts +1 -74
  5. package/src/module-exports.ts +175 -1
  6. package/src/openapi.ts +5 -72
  7. package/src/packages.ts +45 -0
  8. package/src/project-js.ts +3 -6
  9. package/src/project-predicate.ts +1 -2
  10. package/src/project-py.ts +82 -103
  11. package/src/project.ts +2 -2
  12. package/src/python-node-bindings.ts +138 -0
  13. package/src/python-node-bundle.ts +92 -0
  14. package/src/release-catalog.ts +3 -5
  15. package/src/{release-dispatch.ts → release-context.ts} +0 -11
  16. package/src/release.ts +70 -152
  17. package/tasks/bump.ts +12 -21
  18. package/tasks/databricks-cli-assets.ts +129 -0
  19. package/tasks/local-publish.ts +23 -107
  20. package/tasks/publish-npm.ts +10 -1
  21. package/tasks/publish-python.ts +26 -11
  22. package/tasks/publish.ts +12 -48
  23. package/tasks/python-node-bindings-watch.ts +47 -0
  24. package/tasks/python-node-bindings.ts +1017 -0
  25. package/tasks/python-release.ts +74 -0
  26. package/tasks/release.ts +99 -0
  27. package/tasks/sync.ts +13 -18
  28. package/tasks/version-check.ts +1 -28
  29. package/._LICENSE +0 -0
  30. package/._README.md +0 -0
  31. package/._index.ts +0 -0
  32. package/._package.json +0 -0
  33. package/src/.__lazy-require.ts +0 -0
  34. package/src/.__release-platform.ts +0 -0
  35. package/src/.__rust-project.ts +0 -0
  36. package/src/.__rust-release-workflow.ts +0 -0
  37. package/src/.__task-command.ts +0 -0
  38. package/src/._barrels.ts +0 -0
  39. package/src/._bun-app.ts +0 -0
  40. package/src/._bun-workflow.ts +0 -0
  41. package/src/._clean.ts +0 -0
  42. package/src/._codegen.ts +0 -0
  43. package/src/._dbx-tools-config.ts +0 -0
  44. package/src/._engine-root.ts +0 -0
  45. package/src/._generated.ts +0 -0
  46. package/src/._mixin.ts +0 -0
  47. package/src/._module-exports.ts +0 -0
  48. package/src/._openapi.ts +0 -0
  49. package/src/._packages.ts +0 -0
  50. package/src/._pnpm-workspace.ts +0 -0
  51. package/src/._project-js.ts +0 -0
  52. package/src/._project-predicate.ts +0 -0
  53. package/src/._project-py.ts +0 -0
  54. package/src/._project-rs.ts +0 -0
  55. package/src/._project.ts +0 -0
  56. package/src/._projen-version.ts +0 -0
  57. package/src/._publish.ts +0 -0
  58. package/src/._release-catalog.ts +0 -0
  59. package/src/._release-dispatch.ts +0 -0
  60. package/src/._release-github.ts +0 -0
  61. package/src/._release.ts +0 -0
  62. package/src/._scaffold.ts +0 -0
  63. package/src/._tags.ts +0 -0
  64. package/src/._tsconfig.ts +0 -0
  65. package/src/._uniffi.ts +0 -0
  66. package/src/._vscode.ts +0 -0
  67. package/src/._watch.ts +0 -0
  68. package/src/._workspace-lock.ts +0 -0
  69. package/src/._workspace-version.ts +0 -0
  70. package/src/_release-platform.ts +0 -78
  71. package/src/_rust-project.ts +0 -429
  72. package/src/_rust-release-workflow.ts +0 -311
  73. package/src/project-rs.ts +0 -1054
  74. package/src/release-github.ts +0 -109
  75. package/src/uniffi.ts +0 -65
  76. package/tasks/._barrels.ts +0 -0
  77. package/tasks/._bump.ts +0 -0
  78. package/tasks/._clean.ts +0 -0
  79. package/tasks/._compile-workspace.ts +0 -0
  80. package/tasks/._local-publish.ts +0 -0
  81. package/tasks/._openapi.ts +0 -0
  82. package/tasks/._projenrc.ts +0 -0
  83. package/tasks/._publish-npm.ts +0 -0
  84. package/tasks/._publish-python.ts +0 -0
  85. package/tasks/._publish-uniffi-local.ts +0 -0
  86. package/tasks/._publish.ts +0 -0
  87. package/tasks/._python-registry.ts +0 -0
  88. package/tasks/._release-assets.ts +0 -0
  89. package/tasks/._release-candidate.ts +0 -0
  90. package/tasks/._release-manifest.ts +0 -0
  91. package/tasks/._release-pr.ts +0 -0
  92. package/tasks/._release-summary.ts +0 -0
  93. package/tasks/._release-version.ts +0 -0
  94. package/tasks/._rust.ts +0 -0
  95. package/tasks/._sync.ts +0 -0
  96. package/tasks/._uniffi-python.d.ts +0 -0
  97. package/tasks/._uniffi-python.js +0 -0
  98. package/tasks/._uniffi-release.mjs +0 -0
  99. package/tasks/._uniffi.ts +0 -0
  100. package/tasks/._version-check.ts +0 -0
  101. package/tasks/publish-uniffi-local.ts +0 -359
  102. package/tasks/release-assets.ts +0 -467
  103. package/tasks/release-candidate.ts +0 -416
  104. package/tasks/release-manifest.ts +0 -273
  105. package/tasks/release-pr.ts +0 -589
  106. package/tasks/release-summary.ts +0 -379
  107. package/tasks/rust.ts +0 -173
  108. package/tasks/uniffi-python.d.ts +0 -60
  109. package/tasks/uniffi-python.js +0 -178
  110. package/tasks/uniffi-release.mjs +0 -579
  111. package/tasks/uniffi.ts +0 -262
@@ -1,579 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- chmodSync,
4
- cpSync,
5
- existsSync,
6
- mkdirSync,
7
- mkdtempSync,
8
- readFileSync,
9
- readdirSync,
10
- rmSync,
11
- statSync,
12
- writeFileSync,
13
- } from "node:fs";
14
- import { basename, dirname, join, resolve } from "node:path";
15
- import { tmpdir } from "node:os";
16
- import { fileURLToPath } from "node:url";
17
- import { createRequire } from "node:module";
18
- import { parseArgs } from "node:util";
19
- import { spawnSync } from "node:child_process";
20
- import {
21
- installPythonBindings,
22
- preparePythonProjectForPublication,
23
- pythonBindingGeneratorArgs,
24
- pythonBindingGeneratorName,
25
- } from "./uniffi-python.js";
26
-
27
- const require = createRequire(import.meta.url);
28
- const bundledToml = fileURLToPath(new URL("./smol-toml.cjs", import.meta.url));
29
- const toml = require(existsSync(bundledToml) ? bundledToml : "smol-toml");
30
-
31
- const parsed = parseArgs({
32
- allowPositionals: true,
33
- options: {
34
- root: { type: "string" },
35
- crate: { type: "string" },
36
- node: { type: "string" },
37
- python: { type: "string" },
38
- "node-package": { type: "string" },
39
- "native-package": { type: "string" },
40
- "python-package": { type: "string" },
41
- "python-module": { type: "string" },
42
- "python-bindings": { type: "string" },
43
- "cargo-target": { type: "string" },
44
- "generator-target": { type: "string" },
45
- "node-triple": { type: "string" },
46
- "python-tag": { type: "string" },
47
- os: { type: "string" },
48
- cpu: { type: "string" },
49
- libc: { type: "string" },
50
- facade: { type: "string" },
51
- version: { type: "string" },
52
- output: { type: "string" },
53
- "skip-build": { type: "boolean" },
54
- },
55
- });
56
-
57
- const required = (name) => {
58
- const value = parsed.values[name];
59
- if (!value) throw new Error(`Missing --${name}`);
60
- return value;
61
- };
62
-
63
- const root = resolve(parsed.values.root ?? process.cwd());
64
- const commandInvocation = (command, args) => {
65
- if (process.platform !== "win32" || command !== "npm") return { command, args };
66
- const npmCli = resolve(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
67
- if (!existsSync(npmCli)) throw new Error(`Missing npm CLI ${npmCli}`);
68
- return { command: process.execPath, args: [npmCli, ...args] };
69
- };
70
- const run = (command, args, cwd = root) => {
71
- const invocation = commandInvocation(command, args);
72
- const result = spawnSync(invocation.command, invocation.args, { cwd, stdio: "inherit" });
73
- if (result.error) {
74
- throw new Error(`${invocation.command} failed: ${result.error.message}`, {
75
- cause: result.error,
76
- });
77
- }
78
- if (result.status !== 0) throw new Error(`${invocation.command} exited with ${result.status}`);
79
- };
80
-
81
- const runWithRetry = (command, args, cwd = root, attempts = 6) => {
82
- const signal = new Int32Array(new SharedArrayBuffer(4));
83
- for (let attempt = 1; attempt <= attempts; attempt += 1) {
84
- const invocation = commandInvocation(command, args);
85
- const result = spawnSync(invocation.command, invocation.args, { cwd, stdio: "inherit" });
86
- if (result.error) {
87
- throw new Error(`${invocation.command} failed: ${result.error.message}`, {
88
- cause: result.error,
89
- });
90
- }
91
- if (result.status === 0) return;
92
- if (attempt === attempts) {
93
- throw new Error(
94
- `${invocation.command} exited with ${result.status} after ${attempts} attempts`,
95
- );
96
- }
97
- Atomics.wait(signal, 0, 0, 10_000);
98
- }
99
- };
100
-
101
- const singlePackage = (directory) => {
102
- const packages = readdirSync(directory)
103
- .filter((file) => file.endsWith(".tgz"))
104
- .map((file) => resolve(directory, file));
105
- if (packages.length !== 1) {
106
- throw new Error(`Expected one npm package in ${directory}, found ${packages.length}`);
107
- }
108
- return packages[0];
109
- };
110
-
111
- const localWorkspacePackages = () => {
112
- const manifest = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"));
113
- const workspaces = Array.isArray(manifest.workspaces) ? manifest.workspaces : [];
114
- return new Map(
115
- workspaces.flatMap((directory) => {
116
- const manifestPath = resolve(root, directory, "package.json");
117
- if (!existsSync(manifestPath)) return [];
118
- const workspaceManifest = JSON.parse(readFileSync(manifestPath, "utf8"));
119
- return workspaceManifest.name ? [[workspaceManifest.name, workspaceManifest.version]] : [];
120
- }),
121
- );
122
- };
123
-
124
- /**
125
- * Read one bundled facade's static imports so local workspace dependency stubs
126
- * expose every requested ESM name. Callable proxy values support module helpers
127
- * and base classes that execute while the facade is imported.
128
- */
129
- const importedNames = (source, packageName) => {
130
- const escaped = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
131
- const pattern = new RegExp(`(?:^|\\n)import\\s+([^;]+?)\\s+from\\s+["']${escaped}["'];`, "g");
132
- const names = new Set();
133
- let hasDefault = false;
134
- for (const match of source.matchAll(pattern)) {
135
- const clause = match[1].trim();
136
- const named = /\{([\s\S]*?)\}/.exec(clause)?.[1];
137
- if (named) {
138
- for (const specifier of named.split(",")) {
139
- const name = specifier.trim().split(/\s+as\s+/)[0];
140
- if (name) names.add(name);
141
- }
142
- }
143
- const beforeNamed = clause.split(/[,{\s]/, 1)[0];
144
- if (beforeNamed && beforeNamed !== "*" && !clause.startsWith("{")) hasDefault = true;
145
- }
146
- return { names: [...names].sort(), hasDefault };
147
- };
148
-
149
- const testNodeFacade = ({
150
- facadeDirectory,
151
- facadePackage,
152
- manifest,
153
- nativePackage,
154
- nodePackage,
155
- }) => {
156
- const installDirectory = mkdtempSync(join(tmpdir(), "uniffi-facade-install-"));
157
- try {
158
- const workspacePackages = localWorkspacePackages();
159
- const facadeSource = readFileSync(join(facadeDirectory, "lib", "index.js"), "utf8");
160
- const bindings =
161
- JSON.parse(readFileSync(join(root, "package.json"), "utf8")).dbxToolsConfig?.rust?.bindings ??
162
- [];
163
- const localDependencies = Object.keys(manifest.dependencies ?? {}).flatMap((name, index) => {
164
- const workspaceVersion = workspacePackages.get(name);
165
- if (!workspaceVersion) return [];
166
- const binding = bindings.find((binding) => binding.nodePackage === name);
167
- if (binding) {
168
- const stagedFacade = resolve(root, "dist/uniffi/facades", binding.crate, "npm-facade");
169
- const stagedNative = resolve(root, "dist/uniffi/native");
170
- const nativeName = existsSync(stagedNative)
171
- ? readdirSync(stagedNative).find((file) =>
172
- file.startsWith(`${binding.crate}-${required("node-triple")}-`),
173
- )
174
- : undefined;
175
- if (existsSync(stagedFacade) && nativeName) {
176
- return [singlePackage(stagedFacade), join(stagedNative, nativeName)];
177
- }
178
- const output = resolve(root, "dist/release", binding.crate, required("node-triple"));
179
- if (existsSync(join(output, "npm-facade")) && existsSync(join(output, "npm"))) {
180
- return [singlePackage(join(output, "npm-facade")), singlePackage(join(output, "npm"))];
181
- }
182
- return [];
183
- }
184
- const directory = join(installDirectory, "local-dependencies", String(index));
185
- mkdirSync(directory, { recursive: true });
186
- writeFileSync(
187
- join(directory, "package.json"),
188
- `${JSON.stringify({
189
- name,
190
- version: workspaceVersion,
191
- type: "module",
192
- exports: "./index.js",
193
- })}\n`,
194
- );
195
- const imports = importedNames(facadeSource, name);
196
- writeFileSync(
197
- join(directory, "index.js"),
198
- [
199
- "const stub = new Proxy(function () {}, { get: () => stub, apply: () => stub });",
200
- ...imports.names.map((name) => `export const ${name} = stub;`),
201
- ...(imports.hasDefault ? ["export default stub;"] : []),
202
- "",
203
- ].join("\n"),
204
- );
205
- return [directory];
206
- });
207
- writeFileSync(
208
- join(installDirectory, "package.json"),
209
- `${JSON.stringify({ private: true, type: "module" })}\n`,
210
- );
211
- runWithRetry(
212
- "npm",
213
- [
214
- "install",
215
- "--ignore-scripts",
216
- "--no-audit",
217
- "--no-fund",
218
- "--package-lock=false",
219
- facadePackage,
220
- nativePackage,
221
- ...localDependencies,
222
- ],
223
- installDirectory,
224
- );
225
- run("node", ["-e", `import(${JSON.stringify(nodePackage)})`], installDirectory);
226
- } finally {
227
- rmSync(installDirectory, { recursive: true, force: true });
228
- }
229
- };
230
-
231
- /** Resolve workspace and generated catalog protocols for a publishable facade. */
232
- const facadeDependency = (name, dependency, catalog, workspaceVersions) => {
233
- if (typeof dependency !== "string") return dependency;
234
- if (dependency.startsWith("workspace:")) {
235
- const version = workspaceVersions.get(name);
236
- if (!version) throw new Error(`Missing workspace version for ${name}`);
237
- return dependency === "workspace:*"
238
- ? version
239
- : `${dependency.slice("workspace:".length)}${version}`;
240
- }
241
- if (!dependency.startsWith("catalog:")) return dependency;
242
- const resolved = catalog[name];
243
- if (!resolved) throw new Error(`Missing root catalog entry for ${name}`);
244
- return resolved;
245
- };
246
-
247
- const writable = (path) => {
248
- if (existsSync(path)) chmodSync(path, statSync(path).mode | 0o200);
249
- };
250
-
251
- const cargoMetadata = spawnSync("cargo", ["metadata", "--format-version", "1", "--no-deps"], {
252
- cwd: root,
253
- encoding: "utf8",
254
- });
255
- if (cargoMetadata.error) {
256
- throw new Error(`cargo metadata failed: ${cargoMetadata.error.message}`, {
257
- cause: cargoMetadata.error,
258
- });
259
- }
260
- if (cargoMetadata.status !== 0) {
261
- throw new Error(`cargo metadata exited with ${cargoMetadata.status}`);
262
- }
263
- const cargoTargetRoot = JSON.parse(cargoMetadata.stdout).target_directory;
264
- if (typeof cargoTargetRoot !== "string" || !cargoTargetRoot) {
265
- throw new Error("cargo metadata returned no target_directory");
266
- }
267
-
268
- const libraryPath = (crate, cargoTarget, os) => {
269
- const name = crate.replaceAll("-", "_");
270
- const extension = os === "darwin" ? "dylib" : os === "win32" ? "dll" : "so";
271
- const prefix = os === "win32" ? "" : "lib";
272
- return resolve(cargoTargetRoot, cargoTarget, "release", `${prefix}${name}.${extension}`);
273
- };
274
-
275
- const packageNode = ({
276
- library,
277
- output,
278
- nodeDirectory,
279
- nodePackage,
280
- nodeTriple,
281
- os,
282
- cpu,
283
- version,
284
- facade,
285
- }) => {
286
- const libraryFile = basename(library);
287
- const sourceManifest = JSON.parse(
288
- readFileSync(resolve(root, nodeDirectory, "package.json"), "utf8"),
289
- );
290
- const nativePackage = resolve(output, "native-node");
291
- mkdirSync(nativePackage, { recursive: true });
292
- cpSync(library, join(nativePackage, libraryFile));
293
- writeFileSync(
294
- join(nativePackage, "package.json"),
295
- `${JSON.stringify(
296
- {
297
- name: `${nodePackage}-${nodeTriple}`,
298
- version,
299
- description: `Native ${nodeTriple} library for ${nodePackage}`,
300
- repository: sourceManifest.repository,
301
- license: "Apache-2.0",
302
- os: [os],
303
- cpu: [cpu],
304
- ...(parsed.values.libc ? { libc: [parsed.values.libc] } : {}),
305
- files: [libraryFile],
306
- },
307
- null,
308
- 2,
309
- )}\n`,
310
- );
311
- mkdirSync(resolve(output, "npm"), { recursive: true });
312
- run("npm", ["pack", "--pack-destination", resolve(output, "npm")], nativePackage);
313
-
314
- if (!facade) return;
315
- packageNodeFacade({
316
- output,
317
- nodeDirectory,
318
- nodePackage,
319
- version,
320
- nativePackage: singlePackage(resolve(output, "npm")),
321
- });
322
- };
323
-
324
- const packageNodeFacade = ({ output, nodeDirectory, nodePackage, version, nativePackage }) => {
325
- const facadeDirectory = resolve(output, "facade-node");
326
- rmSync(facadeDirectory, { recursive: true, force: true });
327
- rmSync(resolve(output, "npm-facade"), { recursive: true, force: true });
328
- mkdirSync(output, { recursive: true });
329
- cpSync(resolve(root, nodeDirectory), facadeDirectory, { recursive: true });
330
- rmSync(join(facadeDirectory, "dist"), { recursive: true, force: true });
331
- const barrel = join(facadeDirectory, "index.ts");
332
- const barrelVersion = /^export const PACKAGE_VERSION = "([^"]+)";$/m.exec(
333
- readFileSync(barrel, "utf8"),
334
- )?.[1];
335
- if (barrelVersion !== version) {
336
- throw new Error(`Facade PACKAGE_VERSION ${String(barrelVersion)} does not match ${version}`);
337
- }
338
- for (const file of readdirSync(join(facadeDirectory, "src"))) {
339
- if (/\.(dll|dylib|so)$/.test(file)) {
340
- rmSync(join(facadeDirectory, "src", file), { force: true });
341
- }
342
- }
343
- const ffiBindings = join(facadeDirectory, "src", "_bindings-ffi.ts");
344
- writable(ffiBindings);
345
- const ffiSource = readFileSync(ffiBindings, "utf8");
346
- const packageSource = ffiSource.replace(
347
- /(\s+callerUrl: import\.meta\.url,\n)(\s+\}\);)/,
348
- `$1 npmPackageBase: ${JSON.stringify(`${nodePackage}-`)},\n tripleStyle: "node",\n$2`,
349
- );
350
- if (packageSource === ffiSource) {
351
- throw new Error(`Could not configure native package lookup in ${ffiBindings}`);
352
- }
353
- writeFileSync(ffiBindings, packageSource);
354
- const manifestPath = join(facadeDirectory, "package.json");
355
- writable(manifestPath);
356
- const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
357
- const workspaceManifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
358
- const catalog = workspaceManifest.catalog ?? {};
359
- const workspaceVersions = localWorkspacePackages();
360
- if (manifest.version !== version) {
361
- throw new Error(`Facade package version ${String(manifest.version)} does not match ${version}`);
362
- }
363
- if (manifest.private === true) throw new Error(`${manifest.name} is private`);
364
- manifest.license = manifest.license === "UNLICENSED" ? "Apache-2.0" : manifest.license;
365
- manifest.optionalDependencies = Object.fromEntries(
366
- Object.entries(manifest.optionalDependencies ?? {}).map(([name, dependency]) => {
367
- if (dependency !== version) {
368
- throw new Error(`${manifest.name} optional dependency ${name} does not match ${version}`);
369
- }
370
- return [name, dependency];
371
- }),
372
- );
373
- manifest.dependencies = Object.fromEntries(
374
- Object.entries(manifest.dependencies ?? {}).map(([name, dependency]) => [
375
- name,
376
- facadeDependency(name, dependency, catalog, workspaceVersions),
377
- ]),
378
- );
379
- writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
380
- // Node loads the facade from node_modules, so every TypeScript entry point
381
- // must be emitted and advertised as JavaScript.
382
- rmSync(join(facadeDirectory, "lib"), { recursive: true, force: true });
383
- run(
384
- "bun",
385
- [
386
- "build",
387
- "index.ts",
388
- "--outdir",
389
- "lib",
390
- "--target",
391
- "node",
392
- "--format",
393
- "esm",
394
- "--packages",
395
- "external",
396
- ],
397
- facadeDirectory,
398
- );
399
- const compiledPublish = { ...(manifest.publishConfig ?? {}) };
400
- delete compiledPublish.access;
401
- Object.assign(manifest, compiledPublish);
402
- manifest.types = "./index.ts";
403
- manifest.exports["."].types = "./index.ts";
404
- delete manifest.publishConfig;
405
- delete manifest.scripts;
406
- delete manifest.devDependencies;
407
- writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
408
- const facadeOutput = resolve(output, "npm-facade");
409
- mkdirSync(facadeOutput, { recursive: true });
410
- run("npm", ["pack", "--pack-destination", facadeOutput], facadeDirectory);
411
- if (nativePackage) {
412
- testNodeFacade({
413
- facadeDirectory,
414
- facadePackage: singlePackage(facadeOutput),
415
- manifest,
416
- nativePackage,
417
- nodePackage,
418
- });
419
- }
420
- };
421
-
422
- const packagePython = ({
423
- crate,
424
- library,
425
- output,
426
- pythonDirectory,
427
- pythonTag,
428
- version,
429
- cargoTarget,
430
- generatorTarget,
431
- os,
432
- pythonModule,
433
- pythonBindings,
434
- }) => {
435
- const pythonRoot = resolve(output, "python-root");
436
- cpSync(resolve(root, pythonDirectory), pythonRoot, { recursive: true });
437
- const pyproject = join(pythonRoot, "pyproject.toml");
438
- writable(pyproject);
439
- const workspaceBindings =
440
- JSON.parse(readFileSync(join(root, "package.json"), "utf8")).dbxToolsConfig?.rust?.bindings ??
441
- [];
442
- writeFileSync(
443
- pyproject,
444
- preparePythonProjectForPublication(readFileSync(pyproject, "utf8"), {
445
- packages: workspaceBindings.flatMap((binding) =>
446
- binding.pythonPackage && binding.python
447
- ? [{ name: binding.pythonPackage, directory: binding.python }]
448
- : [],
449
- ),
450
- toml,
451
- version,
452
- }),
453
- );
454
- installPythonBindings({
455
- crate,
456
- library,
457
- module: pythonModule,
458
- packageRoot: pythonRoot,
459
- platform: os,
460
- generatedSource: pythonBindings,
461
- run,
462
- targetDirectory: resolve(cargoTargetRoot, generatorTarget ?? cargoTarget, "release"),
463
- });
464
-
465
- const wheelDirectory = resolve(output, "python");
466
- mkdirSync(wheelDirectory, { recursive: true });
467
- run("uv", ["build", "--wheel", "--out-dir", wheelDirectory], pythonRoot);
468
- const wheels = readdirSync(wheelDirectory).filter((file) => file.endsWith(".whl"));
469
- if (wheels.length !== 1) throw new Error(`Expected one Python wheel, found ${wheels.length}`);
470
- run("uvx", [
471
- "--from",
472
- "wheel",
473
- "wheel",
474
- "tags",
475
- "--remove",
476
- "--platform-tag",
477
- pythonTag,
478
- join(wheelDirectory, wheels[0]),
479
- ]);
480
- };
481
-
482
- const generatePython = () => {
483
- const crate = required("crate");
484
- const cargoTarget = required("cargo-target");
485
- const os = required("os");
486
- const output = resolve(root, required("output"));
487
- const generator = resolve(
488
- cargoTargetRoot,
489
- cargoTarget,
490
- "release",
491
- pythonBindingGeneratorName(crate, os),
492
- );
493
- const library = libraryPath(crate, cargoTarget, os);
494
- if (!existsSync(generator)) throw new Error(`Missing UniFFI generator ${generator}`);
495
- if (!existsSync(library)) throw new Error(`Missing native library ${library}`);
496
- rmSync(output, { recursive: true, force: true });
497
- mkdirSync(output, { recursive: true });
498
- run(generator, pythonBindingGeneratorArgs({ crate, library, output }));
499
- };
500
-
501
- const build = () => {
502
- const crate = required("crate");
503
- const cargoTarget = required("cargo-target");
504
- const nodeTriple = required("node-triple");
505
- const pythonTag = required("python-tag");
506
- const version = required("version");
507
- const os = required("os");
508
- const cpu = required("cpu");
509
- const output = resolve(root, required("output"));
510
- const library = libraryPath(crate, cargoTarget, os);
511
-
512
- rmSync(output, { recursive: true, force: true });
513
- mkdirSync(output, { recursive: true });
514
- if (!parsed.values["skip-build"]) {
515
- run("cargo", [
516
- "build",
517
- "--release",
518
- ...(existsSync(resolve(root, "Cargo.lock")) ? ["--locked"] : []),
519
- "--package",
520
- crate,
521
- "--features",
522
- "uniffi-bindgen",
523
- "--target",
524
- cargoTarget,
525
- ]);
526
- }
527
- if (!existsSync(library)) throw new Error(`Missing native library ${library}`);
528
-
529
- const nodeDirectory = parsed.values.node;
530
- const nodePackage = parsed.values["node-package"];
531
- if (nodeDirectory && nodePackage) {
532
- packageNode({
533
- library,
534
- output,
535
- nodeDirectory,
536
- nodePackage,
537
- nodeTriple,
538
- os,
539
- cpu,
540
- version,
541
- facade: parsed.values.facade === "true",
542
- });
543
- }
544
-
545
- const pythonDirectory = parsed.values.python;
546
- if (pythonDirectory) {
547
- packagePython({
548
- crate,
549
- library,
550
- output,
551
- pythonDirectory,
552
- pythonTag,
553
- version,
554
- cargoTarget,
555
- generatorTarget: parsed.values["generator-target"],
556
- os,
557
- pythonModule: required("python-module"),
558
- pythonBindings: parsed.values["python-bindings"],
559
- });
560
- }
561
- };
562
-
563
- if (parsed.positionals[0] === "build") {
564
- build();
565
- } else if (parsed.positionals[0] === "generate-python") {
566
- generatePython();
567
- } else if (parsed.positionals[0] === "facade") {
568
- packageNodeFacade({
569
- output: resolve(root, required("output")),
570
- nodeDirectory: required("node"),
571
- nodePackage: required("node-package"),
572
- version: required("version"),
573
- nativePackage: parsed.values["native-package"]
574
- ? resolve(root, parsed.values["native-package"])
575
- : undefined,
576
- });
577
- } else {
578
- throw new Error("Expected build or facade command");
579
- }