@dbx-tools/projen 0.9.12 → 0.9.17
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 +20 -15
- package/index.ts +4 -3
- package/package.json +4 -4
- package/src/_rust-project.ts +37 -13
- package/src/_rust-release-workflow.ts +267 -164
- package/src/_rust-release.ts +38 -10
- package/src/openapi.ts +191 -79
- package/src/project-py.ts +4 -4
- package/src/project-rs.ts +57 -6
- package/src/release-plan.ts +57 -16
- package/src/release.ts +2 -1
- package/src/watch.ts +19 -2
- package/src/workspace-lock.ts +32 -6
- package/tasks/barrels.ts +47 -30
- package/tasks/openapi.ts +15 -11
- package/tasks/release-plan.ts +2 -1
- package/tasks/release-pr.ts +1 -1
- package/tasks/rust-release.d.ts +9 -5
- package/tasks/rust-release.mjs +20 -11
- package/tasks/rust.ts +62 -33
- package/tasks/uniffi-release.mjs +5 -1
- package/tasks/uniffi.ts +2 -0
package/tasks/rust-release.mjs
CHANGED
|
@@ -1248,7 +1248,7 @@ function stringify(obj, { maxDepth = 1000, numbersAsFloat = false } = {}) {
|
|
|
1248
1248
|
*/
|
|
1249
1249
|
|
|
1250
1250
|
// src/_rust-release.ts
|
|
1251
|
-
var FINGERPRINT_SCHEMA =
|
|
1251
|
+
var FINGERPRINT_SCHEMA = 4;
|
|
1252
1252
|
var VERSION_SLOT_SCHEMA = 1;
|
|
1253
1253
|
var VERSION_CAPACITY = 64;
|
|
1254
1254
|
var MAGIC = Buffer.from("DBXVERSION\x00\x00", "binary");
|
|
@@ -1337,9 +1337,9 @@ function workspaceVersion(root) {
|
|
|
1337
1337
|
function toPosix(path) {
|
|
1338
1338
|
return path.split(sep).join("/");
|
|
1339
1339
|
}
|
|
1340
|
-
function sourceRoots(root, metadata, sources) {
|
|
1340
|
+
function sourceRoots(root, metadata, sources, includeWorkspace) {
|
|
1341
1341
|
const members = new Set(metadata.workspace_members);
|
|
1342
|
-
const discovered = metadata.packages.filter((candidate) => members.has(candidate.id)).map((candidate) => dirname(candidate.manifest_path));
|
|
1342
|
+
const discovered = includeWorkspace ? metadata.packages.filter((candidate) => members.has(candidate.id)).map((candidate) => dirname(candidate.manifest_path)) : [];
|
|
1343
1343
|
return [...new Set([...discovered, ...sources.map((source) => resolve(root, source))])].map((path) => toPosix(relative(root, path)) || ".").sort();
|
|
1344
1344
|
}
|
|
1345
1345
|
function ignoredInput(path) {
|
|
@@ -1397,13 +1397,13 @@ function normalizedInput(root, file, content, packageNames) {
|
|
|
1397
1397
|
}
|
|
1398
1398
|
return content;
|
|
1399
1399
|
}
|
|
1400
|
-
function sourceHash(root, sources = []) {
|
|
1400
|
+
function sourceHash(root, sources = [], includeWorkspace = true) {
|
|
1401
1401
|
const resolvedRoot = resolve(root);
|
|
1402
1402
|
const metadata = cargoMetadata(resolvedRoot);
|
|
1403
1403
|
const members = new Set(metadata.workspace_members);
|
|
1404
1404
|
const packageNames = new Set(metadata.packages.filter((candidate) => members.has(candidate.id)).map((candidate) => candidate.name));
|
|
1405
1405
|
const hash = createHash("sha256");
|
|
1406
|
-
for (const file of inputFiles(resolvedRoot, sourceRoots(resolvedRoot, metadata, sources))) {
|
|
1406
|
+
for (const file of inputFiles(resolvedRoot, sourceRoots(resolvedRoot, metadata, sources, includeWorkspace))) {
|
|
1407
1407
|
const absolute = join(resolvedRoot, file);
|
|
1408
1408
|
const stat = lstatSync(absolute);
|
|
1409
1409
|
hash.update(file);
|
|
@@ -1426,6 +1426,7 @@ function linkerIdentity(target) {
|
|
|
1426
1426
|
}
|
|
1427
1427
|
function targetKey({
|
|
1428
1428
|
rustSourceHash,
|
|
1429
|
+
namespace = "workspace",
|
|
1429
1430
|
target,
|
|
1430
1431
|
targetConfig = "",
|
|
1431
1432
|
toolchain = "stable",
|
|
@@ -1435,6 +1436,7 @@ function targetKey({
|
|
|
1435
1436
|
for (const value of [
|
|
1436
1437
|
String(FINGERPRINT_SCHEMA),
|
|
1437
1438
|
String(VERSION_SLOT_SCHEMA),
|
|
1439
|
+
namespace,
|
|
1438
1440
|
rustSourceHash,
|
|
1439
1441
|
target,
|
|
1440
1442
|
targetConfig,
|
|
@@ -1460,12 +1462,14 @@ function fingerprint({
|
|
|
1460
1462
|
targets,
|
|
1461
1463
|
toolchain = "stable",
|
|
1462
1464
|
portable = false,
|
|
1463
|
-
sources = []
|
|
1465
|
+
sources = [],
|
|
1466
|
+
sourceOnly = false,
|
|
1467
|
+
namespace = "workspace"
|
|
1464
1468
|
}) {
|
|
1465
1469
|
if (!targets.length)
|
|
1466
1470
|
throw new Error("at least one --target is required");
|
|
1467
1471
|
const resolvedRoot = resolve(root);
|
|
1468
|
-
const rustSourceHash = sourceHash(resolvedRoot, sources);
|
|
1472
|
+
const rustSourceHash = sourceHash(resolvedRoot, sources, !sourceOnly);
|
|
1469
1473
|
const rustc = portable ? undefined : rustcIdentity();
|
|
1470
1474
|
const targetEntries = targets.map((specification) => {
|
|
1471
1475
|
const separator = specification.indexOf("|");
|
|
@@ -1473,12 +1477,13 @@ function fingerprint({
|
|
|
1473
1477
|
const targetConfig = separator < 0 ? "" : specification.slice(separator + 1);
|
|
1474
1478
|
return [
|
|
1475
1479
|
target,
|
|
1476
|
-
targetKey({ rustSourceHash, target, targetConfig, toolchain, rustc })
|
|
1480
|
+
targetKey({ rustSourceHash, namespace, target, targetConfig, toolchain, rustc })
|
|
1477
1481
|
];
|
|
1478
1482
|
}).sort(([left], [right]) => left.localeCompare(right));
|
|
1479
1483
|
const manifest = {
|
|
1480
1484
|
schemaVersion: FINGERPRINT_SCHEMA,
|
|
1481
1485
|
versionSlotSchema: VERSION_SLOT_SCHEMA,
|
|
1486
|
+
namespace,
|
|
1482
1487
|
rustSourceHash,
|
|
1483
1488
|
targets: Object.fromEntries(targetEntries)
|
|
1484
1489
|
};
|
|
@@ -1486,7 +1491,7 @@ function fingerprint({
|
|
|
1486
1491
|
if (check) {
|
|
1487
1492
|
const current = JSON.parse(readFileSync(outputPath, "utf8"));
|
|
1488
1493
|
const targetsMatch = targetEntries.every(([target, key]) => current.targets?.[target] === key);
|
|
1489
|
-
if (current.schemaVersion !== manifest.schemaVersion || current.versionSlotSchema !== manifest.versionSlotSchema || current.rustSourceHash !== manifest.rustSourceHash || !targetsMatch) {
|
|
1494
|
+
if (current.schemaVersion !== manifest.schemaVersion || current.versionSlotSchema !== manifest.versionSlotSchema || current.namespace !== manifest.namespace || current.rustSourceHash !== manifest.rustSourceHash || !targetsMatch) {
|
|
1490
1495
|
throw new Error(`${outputPath} does not match current Rust inputs`);
|
|
1491
1496
|
}
|
|
1492
1497
|
} else {
|
|
@@ -1635,7 +1640,9 @@ function fingerprintCommand(args) {
|
|
|
1635
1640
|
target: { type: "string", multiple: true },
|
|
1636
1641
|
toolchain: { type: "string", default: "stable" },
|
|
1637
1642
|
portable: { type: "boolean", default: false },
|
|
1638
|
-
source: { type: "string", multiple: true }
|
|
1643
|
+
source: { type: "string", multiple: true },
|
|
1644
|
+
"source-only": { type: "boolean", default: false },
|
|
1645
|
+
namespace: { type: "string", default: "workspace" }
|
|
1639
1646
|
},
|
|
1640
1647
|
strict: true
|
|
1641
1648
|
});
|
|
@@ -1646,7 +1653,9 @@ function fingerprintCommand(args) {
|
|
|
1646
1653
|
targets: values.target ?? [],
|
|
1647
1654
|
toolchain: values.toolchain,
|
|
1648
1655
|
portable: values.portable,
|
|
1649
|
-
sources: values.source ?? []
|
|
1656
|
+
sources: values.source ?? [],
|
|
1657
|
+
sourceOnly: values["source-only"],
|
|
1658
|
+
namespace: values.namespace
|
|
1650
1659
|
});
|
|
1651
1660
|
}
|
|
1652
1661
|
function stampCommand(args) {
|
package/tasks/rust.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { dirname, isAbsolute, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { log } from "@dbx-tools/shared-core";
|
|
6
|
+
import { log, object } from "@dbx-tools/shared-core";
|
|
7
7
|
import { readDbxToolsConfig, repoRoot } from "../src/packages.ts";
|
|
8
8
|
import {
|
|
9
9
|
discoverRustCrates,
|
|
@@ -40,7 +40,7 @@ function currentStructure(config: RustWorkspaceMapping): RustWorkspaceMapping {
|
|
|
40
40
|
const binding = recorded.get(rust);
|
|
41
41
|
return binding ? [binding] : [{ crate: "", rust }];
|
|
42
42
|
});
|
|
43
|
-
return {
|
|
43
|
+
return { ...config, crates, bindings };
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/** Whether discovered crate membership or UniFFI marker membership changed. */
|
|
@@ -87,18 +87,47 @@ function generate(binding: RustBindingMapping): void {
|
|
|
87
87
|
if (result.status !== 0) throw new Error(`binding generation exited with ${result.status}`);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
function* iterateAffectedRustBindings(
|
|
91
91
|
bindings: readonly RustBindingMapping[],
|
|
92
92
|
changed: ReadonlySet<string>,
|
|
93
|
-
): RustBindingMapping
|
|
93
|
+
): Generator<RustBindingMapping> {
|
|
94
94
|
const affected = new Set(changed);
|
|
95
|
-
const
|
|
96
|
-
for (const binding of ordered) {
|
|
95
|
+
for (const binding of orderRustBindings(bindings)) {
|
|
97
96
|
if (binding.dependencies?.some((dependency) => affected.has(dependency))) {
|
|
98
97
|
affected.add(binding.crate);
|
|
99
98
|
}
|
|
99
|
+
if (affected.has(binding.crate)) yield binding;
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function affectedRustBindings(
|
|
104
|
+
bindings: readonly RustBindingMapping[],
|
|
105
|
+
changed: ReadonlySet<string>,
|
|
106
|
+
): RustBindingMapping[] {
|
|
107
|
+
return [...iterateAffectedRustBindings(bindings, changed)];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Lazily resolve direct binding owners so lock checks stop at the first match.
|
|
112
|
+
*/
|
|
113
|
+
export function changedRustOwners(
|
|
114
|
+
config: RustWorkspaceMapping,
|
|
115
|
+
changed: readonly string[],
|
|
116
|
+
): object.Sequence<RustBindingMapping> {
|
|
117
|
+
return object
|
|
118
|
+
.sequence(changed)
|
|
119
|
+
.map((path) => ownerBinding(path, config.bindings))
|
|
120
|
+
.nonNull()
|
|
121
|
+
.distinct();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Collect direct owners, then lazily yield them and their dependents in order. */
|
|
125
|
+
export function changedRustBindings(
|
|
126
|
+
config: RustWorkspaceMapping,
|
|
127
|
+
changed: readonly string[],
|
|
128
|
+
): object.Sequence<RustBindingMapping> {
|
|
129
|
+
const targets = new Set(changedRustOwners(config, changed).map((binding) => binding.crate));
|
|
130
|
+
return object.sequence(iterateAffectedRustBindings(config.bindings, targets));
|
|
102
131
|
}
|
|
103
132
|
|
|
104
133
|
const config = rustConfig();
|
|
@@ -113,37 +142,37 @@ async function main(): Promise<void> {
|
|
|
113
142
|
return;
|
|
114
143
|
}
|
|
115
144
|
|
|
116
|
-
watchLoop(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
145
|
+
watchLoop(
|
|
146
|
+
"rust",
|
|
147
|
+
[resolve(repoRoot, config.root)],
|
|
148
|
+
(changed) => {
|
|
149
|
+
const latest = rustConfig() ?? config;
|
|
150
|
+
if (rustStructureChanged(latest)) {
|
|
151
|
+
logger.start("Rust project structure changed - re-synthesizing (+install)");
|
|
152
|
+
runSynth({ post: true });
|
|
153
|
+
logger.success("Rust project structure synchronized");
|
|
154
|
+
const refreshed = rustConfig();
|
|
155
|
+
if (!refreshed) return;
|
|
156
|
+
for (const binding of changedRustBindings(refreshed, changed)) {
|
|
157
|
+
logger.start(`generating ${binding.crate} bindings`);
|
|
158
|
+
generate(binding);
|
|
159
|
+
logger.success(`generated ${binding.crate} bindings`);
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
128
162
|
}
|
|
129
|
-
for (const binding of
|
|
163
|
+
for (const binding of changedRustBindings(latest, changed)) {
|
|
130
164
|
logger.start(`generating ${binding.crate} bindings`);
|
|
131
165
|
generate(binding);
|
|
132
166
|
logger.success(`generated ${binding.crate} bindings`);
|
|
133
167
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
logger.start(`generating ${binding.crate} bindings`);
|
|
143
|
-
generate(binding);
|
|
144
|
-
logger.success(`generated ${binding.crate} bindings`);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
check: (changed) => {
|
|
171
|
+
const latest = rustConfig() ?? config;
|
|
172
|
+
return changedRustOwners(latest, changed).some(() => true) || rustStructureChanged(latest);
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
);
|
|
147
176
|
}
|
|
148
177
|
|
|
149
178
|
if (import.meta.main) await main();
|
package/tasks/uniffi-release.mjs
CHANGED
|
@@ -227,7 +227,9 @@ const facadeDependency = (name, dependency, catalog, workspaceVersions) => {
|
|
|
227
227
|
if (dependency.startsWith("workspace:")) {
|
|
228
228
|
const version = workspaceVersions.get(name);
|
|
229
229
|
if (!version) throw new Error(`Missing workspace version for ${name}`);
|
|
230
|
-
return dependency === "workspace:*"
|
|
230
|
+
return dependency === "workspace:*"
|
|
231
|
+
? version
|
|
232
|
+
: `${dependency.slice("workspace:".length)}${version}`;
|
|
231
233
|
}
|
|
232
234
|
if (!dependency.startsWith("catalog:")) return dependency;
|
|
233
235
|
const resolved = catalog[name];
|
|
@@ -481,6 +483,8 @@ const build = () => {
|
|
|
481
483
|
...(existsSync(resolve(root, "Cargo.lock")) ? ["--locked"] : []),
|
|
482
484
|
"--package",
|
|
483
485
|
crate,
|
|
486
|
+
"--features",
|
|
487
|
+
"uniffi-bindgen",
|
|
484
488
|
"--target",
|
|
485
489
|
cargoTarget,
|
|
486
490
|
]);
|
package/tasks/uniffi.ts
CHANGED
|
@@ -119,6 +119,8 @@ if (!values["skip-build"]) {
|
|
|
119
119
|
...(existsSync(join(root, "Cargo.lock")) ? ["--locked"] : []),
|
|
120
120
|
"--package",
|
|
121
121
|
crate,
|
|
122
|
+
"--features",
|
|
123
|
+
"uniffi-bindgen",
|
|
122
124
|
...(values["cargo-target"] ? ["--target", values["cargo-target"]] : []),
|
|
123
125
|
]);
|
|
124
126
|
}
|