install.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. var __defProp = Object.defineProperty;
  2. var __defProps = Object.defineProperties;
  3. var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
  4. var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  5. var __hasOwnProp = Object.prototype.hasOwnProperty;
  6. var __propIsEnum = Object.prototype.propertyIsEnumerable;
  7. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  8. var __spreadValues = (a, b) => {
  9. for (var prop in b || (b = {}))
  10. if (__hasOwnProp.call(b, prop))
  11. __defNormalProp(a, prop, b[prop]);
  12. if (__getOwnPropSymbols)
  13. for (var prop of __getOwnPropSymbols(b)) {
  14. if (__propIsEnum.call(b, prop))
  15. __defNormalProp(a, prop, b[prop]);
  16. }
  17. return a;
  18. };
  19. var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
  20. const fs = require("fs");
  21. const os = require("os");
  22. const path = require("path");
  23. const zlib = require("zlib");
  24. const https = require("https");
  25. const child_process = require("child_process");
  26. const version = "0.12.25";
  27. const binPath = path.join(__dirname, "bin", "esbuild");
  28. async function installBinaryFromPackage(name, fromPath, toPath) {
  29. const cachePath = getCachePath(name);
  30. try {
  31. fs.copyFileSync(cachePath, toPath);
  32. fs.chmodSync(toPath, 493);
  33. validateBinaryVersion(toPath);
  34. const now = new Date();
  35. fs.utimesSync(cachePath, now, now);
  36. return;
  37. } catch (e) {
  38. }
  39. let buffer;
  40. let didFail = false;
  41. try {
  42. buffer = installUsingNPM(name, fromPath);
  43. } catch (err) {
  44. didFail = true;
  45. console.error(`Trying to install "${name}" using npm`);
  46. console.error(`Failed to install "${name}" using npm: ${err && err.message || err}`);
  47. }
  48. if (!buffer) {
  49. const url = `https://registry.npmjs.org/${name}/-/${name}-${version}.tgz`;
  50. console.error(`Trying to download ${JSON.stringify(url)}`);
  51. try {
  52. buffer = extractFileFromTarGzip(await fetch(url), fromPath);
  53. } catch (err) {
  54. console.error(`Failed to download ${JSON.stringify(url)}: ${err && err.message || err}`);
  55. }
  56. }
  57. if (!buffer) {
  58. console.error(`Install unsuccessful`);
  59. process.exit(1);
  60. }
  61. fs.writeFileSync(toPath, buffer, { mode: 493 });
  62. try {
  63. validateBinaryVersion(toPath);
  64. } catch (err) {
  65. console.error(`The version of the downloaded binary is incorrect: ${err && err.message || err}`);
  66. console.error(`Install unsuccessful`);
  67. process.exit(1);
  68. }
  69. try {
  70. fs.mkdirSync(path.dirname(cachePath), {
  71. recursive: true,
  72. mode: 448
  73. });
  74. fs.copyFileSync(toPath, cachePath);
  75. cleanCacheLRU(cachePath);
  76. } catch (e) {
  77. }
  78. if (didFail)
  79. console.error(`Install successful`);
  80. }
  81. function validateBinaryVersion(binaryPath) {
  82. const stdout = child_process.execFileSync(binaryPath, ["--version"]).toString().trim();
  83. if (stdout !== version) {
  84. throw new Error(`Expected ${JSON.stringify(version)} but got ${JSON.stringify(stdout)}`);
  85. }
  86. }
  87. function getCachePath(name) {
  88. const home = os.homedir();
  89. const common = ["esbuild", "bin", `${name}@${version}`];
  90. if (process.platform === "darwin")
  91. return path.join(home, "Library", "Caches", ...common);
  92. if (process.platform === "win32")
  93. return path.join(home, "AppData", "Local", "Cache", ...common);
  94. const XDG_CACHE_HOME = process.env.XDG_CACHE_HOME;
  95. if (process.platform === "linux" && XDG_CACHE_HOME && path.isAbsolute(XDG_CACHE_HOME))
  96. return path.join(XDG_CACHE_HOME, ...common);
  97. return path.join(home, ".cache", ...common);
  98. }
  99. function cleanCacheLRU(fileToKeep) {
  100. const dir = path.dirname(fileToKeep);
  101. const entries = [];
  102. for (const entry of fs.readdirSync(dir)) {
  103. const entryPath = path.join(dir, entry);
  104. try {
  105. const stats = fs.statSync(entryPath);
  106. entries.push({ path: entryPath, mtime: stats.mtime });
  107. } catch (e) {
  108. }
  109. }
  110. entries.sort((a, b) => +b.mtime - +a.mtime);
  111. for (const entry of entries.slice(5)) {
  112. try {
  113. fs.unlinkSync(entry.path);
  114. } catch (e) {
  115. }
  116. }
  117. }
  118. function fetch(url) {
  119. return new Promise((resolve, reject) => {
  120. https.get(url, (res) => {
  121. if ((res.statusCode === 301 || res.statusCode === 302) && res.headers.location)
  122. return fetch(res.headers.location).then(resolve, reject);
  123. if (res.statusCode !== 200)
  124. return reject(new Error(`Server responded with ${res.statusCode}`));
  125. let chunks = [];
  126. res.on("data", (chunk) => chunks.push(chunk));
  127. res.on("end", () => resolve(Buffer.concat(chunks)));
  128. }).on("error", reject);
  129. });
  130. }
  131. function extractFileFromTarGzip(buffer, file) {
  132. try {
  133. buffer = zlib.unzipSync(buffer);
  134. } catch (err) {
  135. throw new Error(`Invalid gzip data in archive: ${err && err.message || err}`);
  136. }
  137. let str = (i, n) => String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, "");
  138. let offset = 0;
  139. file = `package/${file}`;
  140. while (offset < buffer.length) {
  141. let name = str(offset, 100);
  142. let size = parseInt(str(offset + 124, 12), 8);
  143. offset += 512;
  144. if (!isNaN(size)) {
  145. if (name === file)
  146. return buffer.subarray(offset, offset + size);
  147. offset += size + 511 & ~511;
  148. }
  149. }
  150. throw new Error(`Could not find ${JSON.stringify(file)} in archive`);
  151. }
  152. function installUsingNPM(name, file) {
  153. const installDir = path.join(os.tmpdir(), "esbuild-" + Math.random().toString(36).slice(2));
  154. fs.mkdirSync(installDir, { recursive: true });
  155. fs.writeFileSync(path.join(installDir, "package.json"), "{}");
  156. const env = __spreadProps(__spreadValues({}, process.env), { npm_config_global: void 0 });
  157. child_process.execSync(`npm install --loglevel=error --prefer-offline --no-audit --progress=false ${name}@${version}`, { cwd: installDir, stdio: "pipe", env });
  158. const buffer = fs.readFileSync(path.join(installDir, "node_modules", name, file));
  159. try {
  160. removeRecursive(installDir);
  161. } catch (e) {
  162. }
  163. return buffer;
  164. }
  165. function removeRecursive(dir) {
  166. for (const entry of fs.readdirSync(dir)) {
  167. const entryPath = path.join(dir, entry);
  168. let stats;
  169. try {
  170. stats = fs.lstatSync(entryPath);
  171. } catch (e) {
  172. continue;
  173. }
  174. if (stats.isDirectory())
  175. removeRecursive(entryPath);
  176. else
  177. fs.unlinkSync(entryPath);
  178. }
  179. fs.rmdirSync(dir);
  180. }
  181. function isYarnBerryOrNewer() {
  182. const { npm_config_user_agent } = process.env;
  183. if (npm_config_user_agent) {
  184. const match = npm_config_user_agent.match(/yarn\/(\d+)/);
  185. if (match && match[1]) {
  186. return parseInt(match[1], 10) >= 2;
  187. }
  188. }
  189. return false;
  190. }
  191. function installDirectly(name) {
  192. if (process.env.ESBUILD_BINARY_PATH) {
  193. fs.copyFileSync(process.env.ESBUILD_BINARY_PATH, binPath);
  194. validateBinaryVersion(binPath);
  195. } else {
  196. const tempBinPath = binPath + "__";
  197. installBinaryFromPackage(name, "bin/esbuild", tempBinPath).then(() => fs.renameSync(tempBinPath, binPath)).catch((e) => setImmediate(() => {
  198. throw e;
  199. }));
  200. }
  201. }
  202. function installWithWrapper(name, fromPath, toPath) {
  203. fs.writeFileSync(binPath, `#!/usr/bin/env node
  204. const path = require('path');
  205. const esbuild_exe = path.join(__dirname, '..', ${JSON.stringify(toPath)});
  206. const child_process = require('child_process');
  207. const { status } = child_process.spawnSync(esbuild_exe, process.argv.slice(2), { stdio: 'inherit' });
  208. process.exitCode = status === null ? 1 : status;
  209. `);
  210. const absToPath = path.join(__dirname, toPath);
  211. if (process.env.ESBUILD_BINARY_PATH) {
  212. fs.copyFileSync(process.env.ESBUILD_BINARY_PATH, absToPath);
  213. validateBinaryVersion(absToPath);
  214. } else {
  215. installBinaryFromPackage(name, fromPath, absToPath).catch((e) => setImmediate(() => {
  216. throw e;
  217. }));
  218. }
  219. }
  220. function installOnUnix(name) {
  221. if (isYarnBerryOrNewer()) {
  222. installWithWrapper(name, "bin/esbuild", "esbuild");
  223. } else {
  224. installDirectly(name);
  225. }
  226. }
  227. function installOnWindows(name) {
  228. installWithWrapper(name, "esbuild.exe", "esbuild.exe");
  229. }
  230. const platformKey = `${process.platform} ${os.arch()} ${os.endianness()}`;
  231. const knownWindowsPackages = {
  232. "win32 arm64 LE": "esbuild-windows-arm64",
  233. "win32 ia32 LE": "esbuild-windows-32",
  234. "win32 x64 LE": "esbuild-windows-64"
  235. };
  236. const knownUnixlikePackages = {
  237. "android arm64 LE": "esbuild-android-arm64",
  238. "darwin arm64 LE": "esbuild-darwin-arm64",
  239. "darwin x64 LE": "esbuild-darwin-64",
  240. "freebsd arm64 LE": "esbuild-freebsd-arm64",
  241. "freebsd x64 LE": "esbuild-freebsd-64",
  242. "openbsd x64 LE": "esbuild-openbsd-64",
  243. "linux arm LE": "esbuild-linux-arm",
  244. "linux arm64 LE": "esbuild-linux-arm64",
  245. "linux ia32 LE": "esbuild-linux-32",
  246. "linux mips64el LE": "esbuild-linux-mips64le",
  247. "linux ppc64 LE": "esbuild-linux-ppc64le",
  248. "linux x64 LE": "esbuild-linux-64",
  249. "sunos x64 LE": "esbuild-sunos-64"
  250. };
  251. if (platformKey in knownWindowsPackages) {
  252. installOnWindows(knownWindowsPackages[platformKey]);
  253. } else if (platformKey in knownUnixlikePackages) {
  254. installOnUnix(knownUnixlikePackages[platformKey]);
  255. } else {
  256. console.error(`Unsupported platform: ${platformKey}`);
  257. process.exit(1);
  258. }