microsoft/TypeAgent

Public

mirrored fromhttps://github.com/microsoft/TypeAgentAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/fix-github-actions-build-ts

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

ts/tools/scripts/copy-better-sqlite3-node.js

150lines Ā· modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4// Save the Node.js-compatible better-sqlite3 native binary to a safe location.
5//
6// Problem: electron-builder's install-app-deps (in packages/shell postinstall)
7// rebuilds better-sqlite3 for Electron, wiping the entire build/ directory.
8// This runs in the root postinstall BEFORE electron-builder, so we save the
9// correct Node.js binary to prebuild-node/ (outside build/) where
10// electron-builder won't touch it.
11//
12// If the binary in build/Release/ is already for Electron (wrong ABI), we
13// re-download the correct Node.js prebuilt via prebuild-install.
14//
15// Works with pnpm's store layout on Windows, macOS, and Linux.
16
17const fs = require("fs");
18const path = require("path");
19const { execFileSync } = require("child_process");
20
21const expectedABI = process.versions.modules; // e.g. "127" for Node 22
22
23function isNodeCompatible(binaryPath) {
24 try {
25 process.dlopen({ exports: {} }, binaryPath);
26 return true;
27 } catch {
28 return false;
29 }
30}
31
32// Find all better-sqlite3 installations in the pnpm store
33const pnpmDir = path.resolve(__dirname, "..", "..", "node_modules", ".pnpm");
34const entries = fs
35 .readdirSync(pnpmDir)
36 .filter((e) => e.startsWith("better-sqlite3@"));
37
38if (entries.length === 0) {
39 console.error("No better-sqlite3 installations found in", pnpmDir);
40 process.exit(1);
41}
42
43let hasError = false;
44
45for (const entry of entries) {
46 const pkgDir = path.join(pnpmDir, entry, "node_modules", "better-sqlite3");
47 if (!fs.existsSync(path.join(pkgDir, "package.json"))) {
48 continue;
49 }
50
51 console.log(`\nšŸ“¦ Processing ${entry}:`);
52 console.log(" ", pkgDir);
53
54 const dstDir = path.join(pkgDir, "prebuild-node");
55 const dst = path.join(dstDir, "better_sqlite3.node");
56
57 // If prebuild-node/ already has a compatible binary, skip
58 if (fs.existsSync(dst) && isNodeCompatible(dst)) {
59 console.log(
60 "āœ… Already has compatible Node.js binary in prebuild-node/",
61 );
62 continue;
63 }
64
65 const releaseBinary = path.join(
66 pkgDir,
67 "build",
68 "Release",
69 "better_sqlite3.node",
70 );
71
72 // If build/Release/ has a compatible Node.js binary, just copy it
73 if (fs.existsSync(releaseBinary) && isNodeCompatible(releaseBinary)) {
74 fs.mkdirSync(dstDir, { recursive: true });
75 fs.copyFileSync(releaseBinary, dst);
76 console.log("āœ… Copied compatible binary from build/Release/");
77 console.log(" → ", dst);
78 continue;
79 }
80
81 // Binary is missing or wrong ABI (e.g. Electron) — re-download for Node.js
82 console.log(
83 "ā¬‡ļø Downloading Node.js-compatible prebuilt via prebuild-install...",
84 );
85 const tempBuildDir = path.join(pkgDir, "build-node-temp");
86 try {
87 // prebuild-install writes to build/Release/, so use a temp dir
88 // to avoid disturbing any existing Electron binary
89 fs.rmSync(tempBuildDir, { recursive: true, force: true });
90 const origBuild = path.join(pkgDir, "build");
91 const hasBuild = fs.existsSync(origBuild);
92 if (hasBuild) {
93 fs.renameSync(origBuild, tempBuildDir);
94 }
95 try {
96 execFileSync(
97 process.execPath,
98 [
99 require.resolve("prebuild-install/bin"),
100 "--runtime",
101 "node",
102 "--target",
103 process.version,
104 ],
105 {
106 cwd: pkgDir,
107 stdio: "inherit",
108 },
109 );
110
111 const downloaded = path.join(
112 pkgDir,
113 "build",
114 "Release",
115 "better_sqlite3.node",
116 );
117 if (!fs.existsSync(downloaded)) {
118 throw new Error("prebuild-install did not produce a binary");
119 }
120
121 fs.mkdirSync(dstDir, { recursive: true });
122 fs.copyFileSync(downloaded, dst);
123 console.log("āœ… Node.js binary saved to prebuild-node/");
124
125 // Remove the temp build dir created by prebuild-install
126 fs.rmSync(path.join(pkgDir, "build"), {
127 recursive: true,
128 force: true,
129 });
130 } finally {
131 // Restore original build dir (may contain Electron binary)
132 if (hasBuild) {
133 if (!fs.existsSync(origBuild)) {
134 fs.renameSync(tempBuildDir, origBuild);
135 } else {
136 fs.rmSync(tempBuildDir, { recursive: true, force: true });
137 }
138 }
139 }
140 } catch (e) {
141 console.error(`āŒ Failed for ${entry}:`, e.message);
142 fs.rmSync(tempBuildDir, { recursive: true, force: true });
143 hasError = true;
144 continue;
145 }
146}
147
148if (hasError) {
149 process.exit(1);
150}
151