@dbx-tools/projen 0.6.163 → 0.6.174
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 +56 -41
- package/index.ts +2 -1
- package/package.json +4 -5
- package/src/barrels.ts +134 -34
- package/src/project-js.ts +19 -22
- package/src/project-py.ts +83 -21
- package/src/project-rs.ts +175 -309
- package/src/release.ts +109 -4
- package/src/uniffi.ts +45 -0
- package/tasks/bump.ts +12 -2
- package/tasks/publish-uniffi-local.ts +3 -4
- package/tasks/publish.ts +22 -13
- package/tasks/rust.ts +17 -3
- package/tasks/uniffi-release.mjs +242 -29
- package/tasks/uniffi.ts +101 -55
package/src/release.ts
CHANGED
|
@@ -6,11 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, rmSync } from "node:fs";
|
|
8
8
|
import { resolve } from "node:path";
|
|
9
|
+
import { object } from "@dbx-tools/shared-core";
|
|
9
10
|
import { Component, YamlFile } from "projen";
|
|
10
11
|
import { GithubWorkflow } from "projen/lib/github";
|
|
11
12
|
import { JobPermission, type JobStep } from "projen/lib/github/workflows-model";
|
|
12
|
-
import { object } from "@dbx-tools/shared-core";
|
|
13
13
|
import { BUN_VERSION, bunCacheRestoreSteps, bunCacheSaveStep } from "./bun-workflow.ts";
|
|
14
|
+
import {
|
|
15
|
+
orderRustBindings,
|
|
16
|
+
type RustBindingMapping,
|
|
17
|
+
type RustWorkspaceMapping,
|
|
18
|
+
} from "./project-rs.ts";
|
|
14
19
|
import { applyTasks, taskScript, type DBXToolsNodeProject } from "./project.ts";
|
|
15
20
|
import {
|
|
16
21
|
DOWNSTREAM_RELEASE_EVENT,
|
|
@@ -70,6 +75,7 @@ interface PublishWorkflow {
|
|
|
70
75
|
readonly steps: readonly JobStep[];
|
|
71
76
|
readonly workingDirectory?: string;
|
|
72
77
|
readonly upstreamWorkflow?: string;
|
|
78
|
+
readonly rustArtifacts?: boolean;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
/** Shared checkout and toolchain setup for every npm publish workflow. */
|
|
@@ -300,7 +306,7 @@ export class DBXToolsRelease extends Component {
|
|
|
300
306
|
/** Author the common tag trigger, concurrency policy, permissions, and publish job. */
|
|
301
307
|
private authorPublishWorkflow(
|
|
302
308
|
project: DBXToolsNodeProject,
|
|
303
|
-
{ name, tagPrefix, steps, workingDirectory, upstreamWorkflow }: PublishWorkflow,
|
|
309
|
+
{ name, tagPrefix, steps, workingDirectory, upstreamWorkflow, rustArtifacts }: PublishWorkflow,
|
|
304
310
|
): void {
|
|
305
311
|
const setupSteps = publishSetupSteps(project);
|
|
306
312
|
const branchDispatch = upstreamWorkflow === undefined;
|
|
@@ -314,7 +320,7 @@ export class DBXToolsRelease extends Component {
|
|
|
314
320
|
// the publish job below overrides it with the `id-token` it needs.
|
|
315
321
|
workflow.file?.addOverride("permissions", {
|
|
316
322
|
contents: "read",
|
|
317
|
-
...(upstreamWorkflow ? { actions: "read" } : {}),
|
|
323
|
+
...(upstreamWorkflow || rustArtifacts ? { actions: "read" } : {}),
|
|
318
324
|
});
|
|
319
325
|
if (upstreamWorkflow) {
|
|
320
326
|
workflow.file?.addOverride("on.workflow_run", {
|
|
@@ -362,7 +368,7 @@ export class DBXToolsRelease extends Component {
|
|
|
362
368
|
runsOn: ["ubuntu-latest"],
|
|
363
369
|
// `id-token: write` lets npm mint the OIDC token for provenance attestation.
|
|
364
370
|
permissions: {
|
|
365
|
-
...(upstreamWorkflow ? { actions: JobPermission.READ } : {}),
|
|
371
|
+
...(upstreamWorkflow || rustArtifacts ? { actions: JobPermission.READ } : {}),
|
|
366
372
|
contents: JobPermission.READ,
|
|
367
373
|
idToken: JobPermission.WRITE,
|
|
368
374
|
},
|
|
@@ -483,14 +489,112 @@ export class DBXToolsRelease extends Component {
|
|
|
483
489
|
* version on every package first makes the pushed tag the published version
|
|
484
490
|
* (no bump math).
|
|
485
491
|
*/
|
|
492
|
+
private nodeBindingReleaseSteps(project: DBXToolsNodeProject): {
|
|
493
|
+
before: JobStep[];
|
|
494
|
+
after: JobStep[];
|
|
495
|
+
} {
|
|
496
|
+
const config = project.dbxToolsConfig.rust;
|
|
497
|
+
if (!object.isRecord(config) || !Array.isArray(config.bindings)) {
|
|
498
|
+
return { before: [], after: [] };
|
|
499
|
+
}
|
|
500
|
+
const bindings = orderRustBindings(config.bindings as RustWorkspaceMapping["bindings"]).filter(
|
|
501
|
+
(binding): binding is RustBindingMapping & { node: string; nodePackage: string } =>
|
|
502
|
+
Boolean(binding.node && binding.nodePackage),
|
|
503
|
+
);
|
|
504
|
+
if (bindings.length === 0) return { before: [], after: [] };
|
|
505
|
+
|
|
506
|
+
const before: JobStep[] = [
|
|
507
|
+
{
|
|
508
|
+
name: "Require Rust artifact handoff",
|
|
509
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
510
|
+
shell: "bash",
|
|
511
|
+
env: {
|
|
512
|
+
RUST_RUN_ID: "${{ github.event.client_payload.rust_run_id }}",
|
|
513
|
+
RUST_RUN_ATTEMPT: "${{ github.event.client_payload.rust_run_attempt }}",
|
|
514
|
+
},
|
|
515
|
+
run: ['test -n "$RUST_RUN_ID"', 'test -n "$RUST_RUN_ATTEMPT"'].join("\n"),
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: "Download native npm packages",
|
|
519
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
520
|
+
uses: "actions/download-artifact@v8",
|
|
521
|
+
with: {
|
|
522
|
+
pattern: "*-npm",
|
|
523
|
+
path: "dist/uniffi/native",
|
|
524
|
+
"merge-multiple": true,
|
|
525
|
+
"run-id": "${{ github.event.client_payload.rust_run_id }}",
|
|
526
|
+
"github-token": "${{ github.token }}",
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: "Publish native npm packages",
|
|
531
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
532
|
+
env: {
|
|
533
|
+
NPM_CONFIG_PROVENANCE: "true",
|
|
534
|
+
NPM_CONFIG_TOKEN: "${{ secrets.NPM_TOKEN }}",
|
|
535
|
+
NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
|
|
536
|
+
},
|
|
537
|
+
run: [
|
|
538
|
+
"test \"$(find dist/uniffi/native -name '*.tgz' | wc -l | tr -d ' ')\" -gt 0",
|
|
539
|
+
'for package in dist/uniffi/native/*.tgz; do npm publish "$package" --access public; done',
|
|
540
|
+
].join("\n"),
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
name: "Refresh workspace after native publication",
|
|
544
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
545
|
+
run: "bun install --force",
|
|
546
|
+
},
|
|
547
|
+
];
|
|
548
|
+
|
|
549
|
+
const facadeCommands = [
|
|
550
|
+
'if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then',
|
|
551
|
+
' VERSION="0.0.0-dry.${GITHUB_RUN_NUMBER}"',
|
|
552
|
+
" DRY_RUN=--dry-run",
|
|
553
|
+
"else",
|
|
554
|
+
' VERSION="$RELEASE_VERSION"',
|
|
555
|
+
" DRY_RUN=",
|
|
556
|
+
"fi",
|
|
557
|
+
...bindings.flatMap((binding) => {
|
|
558
|
+
const output = `dist/uniffi/facades/${binding.crate}`;
|
|
559
|
+
return [
|
|
560
|
+
`NATIVE_ARG=""`,
|
|
561
|
+
'if [ "$GITHUB_EVENT_NAME" = "repository_dispatch" ]; then',
|
|
562
|
+
` NATIVE_PACKAGE="$(find dist/uniffi/native -name '${binding.crate}-linux-x64-gnu-*.tgz' -print -quit)"`,
|
|
563
|
+
' test -n "$NATIVE_PACKAGE"',
|
|
564
|
+
' NATIVE_ARG="--native-package $NATIVE_PACKAGE"',
|
|
565
|
+
"fi",
|
|
566
|
+
`node .projen/uniffi-release.mjs facade --node "${binding.node}" --node-package "${binding.nodePackage}" --node-triple "linux-x64-gnu" --version "$VERSION" --output "${output}" $NATIVE_ARG`,
|
|
567
|
+
`for package in ${output}/npm-facade/*.tgz; do npm publish "$package" --access public $DRY_RUN; done`,
|
|
568
|
+
];
|
|
569
|
+
}),
|
|
570
|
+
];
|
|
571
|
+
return {
|
|
572
|
+
before,
|
|
573
|
+
after: [
|
|
574
|
+
{
|
|
575
|
+
name: "Build and publish UniFFI npm facades",
|
|
576
|
+
env: {
|
|
577
|
+
NPM_CONFIG_PROVENANCE: "true",
|
|
578
|
+
NPM_CONFIG_TOKEN: "${{ secrets.NPM_TOKEN }}",
|
|
579
|
+
NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
|
|
580
|
+
},
|
|
581
|
+
run: facadeCommands.join("\n"),
|
|
582
|
+
},
|
|
583
|
+
],
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
486
587
|
private authorReleaseWorkflow(project: DBXToolsNodeProject): void {
|
|
487
588
|
if (!this.workflowName) return;
|
|
488
589
|
if (this.workflowName !== "release") project.tryRemoveFile(".github/workflows/release.yml");
|
|
590
|
+
const bindingSteps = this.nodeBindingReleaseSteps(project);
|
|
489
591
|
this.authorPublishWorkflow(project, {
|
|
490
592
|
name: this.workflowName,
|
|
491
593
|
tagPrefix: this.tagPrefix,
|
|
492
594
|
upstreamWorkflow: this.upstreamWorkflow,
|
|
595
|
+
rustArtifacts: bindingSteps.before.length > 0,
|
|
493
596
|
steps: [
|
|
597
|
+
...bindingSteps.before,
|
|
494
598
|
// The pushed tag is the version: `<prefix>1.2.3` -> `1.2.3`. Stamp it on
|
|
495
599
|
// every workspace package (manifests are projen-readonly, so unlock
|
|
496
600
|
// first), rewriting `workspace:*` sibling deps to `^<version>` so the
|
|
@@ -512,6 +616,7 @@ export class DBXToolsRelease extends Component {
|
|
|
512
616
|
NPM_CONFIG_PROVENANCE: "true",
|
|
513
617
|
},
|
|
514
618
|
},
|
|
619
|
+
...bindingSteps.after,
|
|
515
620
|
],
|
|
516
621
|
});
|
|
517
622
|
}
|
package/src/uniffi.ts
CHANGED
|
@@ -36,6 +36,14 @@ export interface TypeScriptBindingModule {
|
|
|
36
36
|
readonly source: string;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/** Add source extensions to UBRN's generated relative binding imports. */
|
|
40
|
+
export const addTypeScriptExtensionsToBindingImports = (source: string): string =>
|
|
41
|
+
source.replace(
|
|
42
|
+
/(["'])\.\/_bindings(-ffi)?\1/g,
|
|
43
|
+
(_specifier, quote: string, suffix: string | undefined) =>
|
|
44
|
+
`${quote}./_bindings${suffix ?? ""}.ts${quote}`,
|
|
45
|
+
);
|
|
46
|
+
|
|
39
47
|
/** Add explicit type exports for interfaces that TypeScript misses through UBRN's star exports. */
|
|
40
48
|
export const addExplicitInterfaceReexports = (
|
|
41
49
|
facade: string,
|
|
@@ -48,3 +56,40 @@ export const addExplicitInterfaceReexports = (
|
|
|
48
56
|
if (exports.length === 0) return facade;
|
|
49
57
|
return `${facade.trimEnd()}\n${exports.join("\n")}\n`;
|
|
50
58
|
};
|
|
59
|
+
|
|
60
|
+
const GENERATED_BINDINGS_HEADER = "GENERATED by UniFFI binding generation";
|
|
61
|
+
|
|
62
|
+
function pythonAllNames(source: string, file: string): string[] {
|
|
63
|
+
const body = /^__all__\s*=\s*\[([\s\S]*?)\]/m.exec(source)?.[1];
|
|
64
|
+
if (body === undefined) {
|
|
65
|
+
throw new Error(`Python exports must define a literal __all__ list: ${file}`);
|
|
66
|
+
}
|
|
67
|
+
return [...body.matchAll(/["']([^"']+)["']/g)].map((match) => match[1]!);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Generate one package root from the binding module's explicit exports. */
|
|
71
|
+
export function mergePythonBindingExports(
|
|
72
|
+
initSource: string,
|
|
73
|
+
bindingsSource: string,
|
|
74
|
+
options: { readonly crate: string; readonly file: string },
|
|
75
|
+
): string {
|
|
76
|
+
if (initSource.trim() && !initSource.includes(GENERATED_BINDINGS_HEADER)) {
|
|
77
|
+
throw new Error(`Cannot replace non-generated Python package exports: ${options.file}`);
|
|
78
|
+
}
|
|
79
|
+
const bindingNames = pythonAllNames(bindingsSource, options.file);
|
|
80
|
+
const publicNames = [...bindingNames].sort((left, right) =>
|
|
81
|
+
left < right ? -1 : left > right ? 1 : 0,
|
|
82
|
+
);
|
|
83
|
+
return [
|
|
84
|
+
"# GENERATED by UniFFI binding generation - DO NOT EDIT.",
|
|
85
|
+
`# Regenerated from the ${options.crate} Rust exports.`,
|
|
86
|
+
"# Hand edits are overwritten on the next watch; this file is read-only.",
|
|
87
|
+
"",
|
|
88
|
+
"from .bindings import *",
|
|
89
|
+
"",
|
|
90
|
+
"__all__ = [",
|
|
91
|
+
...publicNames.map((name) => ` ${JSON.stringify(name)},`),
|
|
92
|
+
"]",
|
|
93
|
+
"",
|
|
94
|
+
].join("\n");
|
|
95
|
+
}
|
package/tasks/bump.ts
CHANGED
|
@@ -135,8 +135,8 @@ function assertReleaseTagsPointToHead(tags: readonly string[]): void {
|
|
|
135
135
|
* (not-yet-published) version into the COMMITTED manifest breaks the release
|
|
136
136
|
* workflow's initial `bun install`, which checks out that commit before anything
|
|
137
137
|
* is published. Sibling versions are resolved transiently at publish time instead:
|
|
138
|
-
*
|
|
139
|
-
*
|
|
138
|
+
* The bump stamps every workspace member before committing so independently
|
|
139
|
+
* synthesized members and the Bun lock resolve the same release version.
|
|
140
140
|
*/
|
|
141
141
|
function writeManifestVersion(pkgPath: string, version: string): void {
|
|
142
142
|
const { mode } = statSync(pkgPath);
|
|
@@ -306,6 +306,16 @@ program
|
|
|
306
306
|
},
|
|
307
307
|
});
|
|
308
308
|
}
|
|
309
|
+
if (opts.version) {
|
|
310
|
+
const publishScript = fileURLToPath(new URL("./publish.ts", import.meta.url));
|
|
311
|
+
exec.spawnSync("bun", [publishScript, version, "--stamp-only"], {
|
|
312
|
+
cwd: process.cwd(),
|
|
313
|
+
stdout: "inherit",
|
|
314
|
+
stderr: "inherit",
|
|
315
|
+
stdin: "ignore",
|
|
316
|
+
check: true,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
309
319
|
|
|
310
320
|
if (opts.commit) {
|
|
311
321
|
// Stage the whole tree so the release commit captures the version bump
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env -S bun
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
2
3
|
import { chmodSync, existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { arch, platform } from "node:os";
|
|
4
5
|
import { dirname, join, resolve } from "node:path";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { parseArgs } from "node:util";
|
|
7
|
-
import { spawnSync } from "node:child_process";
|
|
8
8
|
import { readDbxToolsConfig, repoRoot } from "../src/packages.ts";
|
|
9
9
|
import type { RustBindingMapping, RustWorkspaceMapping } from "../src/project-rs.ts";
|
|
10
10
|
|
|
@@ -155,8 +155,6 @@ function buildAndPublish(binding: RustBindingMapping, version: string): void {
|
|
|
155
155
|
includePython ? binding.python! : "",
|
|
156
156
|
"--node-package",
|
|
157
157
|
includeNode ? binding.nodePackage! : "",
|
|
158
|
-
"--node-generator",
|
|
159
|
-
"projen/tasks/uniffi.ts",
|
|
160
158
|
"--python-package",
|
|
161
159
|
includePython ? binding.pythonPackage! : "",
|
|
162
160
|
"--cargo-target",
|
|
@@ -184,8 +182,9 @@ function buildAndPublish(binding: RustBindingMapping, version: string): void {
|
|
|
184
182
|
...artifacts(join(output, "npm"), ".tgz"),
|
|
185
183
|
...artifacts(join(output, "npm-facade"), ".tgz"),
|
|
186
184
|
];
|
|
187
|
-
for (const packageFile of packages)
|
|
185
|
+
for (const packageFile of packages) {
|
|
188
186
|
run("npm", ["publish", packageFile, "--registry", registry!]);
|
|
187
|
+
}
|
|
189
188
|
}
|
|
190
189
|
if (includePython) {
|
|
191
190
|
const wheels = artifacts(join(output, "python"), ".whl");
|
package/tasks/publish.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* `bun tasks/publish.ts <version> [--registry <url>] [--exclude <dir>] [--dry-run]`
|
|
4
4
|
* - ensure every workspace member and the Bun lock carry the release version,
|
|
5
|
-
* then publish each
|
|
5
|
+
* then publish each package owned by the standard Node release with `bun publish`.
|
|
6
6
|
*
|
|
7
7
|
* Bun has no `pnpm -r publish`, so this loop is the recursive-publish stand-in.
|
|
8
8
|
* It leans on native bun for everything bun already does:
|
|
@@ -41,8 +41,7 @@
|
|
|
41
41
|
* but uploads nothing, so the `release` workflow is testable end-to-end via a
|
|
42
42
|
* `workflow_dispatch` run without anything reaching npm. `--registry` targets a
|
|
43
43
|
* non-default registry (a local verdaccio); `--exclude <dir>` (repeatable,
|
|
44
|
-
* repo-relative) skips a member
|
|
45
|
-
* `projen`, published by `projen-release`, not the main `release`).
|
|
44
|
+
* repo-relative) skips a member owned by another publication flow.
|
|
46
45
|
*
|
|
47
46
|
* `--no-restore` keeps the edits on disk instead of undoing them at exit. Only
|
|
48
47
|
* needed when a LATER process must still see them - `--stamp-only` implies it,
|
|
@@ -140,7 +139,8 @@ function lockfileMatchesVersion(
|
|
|
140
139
|
|
|
141
140
|
/** Spawn `command` in `cwd` with `PATH` overridden, failing the task on non-zero. */
|
|
142
141
|
function run(cwd: string, command: string, args: string[], path: string): void {
|
|
143
|
-
|
|
142
|
+
const executable = command === "bun" && process.versions.bun ? process.execPath : command;
|
|
143
|
+
exec.spawnSync(executable, args, {
|
|
144
144
|
cwd,
|
|
145
145
|
stdout: "inherit",
|
|
146
146
|
stderr: "inherit",
|
|
@@ -152,7 +152,8 @@ function run(cwd: string, command: string, args: string[], path: string): void {
|
|
|
152
152
|
|
|
153
153
|
/** Asynchronous counterpart used for bounded parallel stamping and publishing. */
|
|
154
154
|
async function runAsync(cwd: string, command: string, args: string[], path: string): Promise<void> {
|
|
155
|
-
|
|
155
|
+
const executable = command === "bun" && process.versions.bun ? process.execPath : command;
|
|
156
|
+
await exec.spawn(executable, args, {
|
|
156
157
|
cwd,
|
|
157
158
|
stdout: "inherit",
|
|
158
159
|
stderr: "inherit",
|
|
@@ -274,9 +275,8 @@ if (!Number.isInteger(parsedConcurrency) || parsedConcurrency < 1) {
|
|
|
274
275
|
}
|
|
275
276
|
const concurrency = parsedConcurrency;
|
|
276
277
|
// `--stamp-only`: set versions + refresh the lockfile, then STOP (no publish).
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
// to the release version; publishing every member here would double-publish them.
|
|
278
|
+
// A separate package command can use this when its own publish process needs
|
|
279
|
+
// workspace sibling versions resolved before it starts.
|
|
280
280
|
const stampOnly = rest.includes("--stamp-only");
|
|
281
281
|
// Undo the manifest edits at exit unless a later process still needs them. Implied
|
|
282
282
|
// off by `--stamp-only`, whose stamps exist precisely for a subsequent `bun publish`.
|
|
@@ -338,17 +338,17 @@ for (const dir of members) {
|
|
|
338
338
|
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as {
|
|
339
339
|
name?: string;
|
|
340
340
|
private?: boolean;
|
|
341
|
+
dbxToolsConfig?: { uniffi?: boolean };
|
|
341
342
|
scripts?: Record<string, string>;
|
|
342
343
|
};
|
|
343
344
|
if (pkg.private) {
|
|
344
345
|
logger.info(`skip private ${pkg.name ?? dirname(dir)}`);
|
|
345
346
|
continue;
|
|
346
347
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
applyPublishConfig(manifestPath);
|
|
348
|
+
if (pkg.dbxToolsConfig?.uniffi === true) {
|
|
349
|
+
logger.info(`skip UniFFI ${pkg.name ?? dirname(dir)}`);
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
352
|
publishable.push({
|
|
353
353
|
dir,
|
|
354
354
|
name: pkg.name ?? dirname(dir),
|
|
@@ -362,6 +362,15 @@ if (compiled.length > 0) {
|
|
|
362
362
|
run(root, "bun", ["run", ...compiled.flatMap((pkg) => ["--filter", pkg.name]), "compile"], path);
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
// Compile against workspace source exports first. Switching manifests to their
|
|
366
|
+
// publishConfig entries before compilation makes consumers resolve sibling
|
|
367
|
+
// `lib/*.d.ts` files that have not been emitted yet in a clean checkout.
|
|
368
|
+
for (const { dir } of publishable) {
|
|
369
|
+
const manifestPath = join(dir, "package.json");
|
|
370
|
+
unlockManifest(manifestPath);
|
|
371
|
+
applyPublishConfig(manifestPath);
|
|
372
|
+
}
|
|
373
|
+
|
|
365
374
|
logger.info(
|
|
366
375
|
`${dryRun ? "dry-run packing" : "publishing"} ${publishable.length} packages with concurrency ${concurrency}`,
|
|
367
376
|
);
|
package/tasks/rust.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { readDbxToolsConfig, repoRoot } from "../src/packages.ts";
|
|
|
8
8
|
import {
|
|
9
9
|
discoverRustCrates,
|
|
10
10
|
hasUniFFIBindings,
|
|
11
|
+
orderRustBindings,
|
|
11
12
|
type RustBindingMapping,
|
|
12
13
|
type RustWorkspaceMapping,
|
|
13
14
|
} from "../src/project-rs.ts";
|
|
@@ -84,6 +85,19 @@ function generate(binding: RustBindingMapping): void {
|
|
|
84
85
|
if (result.status !== 0) throw new Error(`binding generation exited with ${result.status}`);
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
export function affectedRustBindings(
|
|
89
|
+
bindings: readonly RustBindingMapping[],
|
|
90
|
+
changed: ReadonlySet<string>,
|
|
91
|
+
): RustBindingMapping[] {
|
|
92
|
+
const affected = new Set(changed);
|
|
93
|
+
const ordered = orderRustBindings(bindings);
|
|
94
|
+
for (const binding of ordered) {
|
|
95
|
+
if (binding.dependencies?.some((dependency) => affected.has(dependency)))
|
|
96
|
+
affected.add(binding.crate);
|
|
97
|
+
}
|
|
98
|
+
return ordered.filter((binding) => affected.has(binding.crate));
|
|
99
|
+
}
|
|
100
|
+
|
|
87
101
|
const config = rustConfig();
|
|
88
102
|
|
|
89
103
|
async function main(): Promise<void> {
|
|
@@ -92,7 +106,7 @@ async function main(): Promise<void> {
|
|
|
92
106
|
throw new Error("Cargo is required because Rust projects were detected");
|
|
93
107
|
}
|
|
94
108
|
if (!process.argv.includes("--watch")) {
|
|
95
|
-
for (const binding of config.bindings) generate(binding);
|
|
109
|
+
for (const binding of orderRustBindings(config.bindings)) generate(binding);
|
|
96
110
|
return;
|
|
97
111
|
}
|
|
98
112
|
|
|
@@ -109,7 +123,7 @@ async function main(): Promise<void> {
|
|
|
109
123
|
const binding = ownerBinding(path, refreshed.bindings);
|
|
110
124
|
if (binding) targets.set(binding.crate, binding);
|
|
111
125
|
}
|
|
112
|
-
for (const binding of targets.
|
|
126
|
+
for (const binding of affectedRustBindings(refreshed.bindings, new Set(targets.keys()))) {
|
|
113
127
|
logger.start(`generating ${binding.crate} bindings`);
|
|
114
128
|
generate(binding);
|
|
115
129
|
logger.success(`generated ${binding.crate} bindings`);
|
|
@@ -121,7 +135,7 @@ async function main(): Promise<void> {
|
|
|
121
135
|
const binding = ownerBinding(path, latest.bindings);
|
|
122
136
|
if (binding) targets.set(binding.crate, binding);
|
|
123
137
|
}
|
|
124
|
-
for (const binding of targets.
|
|
138
|
+
for (const binding of affectedRustBindings(latest.bindings, new Set(targets.keys()))) {
|
|
125
139
|
logger.start(`generating ${binding.crate} bindings`);
|
|
126
140
|
generate(binding);
|
|
127
141
|
logger.success(`generated ${binding.crate} bindings`);
|