mirror of
https://gitee.com/myxzgzs/boyue_jnpf.git
synced 2025-08-12 17:22:42 +08:00
197 lines
9.0 KiB
JavaScript
197 lines
9.0 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.AsarPackager = void 0;
|
|
const asar_1 = require("@electron/asar");
|
|
const builder_util_1 = require("builder-util");
|
|
const fs_1 = require("builder-util/out/fs");
|
|
const fs = require("fs-extra");
|
|
const fs_extra_1 = require("fs-extra");
|
|
const os_1 = require("os");
|
|
const path = require("path");
|
|
const appFileCopier_1 = require("../util/appFileCopier");
|
|
const unpackDetector_1 = require("./unpackDetector");
|
|
/** @internal */
|
|
class AsarPackager {
|
|
constructor(packager, config) {
|
|
this.packager = packager;
|
|
this.config = config;
|
|
this.fileCopier = new fs_1.FileCopier();
|
|
this.outFile = path.join(config.resourcePath, `app.asar`);
|
|
this.tmpDir = packager.info.tempDirManager;
|
|
this.cancellationToken = packager.info.cancellationToken;
|
|
}
|
|
async pack(fileSets) {
|
|
this.rootForAppFilesWithoutAsar = await this.tmpDir.getTempDir({ prefix: "asar-app" });
|
|
const orderedFileSets = [
|
|
// Write dependencies first to minimize offset changes to asar header
|
|
...fileSets.slice(1),
|
|
// Finish with the app files that change most often
|
|
fileSets[0],
|
|
].map(orderFileSet);
|
|
const { unpackedPaths, copiedFiles } = await this.detectAndCopy(orderedFileSets);
|
|
const unpackGlob = unpackedPaths.length > 1 ? `{${unpackedPaths.join(",")}}` : unpackedPaths.pop();
|
|
await this.executeElectronAsar(copiedFiles, unpackGlob);
|
|
}
|
|
async executeElectronAsar(copiedFiles, unpackGlob) {
|
|
let ordering = this.config.options.ordering || undefined;
|
|
if (!ordering) {
|
|
// `copiedFiles` are already ordered due to `orderedFileSets` input, so we just map to their relative paths (via substring) within the asar.
|
|
const filesSorted = copiedFiles.map(file => file.substring(this.rootForAppFilesWithoutAsar.length));
|
|
ordering = await this.tmpDir.getTempFile({ prefix: "asar-ordering", suffix: ".txt" });
|
|
await fs.writeFile(ordering, filesSorted.join("\n"));
|
|
}
|
|
const options = {
|
|
unpack: unpackGlob,
|
|
unpackDir: unpackGlob,
|
|
ordering,
|
|
dot: true,
|
|
};
|
|
// override logger temporarily to clean up console (electron/asar does some internal logging that blogs up the default electron-builder logs)
|
|
const consoleLogger = console.log;
|
|
console.log = (...args) => {
|
|
if (args[0] === "Ordering file has 100% coverage.") {
|
|
return; // no need to log, this means our ordering logic is working correctly
|
|
}
|
|
builder_util_1.log.info({ args }, "logging @electron/asar");
|
|
};
|
|
await (0, asar_1.createPackageWithOptions)(this.rootForAppFilesWithoutAsar, this.outFile, options);
|
|
console.log = consoleLogger;
|
|
}
|
|
async detectAndCopy(fileSets) {
|
|
var _a;
|
|
const taskManager = new builder_util_1.AsyncTaskManager(this.cancellationToken);
|
|
const unpackedPaths = new Set();
|
|
const copiedFiles = new Set();
|
|
const createdSourceDirs = new Set();
|
|
const links = [];
|
|
const symlinkType = (0, os_1.platform)() === "win32" ? "junction" : "file";
|
|
const matchUnpacker = (file, dest, stat, tmpUnpackedPaths) => {
|
|
var _a, _b;
|
|
if ((_b = (_a = this.config).unpackPattern) === null || _b === void 0 ? void 0 : _b.call(_a, file, stat)) {
|
|
builder_util_1.log.debug({ file }, "unpacking");
|
|
tmpUnpackedPaths.add(dest);
|
|
return;
|
|
}
|
|
};
|
|
const writeFileOrProcessSymlink = async (options) => {
|
|
const { transformedData, file, destination, stat, fileSet } = options;
|
|
if (!stat.isFile() && !stat.isSymbolicLink()) {
|
|
return;
|
|
}
|
|
copiedFiles.add(destination);
|
|
const dir = path.dirname(destination);
|
|
if (!createdSourceDirs.has(dir)) {
|
|
await (0, fs_extra_1.mkdir)(dir, { recursive: true });
|
|
createdSourceDirs.add(dir);
|
|
}
|
|
// write any data if provided, skip symlink check
|
|
if (transformedData != null) {
|
|
return fs.writeFile(destination, transformedData, { mode: stat.mode });
|
|
}
|
|
const realPathFile = await fs.realpath(file);
|
|
const realPathRelative = path.relative(fileSet.src, realPathFile);
|
|
const isOutsidePackage = realPathRelative.startsWith("..");
|
|
if (isOutsidePackage) {
|
|
builder_util_1.log.error({ source: builder_util_1.log.filePath(file), realPathFile: builder_util_1.log.filePath(realPathFile) }, `unable to copy, file is symlinked outside the package`);
|
|
throw new Error(`Cannot copy file (${path.basename(file)}) symlinked to file (${path.basename(realPathFile)}) outside the package as that violates asar security integrity`);
|
|
}
|
|
// not a symlink, copy directly
|
|
if (file === realPathFile) {
|
|
return this.fileCopier.copy(file, destination, stat);
|
|
}
|
|
// okay, it must be a symlink. evaluate link to be relative to source file in asar
|
|
let link = await (0, fs_extra_1.readlink)(file);
|
|
if (path.isAbsolute(link)) {
|
|
link = path.relative(path.dirname(file), link);
|
|
}
|
|
links.push({ file: destination, link });
|
|
};
|
|
for (const fileSet of fileSets) {
|
|
if (this.config.options.smartUnpack !== false) {
|
|
(0, unpackDetector_1.detectUnpackedDirs)(fileSet, unpackedPaths);
|
|
}
|
|
// Don't use Promise.all, we need to retain order of execution/iteration through the ordered fileset
|
|
const tmpUnpackedPaths = new Set();
|
|
for (let i = 0; i < fileSet.files.length; i++) {
|
|
const file = fileSet.files[i];
|
|
const transformedData = (_a = fileSet.transformedFiles) === null || _a === void 0 ? void 0 : _a.get(i);
|
|
const stat = fileSet.metadata.get(file);
|
|
const relative = path.relative(this.config.defaultDestination, (0, appFileCopier_1.getDestinationPath)(file, fileSet));
|
|
const destination = path.resolve(this.rootForAppFilesWithoutAsar, relative);
|
|
matchUnpacker(file, destination, stat, tmpUnpackedPaths);
|
|
taskManager.addTask(writeFileOrProcessSymlink({ transformedData, file, destination, stat, fileSet }));
|
|
if (taskManager.tasks.length > fs_1.MAX_FILE_REQUESTS) {
|
|
await taskManager.awaitTasks();
|
|
}
|
|
}
|
|
if (tmpUnpackedPaths.size === fileSet.files.length) {
|
|
const relative = path.relative(this.config.defaultDestination, fileSet.destination);
|
|
unpackedPaths.add(relative);
|
|
}
|
|
else {
|
|
// add all tmpUnpackedPaths to unpackedPaths
|
|
for (const it of tmpUnpackedPaths) {
|
|
unpackedPaths.add(it);
|
|
}
|
|
}
|
|
}
|
|
// finish copy then set up all symlinks
|
|
await taskManager.awaitTasks();
|
|
for (const it of links) {
|
|
taskManager.addTask((0, fs_extra_1.symlink)(it.link, it.file, symlinkType));
|
|
if (taskManager.tasks.length > fs_1.MAX_FILE_REQUESTS) {
|
|
await taskManager.awaitTasks();
|
|
}
|
|
}
|
|
await taskManager.awaitTasks();
|
|
return {
|
|
unpackedPaths: Array.from(unpackedPaths),
|
|
copiedFiles: Array.from(copiedFiles),
|
|
};
|
|
}
|
|
}
|
|
exports.AsarPackager = AsarPackager;
|
|
function orderFileSet(fileSet) {
|
|
const sortedFileEntries = Array.from(fileSet.files.entries());
|
|
sortedFileEntries.sort(([, a], [, b]) => {
|
|
if (a === b) {
|
|
return 0;
|
|
}
|
|
// Place addons last because their signature changes per build
|
|
const isAAddon = a.endsWith(".node");
|
|
const isBAddon = b.endsWith(".node");
|
|
if (isAAddon && !isBAddon) {
|
|
return 1;
|
|
}
|
|
if (isBAddon && !isAAddon) {
|
|
return -1;
|
|
}
|
|
// Otherwise order by name
|
|
return a < b ? -1 : 1;
|
|
});
|
|
let transformedFiles;
|
|
if (fileSet.transformedFiles) {
|
|
transformedFiles = new Map();
|
|
const indexMap = new Map();
|
|
for (const [newIndex, [oldIndex]] of sortedFileEntries.entries()) {
|
|
indexMap.set(oldIndex, newIndex);
|
|
}
|
|
for (const [oldIndex, value] of fileSet.transformedFiles) {
|
|
const newIndex = indexMap.get(oldIndex);
|
|
if (newIndex === undefined) {
|
|
const file = fileSet.files[oldIndex];
|
|
throw new Error(`Internal error: ${file} was lost while ordering asar`);
|
|
}
|
|
transformedFiles.set(newIndex, value);
|
|
}
|
|
}
|
|
const { src, destination, metadata } = fileSet;
|
|
return {
|
|
src,
|
|
destination,
|
|
metadata,
|
|
files: sortedFileEntries.map(([, file]) => file),
|
|
transformedFiles,
|
|
};
|
|
}
|
|
//# sourceMappingURL=asarUtil.js.map
|