436a9631fc
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
218 lines
9.6 KiB
JavaScript
218 lines
9.6 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.hashUrlSafe = hashUrlSafe;
|
||
exports.getCacheDirectory = getCacheDirectory;
|
||
exports.downloadArtifact = downloadArtifact;
|
||
exports.download = download;
|
||
exports.getBinFromCustomLoc = getBinFromCustomLoc;
|
||
exports.getBinFromUrl = getBinFromUrl;
|
||
exports.getBin = getBin;
|
||
const get = require("@electron/get");
|
||
const get_1 = require("@electron/get");
|
||
const builder_util_1 = require("builder-util");
|
||
const filename_1 = require("builder-util/out/filename");
|
||
const multiProgress_1 = require("electron-publish/out/multiProgress");
|
||
const fs = require("fs/promises");
|
||
const os = require("os");
|
||
const path = require("path");
|
||
const lockfile = require("proper-lockfile");
|
||
const tar = require("tar");
|
||
/**
|
||
* Deterministic <length>-character URL-safe hash (a–z0–9)
|
||
*/
|
||
function hashUrlSafe(input, length = 6) {
|
||
let hash = 5381;
|
||
for (let i = 0; i < input.length; i++) {
|
||
hash = ((hash << 5) + hash) ^ input.charCodeAt(i); // hash * 33 ^ c
|
||
}
|
||
// Force unsigned 32-bit
|
||
hash >>>= 0;
|
||
// Base-36 (0–9a–z)
|
||
const out = hash.toString(36);
|
||
// Ensure exactly `length` chars
|
||
if (out.length >= length) {
|
||
return out.slice(0, length);
|
||
}
|
||
return out.padStart(length, "0");
|
||
}
|
||
/**
|
||
* Get cache directory for electron-builder
|
||
*/
|
||
function getCacheDirectory(isAvoidSystemOnWindows = false) {
|
||
var _a, _b, _c, _d, _e;
|
||
const env = (_a = process.env.ELECTRON_BUILDER_CACHE) === null || _a === void 0 ? void 0 : _a.trim();
|
||
if (env) {
|
||
return env;
|
||
}
|
||
const appName = "electron-builder";
|
||
const platform = os.platform();
|
||
const homeDir = os.homedir();
|
||
if (platform === "darwin") {
|
||
return path.join(homeDir, "Library", "Caches", appName);
|
||
}
|
||
if (platform === "win32") {
|
||
const localAppData = (_b = process.env.LOCALAPPDATA) === null || _b === void 0 ? void 0 : _b.trim();
|
||
const username = (_d = (_c = process.env.USERNAME) === null || _c === void 0 ? void 0 : _c.trim()) === null || _d === void 0 ? void 0 : _d.toLowerCase();
|
||
const isSystemUser = isAvoidSystemOnWindows && (((_e = localAppData === null || localAppData === void 0 ? void 0 : localAppData.toLowerCase()) === null || _e === void 0 ? void 0 : _e.includes("\\windows\\system32\\")) || username === "system");
|
||
if (!localAppData || isSystemUser) {
|
||
return path.join(os.tmpdir(), `${appName}-cache`);
|
||
}
|
||
return path.join(localAppData, appName, "Cache");
|
||
}
|
||
// linux
|
||
const xdgCache = process.env.XDG_CACHE_HOME;
|
||
if (xdgCache) {
|
||
return path.join(xdgCache, appName);
|
||
}
|
||
return path.join(homeDir, ".cache", appName);
|
||
}
|
||
/**
|
||
* Downloads an artifact from GitHub releases (convenience wrapper)
|
||
*/
|
||
async function downloadArtifact(options) {
|
||
const { releaseName, filenameWithExt, checksums, githubOrgRepo = "electron-userland/electron-builder-binaries" } = options;
|
||
const file = await _downloadArtifact(`https://github.com/${githubOrgRepo}/releases/download/`, releaseName, filenameWithExt, checksums);
|
||
return file;
|
||
}
|
||
/**
|
||
* Downloads, validates, and extracts a .tar.gz from a release URL
|
||
*/
|
||
async function _downloadArtifact(baseUrl, releaseName, filenameWithExt, checksums) {
|
||
var _a;
|
||
const suffix = hashUrlSafe(`${baseUrl}-${releaseName}-${filenameWithExt}`, 5);
|
||
const folderName = `${filenameWithExt.replace(/\.(tar\.gz|tgz)$/, "")}-${suffix}`;
|
||
const extractDir = path.join(getCacheDirectory(), releaseName, folderName);
|
||
const extractionCompleteMarker = `${extractDir}.complete`;
|
||
// Ensure download directory exists before trying to lock
|
||
await fs.mkdir(extractDir, { recursive: true });
|
||
// Acquire the lock
|
||
let release;
|
||
try {
|
||
release = await lockfile.lock(extractDir, {
|
||
retries: {
|
||
retries: 5,
|
||
minTimeout: 1000,
|
||
maxTimeout: 5000,
|
||
},
|
||
stale: 60000,
|
||
});
|
||
const varName = "ELECTRON_DOWNLOAD_CACHE_MODE";
|
||
const cacheOverride = (_a = process.env[varName]) === null || _a === void 0 ? void 0 : _a.trim();
|
||
let cacheMode = get_1.ElectronDownloadCacheMode.ReadWrite;
|
||
if (cacheOverride && Number(cacheOverride) in get_1.ElectronDownloadCacheMode) {
|
||
cacheMode = Number(cacheOverride);
|
||
builder_util_1.log.debug({ mode: cacheMode }, `cache mode overridden via env var ${varName}`);
|
||
}
|
||
if (await (0, builder_util_1.exists)(extractionCompleteMarker)) {
|
||
builder_util_1.log.debug({ file: filenameWithExt, path: extractDir }, "using cached artifact - skipping download/extract");
|
||
return extractDir;
|
||
}
|
||
// These are just stubs. Actual url construction/file naming are in `mirrorOptions` below.
|
||
const details = {
|
||
// Needs to be higher than 1.3.2 to avoid @electron/get validation shortcut
|
||
// https://github.com/electron/get/blob/05c466d4fc60fa0c83064df28dce245eb83d63c9/src/index.ts#L60
|
||
version: "9.9.9",
|
||
artifactName: filenameWithExt, // also is the output filename
|
||
};
|
||
const progress = process.stdout.isTTY ? new multiProgress_1.MultiProgress() : null;
|
||
const progressBar = progress === null || progress === void 0 ? void 0 : progress.createBar(`${" ".repeat(builder_util_1.PADDING + 2)}[:bar] :percent | ${filenameWithExt}`, { total: 100 });
|
||
const downloadOptions = {
|
||
getProgressCallback: info => {
|
||
progressBar === null || progressBar === void 0 ? void 0 : progressBar.update(info.percent != null ? Math.floor(info.percent * 100) : 0);
|
||
return Promise.resolve();
|
||
},
|
||
};
|
||
const options = {
|
||
cacheRoot: path.resolve(getCacheDirectory(), "downloads"),
|
||
cacheMode,
|
||
downloadOptions,
|
||
checksums,
|
||
mirrorOptions: {
|
||
// `${opts.mirror}${opts.customDir}/${opts.customFilename}`
|
||
mirror: baseUrl,
|
||
customDir: releaseName,
|
||
customFilename: filenameWithExt,
|
||
},
|
||
};
|
||
builder_util_1.log.info({ release: releaseName, file: filenameWithExt }, "downloading");
|
||
progressBar === null || progressBar === void 0 ? void 0 : progressBar.render();
|
||
const downloadedFile = await get.downloadArtifact({
|
||
...details,
|
||
...options,
|
||
isGeneric: true,
|
||
});
|
||
await tar.extract({
|
||
file: downloadedFile,
|
||
cwd: extractDir,
|
||
strip: 1, // Strip the top-level directory from the archive
|
||
});
|
||
// Write the extraction complete marker file to indicate successful extraction and prevent future re-extraction
|
||
await fs.writeFile(extractionCompleteMarker, "");
|
||
builder_util_1.log.debug({ file: filenameWithExt, path: extractDir }, "downloaded");
|
||
progressBar === null || progressBar === void 0 ? void 0 : progressBar.update(100);
|
||
progressBar === null || progressBar === void 0 ? void 0 : progressBar.terminate();
|
||
return extractDir;
|
||
}
|
||
finally {
|
||
// Release the lock
|
||
if (release) {
|
||
await release();
|
||
}
|
||
}
|
||
}
|
||
const versionToPromise = new Map();
|
||
function download(url, output, checksum) {
|
||
const args = ["download", "--url", url, "--output", output];
|
||
if (checksum != null) {
|
||
args.push("--sha512", checksum);
|
||
}
|
||
return (0, builder_util_1.executeAppBuilder)(args);
|
||
}
|
||
function getBinFromCustomLoc(name, version, binariesLocUrl, checksum) {
|
||
const dirName = `${name}-${version}`;
|
||
return getBin(dirName, binariesLocUrl, checksum);
|
||
}
|
||
function getBinFromUrl(releaseName, filenameWithExt, checksum, githubOrgRepo = "electron-userland/electron-builder-binaries") {
|
||
let url;
|
||
if (process.env.ELECTRON_BUILDER_BINARIES_DOWNLOAD_OVERRIDE_URL) {
|
||
url = process.env.ELECTRON_BUILDER_BINARIES_DOWNLOAD_OVERRIDE_URL + "/" + filenameWithExt;
|
||
}
|
||
else {
|
||
const baseUrl = process.env.NPM_CONFIG_ELECTRON_BUILDER_BINARIES_MIRROR ||
|
||
process.env.npm_config_electron_builder_binaries_mirror ||
|
||
process.env.npm_package_config_electron_builder_binaries_mirror ||
|
||
process.env.ELECTRON_BUILDER_BINARIES_MIRROR ||
|
||
`https://github.com/${githubOrgRepo}/releases/download/`;
|
||
const middleUrl = process.env.NPM_CONFIG_ELECTRON_BUILDER_BINARIES_CUSTOM_DIR ||
|
||
process.env.npm_config_electron_builder_binaries_custom_dir ||
|
||
process.env.npm_package_config_electron_builder_binaries_custom_dir ||
|
||
process.env.ELECTRON_BUILDER_BINARIES_CUSTOM_DIR ||
|
||
releaseName;
|
||
url = `${baseUrl}${middleUrl}/${filenameWithExt}`;
|
||
}
|
||
const cacheKey = `${releaseName}-${path.basename(filenameWithExt, path.extname(filenameWithExt))}`;
|
||
return getBin(cacheKey, url, checksum);
|
||
}
|
||
function getBin(cacheKey, url, checksum) {
|
||
var _a;
|
||
// Old cache is ignored if cache environment variable changes
|
||
const cacheName = (0, filename_1.sanitizeFileName)(`${(_a = process.env.ELECTRON_BUILDER_CACHE) !== null && _a !== void 0 ? _a : ""}${cacheKey}`);
|
||
let promise = versionToPromise.get(cacheName); // if rejected, we will try to download again
|
||
if (promise != null) {
|
||
return promise;
|
||
}
|
||
promise = doGetBin(cacheKey, url, checksum);
|
||
versionToPromise.set(cacheName, promise);
|
||
return promise;
|
||
}
|
||
function doGetBin(name, url, checksum) {
|
||
const args = ["download-artifact", "--name", name];
|
||
if (url != null) {
|
||
args.push("--url", url);
|
||
}
|
||
if (checksum != null) {
|
||
args.push("--sha512", checksum);
|
||
}
|
||
return (0, builder_util_1.executeAppBuilder)(args);
|
||
}
|
||
//# sourceMappingURL=binDownload.js.map
|