Skip to content
File

Blob: scripts/litmus/setup.ts

typescript85 lines
1import { access, cp, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2import { constants } from "node:fs";
3import os from "node:os";
4import path from "node:path";
5import { spawn } from "node:child_process";
6 
7const repoRoot = path.resolve(import.meta.dirname, "../..");
8const litmusDir = path.join(repoRoot, "vendor", "litmus");
9const binaryPath = path.join(litmusDir, "litmus");
10const releaseVersion = "0.17";
11const releaseUrl = `https://notroj.github.io/litmus/litmus-${releaseVersion}.tar.gz`;
12 
13async function exists(filePath: string): Promise<boolean> {
14 try {
15 await access(filePath, constants.F_OK);
16 return true;
17 } catch {
18 return false;
19 }
20}
21 
22function run(command: string, args: string[], cwd: string): Promise<void> {
23 return new Promise((resolve, reject) => {
24 const child = spawn(command, args, { cwd, stdio: "inherit" });
25 child.on("error", reject);
26 child.on("exit", (code) => {
27 if (code === 0) resolve();
28 else reject(new Error(`${command} ${args.join(" ")} exited with ${code}`));
29 });
30 });
31}
32 
33async function downloadReleaseTarball(): Promise<void> {
34 const tempDir = await mkdtemp(path.join(os.tmpdir(), "dab-litmus-setup-"));
35 try {
36 const archivePath = path.join(tempDir, `litmus-${releaseVersion}.tar.gz`);
37 const extractedDir = path.join(tempDir, `litmus-${releaseVersion}`);
38 
39 const response = await fetch(releaseUrl);
40 if (!response.ok) throw new Error(`Unable to download ${releaseUrl}: ${response.status}`);
41 const body = await response.arrayBuffer();
42 await writeFile(archivePath, new Uint8Array(body));
43 await run("tar", ["-xzf", archivePath, "-C", tempDir], repoRoot);
44 await rm(litmusDir, { recursive: true, force: true });
45 await mkdir(path.dirname(litmusDir), { recursive: true });
46 await cp(extractedDir, litmusDir, { recursive: true });
47 } finally {
48 await rm(tempDir, { recursive: true, force: true });
49 }
50}
51 
52async function main(): Promise<void> {
53 if (await exists(binaryPath)) {
54 console.log(binaryPath);
55 return;
56 }
57 
58 await mkdir(path.dirname(litmusDir), { recursive: true });
59 if (!(await exists(litmusDir))) {
60 await downloadReleaseTarball();
61 }
62 
63 if (!(await exists(path.join(litmusDir, "configure")))) {
64 await downloadReleaseTarball();
65 }
66 if (await exists(path.join(litmusDir, "configure"))) {
67 await run("./configure", [], litmusDir);
68 }
69 await run("make", [], litmusDir);
70 
71 if (!(await exists(binaryPath))) {
72 throw new Error("litmus build completed, but vendor/litmus/litmus was not found");
73 }
74 
75 console.log(binaryPath);
76}
77 
78main().catch((error) => {
79 console.error(
80 "Unable to build litmus. Install git, make, a C compiler, autoconf/automake, and neon development headers.",
81 );
82 console.error(error instanceof Error ? error.message : String(error));
83 process.exit(1);
84});