install.js 8.5 KB

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