History

compat with legacy dir

Rhys Sullivan committed 8 months ago

Commit a802f4e1 parent ed7a3486 files · +377 −25Browse files

Showing the changes to apps (3 of 6 files). Show all

Unified · Split

3 files
  1. apps/executor/package.json +2 −1
  2. apps/executor/src/distribution/build-release.ts +137 −0
  3. apps/executor/src/distribution/portable.ts +2 −0
apps/executor/package.json+2−1
@@ -33,7 +33,8 @@ · 32 unmodified lines
33 "pack:dist": "bun src/distribution/build-package.ts && npm pack ./dist/npm",33 "pack:dist": "bun src/distribution/build-package.ts && npm pack ./dist/npm",
34 "publish:dist:dry-run": "bun src/distribution/build-package.ts && npm publish ./dist/npm --dry-run",34 "publish:dist:dry-run": "bun src/distribution/build-package.ts && npm publish ./dist/npm --dry-run",
35 "publish:dist": "bun src/distribution/build-package.ts && npm publish ./dist/npm",35 "publish:dist": "bun src/distribution/build-package.ts && npm publish ./dist/npm",
36 "build:portable": "bun src/distribution/build-portable.ts"36 "build:portable": "bun src/distribution/build-portable.ts",
37 "build:release": "bun src/distribution/build-release.ts"
37 },38 },
38 "dependencies": {39 "dependencies": {
39 "@effect/cli": "catalog:",40 "@effect/cli": "catalog:",
apps/executor/src/distribution/build-release.ts+137−0
@@ -0,0 +1,137 @@
1import { createHash } from "node:crypto";
2import { spawn } from "node:child_process";
3import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
4import { join, relative, resolve } from "node:path";
5
6import { buildDistributionPackage } from "./artifact";
7import { repoRoot } from "./metadata";
8import { buildPortableDistribution, portableTargetIds } from "./portable";
9
10const defaultReleaseDir = resolve(repoRoot, "apps/executor/dist/release");
11
12type CommandInput = {
13 command: string;
14 args: ReadonlyArray<string>;
15 cwd: string;
16};
17
18type CommandOutput = {
19 stdout: string;
20 stderr: string;
21};
22
23type PackResult = {
24 filename?: string;
25};
26
27const runCommand = async (input: CommandInput): Promise<CommandOutput> => {
28 const child = spawn(input.command, [...input.args], {
29 cwd: input.cwd,
30 env: process.env,
31 stdio: ["ignore", "pipe", "pipe"],
32 });
33
34 let stdout = "";
35 let stderr = "";
36
37 child.stdout?.setEncoding("utf8");
38 child.stdout?.on("data", (chunk) => {
39 stdout += chunk;
40 });
41
42 child.stderr?.setEncoding("utf8");
43 child.stderr?.on("data", (chunk) => {
44 stderr += chunk;
45 });
46
47 const exitCode = await new Promise<number>((resolveExitCode, reject) => {
48 child.once("error", reject);
49 child.once("close", (code) => {
50 resolveExitCode(code ?? -1);
51 });
52 });
53
54 if (exitCode !== 0) {
55 throw new Error(
56 [
57 `${input.command} ${input.args.join(" ")} exited with code ${exitCode}`,
58 stdout.trim().length > 0 ? `stdout:\n${stdout.trim()}` : null,
59 stderr.trim().length > 0 ? `stderr:\n${stderr.trim()}` : null,
60 ]
61 .filter((part) => part !== null)
62 .join("\n\n"),
63 );
64 }
65
66 return {
67 stdout: stdout.trim(),
68 stderr: stderr.trim(),
69 };
70};
71
72const computeSha256 = (contents: Uint8Array): string =>
73 createHash("sha256").update(contents).digest("hex");
74
75const createChecksumsFile = async (
76 releaseDir: string,
77 assetPaths: ReadonlyArray<string>,
78): Promise<string> => {
79 const entries = await Promise.all(
80 [...assetPaths]
81 .sort((left, right) => left.localeCompare(right))
82 .map(async (assetPath) => {
83 const contents = await readFile(assetPath);
84 const relativePath = relative(releaseDir, assetPath).replaceAll("\\", "/");
85 return `${computeSha256(contents)} ${relativePath}`;
86 }),
87 );
88
89 const checksumsPath = join(releaseDir, "checksums.txt");
90 await writeFile(checksumsPath, `${entries.join("\n")}\n`);
91 return checksumsPath;
92};
93
94const packDistributionPackage = async (releaseDir: string): Promise<string> => {
95 const output = await runCommand({
96 command: "npm",
97 args: ["pack", "./apps/executor/dist/npm", "--pack-destination", releaseDir, "--json"],
98 cwd: repoRoot,
99 });
100 const [result] = JSON.parse(output.stdout) as ReadonlyArray<PackResult>;
101 const filename = result?.filename;
102
103 if (!filename) {
104 throw new Error(`npm pack did not report an output filename. stdout:\n${output.stdout}`);
105 }
106
107 return join(releaseDir, filename);
108};
109
110const main = async () => {
111 const releaseDir = defaultReleaseDir;
112 const portableDir = join(releaseDir, "portable");
113
114 await rm(releaseDir, { recursive: true, force: true });
115 await mkdir(releaseDir, { recursive: true });
116
117 await buildDistributionPackage();
118 const packageArchivePath = await packDistributionPackage(releaseDir);
119 const portableArtifact = await buildPortableDistribution({
120 outputDir: portableDir,
121 buildWeb: false,
122 targets: portableTargetIds,
123 });
124 const portableArchivePaths = portableArtifact.artifacts
125 .map((artifact) => artifact.archivePath)
126 .filter((archivePath): archivePath is string => archivePath !== null);
127 const checksumsPath = await createChecksumsFile(releaseDir, [
128 packageArchivePath,
129 ...portableArchivePaths,
130 ]);
131
132 for (const assetPath of [packageArchivePath, ...portableArchivePaths, checksumsPath]) {
133 process.stdout.write(`${assetPath}\n`);
134 }
135};
136
137await main();
apps/executor/src/distribution/portable.ts+2−0
@@ -74,6 +74,8 @@ const portableTargets: Record<string, PortableTarget> = { · 73 unmodified lines
74 },74 },
75};75};
76 76
77export const portableTargetIds = Object.freeze(Object.keys(portableTargets));
78
77export type BuildPortableDistributionOptions = {79export type BuildPortableDistributionOptions = {
78 outputDir?: string;80 outputDir?: string;
79 packageName?: string;81 packageName?: string;