@dbx-tools/projen 0.9.19 → 0.9.28
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 +83 -229
- package/index.ts +11 -18
- package/package.json +9 -5
- package/src/_task-command.ts +75 -0
- package/src/barrels.ts +1 -74
- package/src/module-exports.ts +175 -1
- package/src/openapi.ts +5 -72
- package/src/packages.ts +45 -0
- package/src/project-js.ts +5 -48
- package/src/project-predicate.ts +1 -2
- package/src/project-py.ts +87 -199
- package/src/project.ts +2 -2
- package/src/python-node-bindings.ts +138 -0
- package/src/python-node-bundle.ts +92 -0
- package/src/release-catalog.ts +40 -208
- package/src/{release-dispatch.ts → release-context.ts} +0 -11
- package/src/release.ts +74 -778
- package/src/scaffold.ts +2 -6
- package/src/workspace-version.ts +9 -121
- package/tasks/bump.ts +17 -34
- package/tasks/databricks-cli-assets.ts +129 -0
- package/tasks/local-publish.ts +61 -138
- package/tasks/publish-npm.ts +71 -30
- package/tasks/publish-python.ts +61 -148
- package/tasks/publish.ts +32 -182
- package/tasks/python-node-bindings-watch.ts +47 -0
- package/tasks/python-node-bindings.ts +1017 -0
- package/tasks/python-registry.ts +2 -9
- package/tasks/python-release.ts +74 -0
- package/tasks/release-version.ts +23 -2
- package/tasks/release.ts +99 -0
- package/tasks/sync.ts +13 -18
- package/tasks/version-check.ts +13 -72
- package/src/_rust-project.ts +0 -429
- package/src/_rust-release-workflow.ts +0 -698
- package/src/project-rs.ts +0 -1127
- package/src/release-plan.ts +0 -269
- package/src/release-please.ts +0 -242
- package/src/uniffi.ts +0 -65
- package/tasks/publish-uniffi-local.ts +0 -314
- package/tasks/release-assets.ts +0 -476
- package/tasks/release-bootstrap.ts +0 -59
- package/tasks/release-candidate.ts +0 -383
- package/tasks/release-manifest.ts +0 -273
- package/tasks/release-plan.ts +0 -89
- package/tasks/release-please.ts +0 -162
- package/tasks/release-pr.ts +0 -563
- package/tasks/release-request.ts +0 -166
- package/tasks/release-summary-units.ts +0 -75
- package/tasks/release-summary.ts +0 -381
- package/tasks/rust.ts +0 -178
- package/tasks/stamp-python.ts +0 -13
- package/tasks/uniffi-python.d.ts +0 -61
- package/tasks/uniffi-python.js +0 -191
- package/tasks/uniffi-release.mjs +0 -573
- package/tasks/uniffi.ts +0 -271
package/tasks/uniffi.ts
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env -S bun
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
import {
|
|
4
|
-
cpSync,
|
|
5
|
-
existsSync,
|
|
6
|
-
mkdirSync,
|
|
7
|
-
mkdtempSync,
|
|
8
|
-
readFileSync,
|
|
9
|
-
readdirSync,
|
|
10
|
-
renameSync,
|
|
11
|
-
rmSync,
|
|
12
|
-
writeFileSync,
|
|
13
|
-
} from "node:fs";
|
|
14
|
-
import { tmpdir } from "node:os";
|
|
15
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
16
|
-
import { fileURLToPath } from "node:url";
|
|
17
|
-
import { parseArgs } from "node:util";
|
|
18
|
-
import { installPythonBindings } from "./uniffi-python.js";
|
|
19
|
-
import { makeReadonly, makeWritable, stampGenerated } from "../src/generated.ts";
|
|
20
|
-
import type { RustWorkspaceMapping } from "../src/project-rs.ts";
|
|
21
|
-
import {
|
|
22
|
-
addExplicitInterfaceReexports,
|
|
23
|
-
addTypeScriptExtensionsToBindingImports,
|
|
24
|
-
makeDefaultedInterfaceParametersOptional,
|
|
25
|
-
removeObsoleteInterfaceAliases,
|
|
26
|
-
} from "../src/uniffi.ts";
|
|
27
|
-
|
|
28
|
-
const { values } = parseArgs({
|
|
29
|
-
options: {
|
|
30
|
-
root: { type: "string" },
|
|
31
|
-
crate: { type: "string" },
|
|
32
|
-
node: { type: "string" },
|
|
33
|
-
python: { type: "string" },
|
|
34
|
-
"python-module": { type: "string" },
|
|
35
|
-
"cargo-target": { type: "string" },
|
|
36
|
-
"node-package-base": { type: "string" },
|
|
37
|
-
ubrn: { type: "string" },
|
|
38
|
-
"skip-build": { type: "boolean" },
|
|
39
|
-
"skip-barrels": { type: "boolean" },
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
if (!values.crate || (!values.node && !values.python)) {
|
|
43
|
-
throw new Error("Expected --crate and at least one of --node or --python");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const root = values.root
|
|
47
|
-
? resolve(values.root)
|
|
48
|
-
: resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
49
|
-
const crate = values.crate;
|
|
50
|
-
const libraryName = crate.replaceAll("-", "_");
|
|
51
|
-
const workspace = JSON.parse(readFileSync(join(root, "package.json"), "utf8")).dbxToolsConfig
|
|
52
|
-
?.rust as RustWorkspaceMapping | undefined;
|
|
53
|
-
const binding = workspace?.bindings.find((binding) => binding.crate === crate);
|
|
54
|
-
const dependencies =
|
|
55
|
-
workspace?.bindings.filter((candidate) => binding?.dependencies?.includes(candidate.crate)) ?? [];
|
|
56
|
-
const extension =
|
|
57
|
-
process.platform === "darwin" ? "dylib" : process.platform === "win32" ? "dll" : "so";
|
|
58
|
-
const prefix = process.platform === "win32" ? "" : "lib";
|
|
59
|
-
const normalizedOutput = (value: string): string =>
|
|
60
|
-
value
|
|
61
|
-
.replace(/[\p{Extended_Pictographic}\uFE0F]/gu, "")
|
|
62
|
-
.replace(/[ \t]+$/gm, "")
|
|
63
|
-
.trim();
|
|
64
|
-
const run = (command: string, args: string[]) => {
|
|
65
|
-
const result = spawnSync(command, args, { cwd: root, encoding: "utf8" });
|
|
66
|
-
const stdout = normalizedOutput(result.stdout ?? "");
|
|
67
|
-
const stderr = normalizedOutput(result.stderr ?? "");
|
|
68
|
-
if (stdout) process.stdout.write(`${stdout}\n`);
|
|
69
|
-
if (stderr) process.stderr.write(`${stderr}\n`);
|
|
70
|
-
if (result.error) {
|
|
71
|
-
throw new Error(`${command} failed: ${result.error.message}`, { cause: result.error });
|
|
72
|
-
}
|
|
73
|
-
if (result.status !== 0) throw new Error(`${command} exited with ${result.status}`);
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const cargoMetadata = spawnSync("cargo", ["metadata", "--format-version", "1", "--no-deps"], {
|
|
77
|
-
cwd: root,
|
|
78
|
-
encoding: "utf8",
|
|
79
|
-
});
|
|
80
|
-
if (cargoMetadata.error) {
|
|
81
|
-
throw new Error(`cargo metadata failed: ${cargoMetadata.error.message}`, {
|
|
82
|
-
cause: cargoMetadata.error,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
if (cargoMetadata.status !== 0) {
|
|
86
|
-
throw new Error(`cargo metadata exited with ${cargoMetadata.status}`);
|
|
87
|
-
}
|
|
88
|
-
const cargoTargetRoot = (JSON.parse(cargoMetadata.stdout) as { target_directory?: unknown })
|
|
89
|
-
.target_directory;
|
|
90
|
-
if (typeof cargoTargetRoot !== "string" || !cargoTargetRoot) {
|
|
91
|
-
throw new Error("cargo metadata returned no target_directory");
|
|
92
|
-
}
|
|
93
|
-
const targetDirectory = values["cargo-target"]
|
|
94
|
-
? join(cargoTargetRoot, values["cargo-target"], "release")
|
|
95
|
-
: join(cargoTargetRoot, "release");
|
|
96
|
-
const library = join(targetDirectory, `${prefix}${libraryName}.${extension}`);
|
|
97
|
-
|
|
98
|
-
const replaceGenerated = (source: string, destination: string): void => {
|
|
99
|
-
const deadline = Date.now() + 5_000;
|
|
100
|
-
const signal = new Int32Array(new SharedArrayBuffer(4));
|
|
101
|
-
while (!existsSync(source) && Date.now() < deadline) Atomics.wait(signal, 0, 0, 25);
|
|
102
|
-
if (!existsSync(source)) throw new Error(`Missing generated binding: ${source}`);
|
|
103
|
-
mkdirSync(dirname(destination), { recursive: true });
|
|
104
|
-
makeWritable(destination);
|
|
105
|
-
rmSync(destination, { force: true });
|
|
106
|
-
try {
|
|
107
|
-
renameSync(source, destination);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
if (!(error instanceof Error) || !("code" in error) || error.code !== "EXDEV") throw error;
|
|
110
|
-
cpSync(source, destination);
|
|
111
|
-
rmSync(source, { force: true });
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
if (!values["skip-build"]) {
|
|
116
|
-
run("cargo", [
|
|
117
|
-
"build",
|
|
118
|
-
"--release",
|
|
119
|
-
...(existsSync(join(root, "Cargo.lock")) ? ["--locked"] : []),
|
|
120
|
-
"--package",
|
|
121
|
-
crate,
|
|
122
|
-
"--features",
|
|
123
|
-
"uniffi-bindgen",
|
|
124
|
-
...(values["cargo-target"] ? ["--target", values["cargo-target"]] : []),
|
|
125
|
-
]);
|
|
126
|
-
}
|
|
127
|
-
if (!existsSync(library)) throw new Error(`Missing compiled UniFFI library: ${library}`);
|
|
128
|
-
|
|
129
|
-
if (values.node) {
|
|
130
|
-
const nodeSource = resolve(root, values.node, "src");
|
|
131
|
-
const nodeOutput = mkdtempSync(join(tmpdir(), `${libraryName}-node-`));
|
|
132
|
-
run(values.ubrn ? resolve(values.ubrn) : join(root, "node_modules/.bin/ubrn"), [
|
|
133
|
-
"generate",
|
|
134
|
-
"napi",
|
|
135
|
-
"bindings",
|
|
136
|
-
"--library",
|
|
137
|
-
"--ts-dir",
|
|
138
|
-
nodeOutput,
|
|
139
|
-
...(values["node-package-base"]
|
|
140
|
-
? ["--lib-package-base", values["node-package-base"], "--lib-node-triple"]
|
|
141
|
-
: ["--lib-colocated"]),
|
|
142
|
-
library,
|
|
143
|
-
]);
|
|
144
|
-
const generatedModules = readdirSync(nodeOutput).filter(
|
|
145
|
-
(file) => file.endsWith(".ts") && file !== "index.ts",
|
|
146
|
-
);
|
|
147
|
-
for (const dependency of dependencies) {
|
|
148
|
-
if (!dependency.nodePackage) throw new Error(`Missing Node binding for ${dependency.crate}`);
|
|
149
|
-
const namespace = dependency.crate.replaceAll("-", "_");
|
|
150
|
-
for (const file of readdirSync(nodeOutput).filter((file) => file.endsWith(".ts"))) {
|
|
151
|
-
const path = join(nodeOutput, file);
|
|
152
|
-
const source = readFileSync(path, "utf8")
|
|
153
|
-
.replace(
|
|
154
|
-
new RegExp(`import (\\w+) from ["']\\./${namespace}["'];`, "g"),
|
|
155
|
-
`import { uniffiModule as $1 } from "${dependency.nodePackage}";`,
|
|
156
|
-
)
|
|
157
|
-
.replaceAll(`'./${namespace}'`, `'${dependency.nodePackage}'`)
|
|
158
|
-
.replaceAll(`"./${namespace}"`, `"${dependency.nodePackage}"`);
|
|
159
|
-
writeFileSync(path, source);
|
|
160
|
-
}
|
|
161
|
-
for (const suffix of [".ts", "-ffi.ts"]) {
|
|
162
|
-
const file = `${namespace}${suffix}`;
|
|
163
|
-
rmSync(join(nodeOutput, file), { force: true });
|
|
164
|
-
const index = generatedModules.indexOf(file);
|
|
165
|
-
if (index >= 0) generatedModules.splice(index, 1);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
const ownModules = generatedModules.filter(
|
|
169
|
-
(file) => file === `${libraryName}.ts` || file === `${libraryName}-ffi.ts`,
|
|
170
|
-
);
|
|
171
|
-
if (ownModules.length !== 2 || generatedModules.length !== 2) {
|
|
172
|
-
throw new Error(`Unmapped UniFFI components in ${crate}: ${generatedModules.join(", ")}`);
|
|
173
|
-
}
|
|
174
|
-
writeFileSync(
|
|
175
|
-
join(nodeOutput, "index.ts"),
|
|
176
|
-
[
|
|
177
|
-
`export * from './${libraryName}';`,
|
|
178
|
-
`import uniffiModule from './${libraryName}';`,
|
|
179
|
-
"uniffiModule.initialize();",
|
|
180
|
-
"export { uniffiModule };",
|
|
181
|
-
"export async function uniffiInitAsync() {}",
|
|
182
|
-
"",
|
|
183
|
-
].join("\n"),
|
|
184
|
-
);
|
|
185
|
-
const nodeBindings = join(nodeSource, "bindings.ts");
|
|
186
|
-
const generatedFiles = [join(nodeSource, "_bindings.ts"), join(nodeSource, "_bindings-ffi.ts")];
|
|
187
|
-
const legacyExports = resolve(root, values.node, "exports.ts");
|
|
188
|
-
if (
|
|
189
|
-
existsSync(legacyExports) &&
|
|
190
|
-
readFileSync(legacyExports, "utf8").trim() === 'export * from "./src/bindings.ts";'
|
|
191
|
-
) {
|
|
192
|
-
makeWritable(legacyExports);
|
|
193
|
-
rmSync(legacyExports, { force: true });
|
|
194
|
-
}
|
|
195
|
-
replaceGenerated(join(nodeOutput, "index.ts"), nodeBindings);
|
|
196
|
-
replaceGenerated(join(nodeOutput, libraryName + ".ts"), generatedFiles[0]);
|
|
197
|
-
replaceGenerated(join(nodeOutput, libraryName + "-ffi.ts"), generatedFiles[1]);
|
|
198
|
-
writeFileSync(
|
|
199
|
-
nodeBindings,
|
|
200
|
-
readFileSync(nodeBindings, "utf8").replaceAll("./" + libraryName, "./_bindings"),
|
|
201
|
-
);
|
|
202
|
-
writeFileSync(
|
|
203
|
-
generatedFiles[0],
|
|
204
|
-
readFileSync(generatedFiles[0], "utf8").replaceAll(
|
|
205
|
-
"./" + libraryName + "-ffi",
|
|
206
|
-
"./_bindings-ffi",
|
|
207
|
-
),
|
|
208
|
-
);
|
|
209
|
-
for (const file of generatedFiles) {
|
|
210
|
-
writeFileSync(
|
|
211
|
-
file,
|
|
212
|
-
removeObsoleteInterfaceAliases(
|
|
213
|
-
makeDefaultedInterfaceParametersOptional(readFileSync(file, "utf8")),
|
|
214
|
-
),
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
writeFileSync(
|
|
218
|
-
nodeBindings,
|
|
219
|
-
addExplicitInterfaceReexports(
|
|
220
|
-
readFileSync(nodeBindings, "utf8"),
|
|
221
|
-
generatedFiles.map((file) => ({
|
|
222
|
-
specifier: `./${basename(file, ".ts")}`,
|
|
223
|
-
source: readFileSync(file, "utf8"),
|
|
224
|
-
})),
|
|
225
|
-
),
|
|
226
|
-
);
|
|
227
|
-
for (const file of [nodeBindings, ...generatedFiles]) {
|
|
228
|
-
// Consumers type-check these files through workspace source exports, while
|
|
229
|
-
// the generated runtime internals are validated by UniFFI's own build.
|
|
230
|
-
const source = addTypeScriptExtensionsToBindingImports(readFileSync(file, "utf8")).replace(
|
|
231
|
-
/[ \t]+$/gm,
|
|
232
|
-
"",
|
|
233
|
-
);
|
|
234
|
-
writeFileSync(file, `/* eslint-disable */\n// @ts-nocheck\n${source}`);
|
|
235
|
-
stampGenerated(file, {
|
|
236
|
-
tool: "UniFFI binding generation",
|
|
237
|
-
source: `the ${crate} Rust exports`,
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
if (!values["node-package-base"]) {
|
|
241
|
-
const nodeLibrary = join(nodeSource, basename(library));
|
|
242
|
-
makeWritable(nodeLibrary);
|
|
243
|
-
cpSync(library, nodeLibrary);
|
|
244
|
-
makeReadonly(nodeLibrary);
|
|
245
|
-
}
|
|
246
|
-
rmSync(resolve(root, values.node, "src/generated"), { recursive: true, force: true });
|
|
247
|
-
rmSync(nodeOutput, { recursive: true, force: true });
|
|
248
|
-
if (!values["skip-barrels"]) {
|
|
249
|
-
run(process.execPath, [
|
|
250
|
-
resolve(dirname(fileURLToPath(import.meta.url)), "barrels.ts"),
|
|
251
|
-
"--dir",
|
|
252
|
-
resolve(root, values.node),
|
|
253
|
-
]);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (values.python) {
|
|
258
|
-
if (!values["python-module"]) {
|
|
259
|
-
throw new Error("Expected --python-module with --python");
|
|
260
|
-
}
|
|
261
|
-
installPythonBindings({
|
|
262
|
-
crate,
|
|
263
|
-
library,
|
|
264
|
-
module: values["python-module"],
|
|
265
|
-
packageRoot: resolve(root, values.python),
|
|
266
|
-
platform: process.platform,
|
|
267
|
-
readonly: true,
|
|
268
|
-
run,
|
|
269
|
-
targetDirectory,
|
|
270
|
-
});
|
|
271
|
-
}
|