diff --git a/scripts/download.mjs b/scripts/download.mjs new file mode 100644 index 0000000..095d779 --- /dev/null +++ b/scripts/download.mjs @@ -0,0 +1,112 @@ +import fs from "node:fs"; +import fsP from "node:fs/promises"; +import { join, dirname, basename } from "node:path"; +import { pipeline } from "node:stream/promises"; +import { fileURLToPath } from "node:url"; +import { homedir } from "node:os"; +import crypto from "node:crypto"; +import { tgz } from "compressing"; +import { Readable } from "node:stream"; +import { finished } from "node:stream/promises"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const resourceJSON = JSON.parse(fs.readFileSync(join(__dirname, "resource.json"), "utf-8")); + +const info = resourceJSON[`${process.platform}-${process.arch}`]; +if (!info) { + const supportList = Object.keys(resourceJSON).map(item => item.split("-").join(" ")).join(", "); + console.warn(`[OVM]: Currently only supports ${supportList}`); + process.exit(0); +} + +const cacheDir = join(homedir(), ".cache", "ovm"); +const distDir = join(__dirname, "vm-resources"); +await fsP.mkdir(distDir, { recursive: true }); + +for (const { name, version, download: downloadTemplate, sha256, out } of info) { + const downloadURL = downloadTemplate.replace(/\{version}/g, version); + const cachePath = join(cacheDir, `${name}-${version}`, ...out.split("/")); + await fsP.mkdir(dirname(cachePath), { recursive: true }); + + await download(5)(downloadURL, cachePath, sha256); + + let distPath; + if (out.endsWith(".tar.gz")) { + distPath = join(distDir, out.replace(".tar.gz", "")); + await fsP.rm(distPath, { force: true, recursive: true }); + await tgz.uncompress(cachePath, distPath) + } else { + distPath = join(distDir, out); + await fsP.rm(distPath, { force: true, recursive: true }); + await fsP.mkdir(dirname(distPath), { recursive: true }); + await fsP.copyFile(cachePath, distPath); + } + + console.log(`[OVM]: Downloaded ${distPath}`); +} + +const files = await fsP.readdir(distDir, { withFileTypes: true, recursive: true }); +for (const file of files) { + if (file.isDirectory()) { + continue; + } + if (["gvproxy", "krunkit", "ovm", "ovm.exe"].includes(file.name)) { + await fsP.chmod(join(file.path, file.name), 0o755); + } +} + +console.log("[OVM]: Downloaded successfully"); + +function download(retry) { + let r = retry; + return async function doDownload(url, output, sha256, isRetry = false) { + if (r === 0) { + console.error("[OVM]: Failed to download the file"); + process.exit(1); + } + r--; + + if (fs.existsSync(output)) { + const cacheHash = await computeHash(output); + if (cacheHash === sha256) { + isRetry || console.info(`[OVM]: Find ${basename(output)} in cache, hash matched`); + return; + } + + console.warn(`[OVM]: Hash mismatch for ${basename(output)}, Expected: ${sha256}, Actual: ${cacheHash}`); + await fsP.rm(output, { force: true }); + } + + console.log("[OVM]: Downloading", url, "to", output); + try { + await downloadSteam(url, output) + } catch (_err) { + console.warn("[OVM]: Download failed, retrying..."); + await new Promise(resolve => setTimeout(resolve, 1000)); + await fsP.rm(output, { force: true }); + } + + await doDownload(url, output, sha256, true); + } +} + +async function computeHash(filePath) { + const input = fs.createReadStream(filePath); + const hash = crypto.createHash("sha256"); + await pipeline(input, hash); + return hash.digest("hex"); +} + + +async function downloadSteam (url, dest) { + const resp = await fetch(url); + if (!resp.ok || !resp.body) { + throw new Error(`unexpected response ${resp.statusText}`); + } + + const file = fs.createWriteStream(dest); + await finished(Readable.fromWeb(resp.body) + .pipe(file)); +} diff --git a/scripts/package-lock.json b/scripts/package-lock.json new file mode 100644 index 0000000..9d72812 --- /dev/null +++ b/scripts/package-lock.json @@ -0,0 +1,329 @@ +{ + "name": "scripts", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "scripts", + "version": "1.0.0", + "dependencies": { + "compressing": "^1.10.1" + } + }, + "node_modules/@eggjs/yauzl": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@eggjs/yauzl/-/yauzl-2.11.0.tgz", + "integrity": "sha512-Jq+k2fCZJ3i3HShb0nxLUiAgq5pwo8JTT1TrH22JoehZQ0Nm2dvByGIja1NYfNyuE4Tx5/Dns5nVsBN/mlC8yg==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer2": "^1.2.0" + } + }, + "node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT" + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "license": "MIT" + }, + "node_modules/compressing": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/compressing/-/compressing-1.10.1.tgz", + "integrity": "sha512-XXwUffcVjqv8NGSQu1ttp6eMmuZ3zZEAec28Rt30o/vkXE20jXhowRQ9LXLY4uOgFkxXrNzApLobpam53Dc1AA==", + "license": "MIT", + "dependencies": { + "@eggjs/yauzl": "^2.11.0", + "flushwritable": "^1.0.0", + "get-ready": "^1.0.0", + "iconv-lite": "^0.5.0", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "streamifier": "^0.1.1", + "tar-stream": "^1.5.2", + "yazl": "^2.4.2" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/fd-slicer2": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fd-slicer2/-/fd-slicer2-1.2.0.tgz", + "integrity": "sha512-3lBUNUckhMZduCc4g+Pw4Ve16LD9vpX9b8qUkkKq2mgDRLYWzblszZH2luADnJqjJe+cypngjCuKRm/IW12rRw==", + "license": "MIT", + "dependencies": { + "pend": "^1.2.0" + } + }, + "node_modules/flushwritable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flushwritable/-/flushwritable-1.0.0.tgz", + "integrity": "sha512-3VELfuWCLVzt5d2Gblk8qcqFro6nuwvxwMzHaENVDHI7rxcBRtMCwTk/E9FXcgh+82DSpavPNDueA9+RxXJoFg==", + "license": "MIT" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/get-ready": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-ready/-/get-ready-1.0.0.tgz", + "integrity": "sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw==", + "license": "MIT" + }, + "node_modules/iconv-lite": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", + "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/streamifier": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz", + "integrity": "sha512-zDgl+muIlWzXNsXeyUfOk9dChMjlpkq0DRsxujtYPgyJ676yQ8jEm6zzaaWHFDg5BNcLuif0eD2MTyJdZqXpdg==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "license": "MIT", + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/scripts/package.json b/scripts/package.json new file mode 100644 index 0000000..a1a8106 --- /dev/null +++ b/scripts/package.json @@ -0,0 +1,8 @@ +{ + "name": "scripts", + "version": "1.0.0", + "packageManager": "npm@10.9.0", + "dependencies": { + "compressing": "^1.10.1" + } +} diff --git a/scripts/postinstall.mjs b/scripts/postinstall.mjs index a7f7e59..4d1b4a5 100644 --- a/scripts/postinstall.mjs +++ b/scripts/postinstall.mjs @@ -1,99 +1,45 @@ -import fs from "node:fs"; import fsP from "node:fs/promises"; -import got from "got"; -import { join, dirname, basename } from "node:path"; -import { pipeline } from "node:stream/promises"; +import os from "node:os"; +import path, { dirname } from "node:path"; +import cp from "node:child_process"; import { fileURLToPath } from "node:url"; -import { homedir } from "node:os"; -import crypto from "node:crypto"; -import { tgz } from "compressing"; +import fs, { constants } from "node:fs"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const resourceJSON = JSON.parse(fs.readFileSync(join(__dirname, "..", "resource.json"), "utf-8")); - -const info = resourceJSON[`${process.platform}-${process.arch}`]; -if (!info) { - const supportList = Object.keys(resourceJSON).map(item => item.split("-").join(" ")).join(", "); - console.warn(`[OVM]: Currently only supports ${supportList}`); - process.exit(0); -} - -const cacheDir = join(homedir(), ".cache", "ovm"); -const distDir = join(__dirname, "..", "vm-resources"); -await fsP.mkdir(distDir, { recursive: true }); - -for (const { name, version, download: downloadTemplate, sha256, out } of info) { - const downloadURL = downloadTemplate.replace(/\{version}/g, version); - const cachePath = join(cacheDir, `${name}-${version}`, ...out.split("/")); - await fsP.mkdir(dirname(cachePath), { recursive: true }); - - await download(5)(downloadURL, cachePath, sha256); - - let distPath; - if (out.endsWith(".tar.gz")) { - distPath = join(distDir, out.replace(".tar.gz", "")); - await fsP.rm(distPath, { force: true, recursive: true }); - await tgz.uncompress(cachePath, distPath) - } else { - distPath = join(distDir, out); - await fsP.rm(distPath, { force: true, recursive: true }); - await fsP.mkdir(dirname(distPath), { recursive: true }); - await fsP.copyFile(cachePath, distPath); - } - - console.log(`[OVM]: Downloaded ${distPath}`); -} - -const files = await fsP.readdir(distDir, { withFileTypes: true, recursive: true }); -for (const file of files) { - if (file.isDirectory()) { - continue; - } - if (["gvproxy", "krunkit", "ovm", "ovm.exe"].includes(file.name)) { - await fsP.chmod(join(file.path, file.name), 0o755); - } -} - -console.log("[OVM]: Downloaded successfully"); - -function download(retry) { - let r = retry; - return async function doDownload(url, output, sha256, isRetry = false) { - if (r === 0) { - console.error("[OVM]: Failed to download the file"); - process.exit(1); - } - r--; - - if (fs.existsSync(output)) { - const cacheHash = await computeHash(output); - if (cacheHash === sha256) { - isRetry || console.info(`[OVM]: Find ${basename(output)} in cache, hash matched`); - return; - } - - console.warn(`[OVM]: Hash mismatch for ${basename(output)}, Expected: ${sha256}, Actual: ${cacheHash}`); - await fsP.rm(output, { force: true }); - } - - console.log("[OVM]: Downloading", url, "to", output); - try { - await pipeline(got.stream(url), fs.createWriteStream(output)); - } catch (_err) { - console.warn("[OVM]: Download failed, retrying..."); - await new Promise(resolve => setTimeout(resolve, 1000)); - await fsP.rm(output, { force: true }); - } - - await doDownload(url, output, sha256, true); +const workspace = await fsP.mkdtemp(path.join(os.tmpdir(), "ovm-download-")); + +await Promise.all([ + fsP.cp(path.join(__dirname, "download.mjs"), path.join(workspace, "download.mjs"), { force: true }), + fsP.cp(path.join(__dirname, "resource.json"), path.join(workspace, "resource.json"), { force: true }), + fsP.cp(path.join(__dirname, "package.json"), path.join(workspace, "package.json"), { force: true }), + fsP.cp(path.join(__dirname, "package-lock.json"), path.join(workspace, "package-lock.json"), { force: true }), +]) + +cp.execSync("npm install", { + cwd: workspace, + encoding: "utf-8", + shell: true, + stdio: "inherit", +}); + +cp.execSync("node download.mjs", { + cwd: workspace, + encoding: "utf-8", + shell: true, + stdio: "inherit", +}); + +fs.access(path.join(workspace, "vm-resources"), constants.F_OK, async (err) => { + if (!err) { + console.log(`[OVM]: Move ${path.join(workspace, "vm-resources")} to ${path.join(__dirname, "..", "vm-resources")}`); + await fsP.cp(path.join(workspace, "vm-resources"), path.join(__dirname, "..", "vm-resources"), { + recursive: true, + force: true, + preserveTimestamps: true, + }); } -} -async function computeHash(filePath) { - const input = fs.createReadStream(filePath); - const hash = crypto.createHash("sha256"); - await pipeline(input, hash); - return hash.digest("hex"); -} + await fsP.rm(workspace, { recursive: true, force: true }); +}); diff --git a/resource.json b/scripts/resource.json similarity index 100% rename from resource.json rename to scripts/resource.json