electron-builder
Version:
A complete solution to package and build a ready for distribution Electron app for MacOS, Windows and Linux with “auto update” support out of the box
483 lines (448 loc) • 22.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.checkFileInArchive = exports.createAsarArchive = exports.walk = undefined;
var _bluebirdLstC;
function _load_bluebirdLstC() {
return _bluebirdLstC = require("bluebird-lst-c");
}
var _bluebirdLstC2;
function _load_bluebirdLstC2() {
return _bluebirdLstC2 = _interopRequireDefault(require("bluebird-lst-c"));
}
let walk = exports.walk = (() => {
var _ref = (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* (initialDirPath, consumer, filter) {
const result = [];
const queue = [initialDirPath];
let addDirToResult = false;
while (queue.length > 0) {
const dirPath = queue.pop();
if (addDirToResult) {
result.push(dirPath);
} else {
addDirToResult = true;
}
const childNames = yield (0, (_fsExtraP || _load_fsExtraP()).readdir)(dirPath);
childNames.sort();
const dirs = [];
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.map(childNames, function (name) {
const filePath = dirPath + (_path || _load_path()).sep + name;
return (0, (_fsExtraP || _load_fsExtraP()).lstat)(filePath).then(function (stat) {
if (filter != null && !filter(filePath, stat)) {
return;
}
if (consumer != null) {
consumer(filePath, stat);
}
if (stat.isDirectory()) {
dirs.push(filePath);
} else {
result.push(filePath);
}
});
}, concurrency);
for (let i = dirs.length - 1; i > -1; i--) {
queue.push(dirs[i]);
}
}
return result;
});
return function walk(_x, _x2, _x3) {
return _ref.apply(this, arguments);
};
})();
let createAsarArchive = exports.createAsarArchive = (() => {
var _ref2 = (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* (src, resourcesPath, options, filter) {
// sort files to minimize file change (i.e. asar file is not changed dramatically on small change)
yield new AsarPackager(src, resourcesPath, options).pack(filter);
});
return function createAsarArchive(_x4, _x5, _x6, _x7) {
return _ref2.apply(this, arguments);
};
})();
let checkFileInArchive = exports.checkFileInArchive = (() => {
var _ref3 = (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* (asarFile, relativeFile, messagePrefix) {
function error(text) {
return new Error(`${ messagePrefix } "${ relativeFile }" in the "${ asarFile }" ${ text }`);
}
let stat;
try {
stat = (0, (_asarElectronBuilder || _load_asarElectronBuilder()).statFile)(asarFile, relativeFile);
} catch (e) {
const fileStat = yield (0, (_util || _load_util()).statOrNull)(asarFile);
if (fileStat == null) {
throw error(`does not exist. Seems like a wrong configuration.`);
}
try {
(0, (_asarElectronBuilder || _load_asarElectronBuilder()).listPackage)(asarFile);
} catch (e) {
throw error(`is corrupted: ${ e }`);
}
// asar throws error on access to undefined object (info.link)
stat = null;
}
if (stat == null) {
throw error(`does not exist. Seems like a wrong configuration.`);
}
if (stat.size === 0) {
throw error(`is corrupted: size 0`);
}
});
return function checkFileInArchive(_x8, _x9, _x10) {
return _ref3.apply(this, arguments);
};
})();
var _asarElectronBuilder;
function _load_asarElectronBuilder() {
return _asarElectronBuilder = require("asar-electron-builder");
}
var _util;
function _load_util() {
return _util = require("./util/util");
}
var _fsExtraP;
function _load_fsExtraP() {
return _fsExtraP = require("fs-extra-p");
}
var _path;
function _load_path() {
return _path = _interopRequireWildcard(require("path"));
}
var _log;
function _load_log() {
return _log = require("./util/log");
}
var _minimatch;
function _load_minimatch() {
return _minimatch = require("minimatch");
}
var _deepAssign;
function _load_deepAssign() {
return _deepAssign = require("./util/deepAssign");
}
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const isBinaryFile = (_bluebirdLstC2 || _load_bluebirdLstC2()).default.promisify(require("isbinaryfile"));
const pickle = require("chromium-pickle-js");
const Filesystem = require("asar-electron-builder/lib/filesystem");
const UINT64 = require("cuint").UINT64;
const MAX_FILE_REQUESTS = 8;
const concurrency = { concurrency: MAX_FILE_REQUESTS };
const NODE_MODULES_PATTERN = (_path || _load_path()).sep + "node_modules" + (_path || _load_path()).sep;
function isUnpackDir(path, pattern, rawPattern) {
return path.startsWith(rawPattern) || pattern.match(path);
}
class AsarPackager {
constructor(src, resourcesPath, options) {
this.src = src;
this.resourcesPath = resourcesPath;
this.options = options;
this.toPack = [];
this.fs = new Filesystem(this.src);
this.changedFiles = new Map();
this.outFile = (_path || _load_path()).join(this.resourcesPath, "app.asar");
}
pack(filter) {
var _this = this;
return (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* () {
const metadata = new Map();
const files = yield walk(_this.src, function (it, stat) {
metadata.set(it, stat);
}, filter);
yield _this.createPackageFromFiles(_this.options.ordering == null ? files : yield _this.order(files), metadata);
yield _this.writeAsarFile();
})();
}
getSrcRealPath() {
if (this.srcRealPath == null) {
this.srcRealPath = (0, (_fsExtraP || _load_fsExtraP()).realpath)(this.src);
}
return this.srcRealPath;
}
detectUnpackedDirs(files, metadata, autoUnpackDirs, createDirPromises, unpackedDest, fileIndexToModulePackageData) {
var _this2 = this;
return (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* () {
const packageJsonStringLength = "package.json".length;
const readPackageJsonPromises = [];
for (let i = 0, n = files.length; i < n; i++) {
const file = files[i];
const index = file.lastIndexOf(NODE_MODULES_PATTERN);
if (index < 0) {
continue;
}
const nextSlashIndex = file.indexOf((_path || _load_path()).sep, index + NODE_MODULES_PATTERN.length + 1);
if (nextSlashIndex < 0) {
continue;
}
if (!metadata.get(file).isFile()) {
continue;
}
const nodeModuleDir = file.substring(0, nextSlashIndex);
if (file.length === nodeModuleDir.length + 1 + packageJsonStringLength && file.endsWith("package.json")) {
const promise = (0, (_fsExtraP || _load_fsExtraP()).readJson)(file);
if (readPackageJsonPromises.length > MAX_FILE_REQUESTS) {
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(readPackageJsonPromises);
readPackageJsonPromises.length = 0;
}
readPackageJsonPromises.push(promise);
fileIndexToModulePackageData[i] = promise;
}
if (autoUnpackDirs.has(nodeModuleDir)) {
const fileParent = (_path || _load_path()).dirname(file);
if (fileParent !== nodeModuleDir && !autoUnpackDirs.has(fileParent)) {
autoUnpackDirs.add(fileParent);
createDirPromises.push((0, (_fsExtraP || _load_fsExtraP()).ensureDir)((_path || _load_path()).join(unpackedDest, (_path || _load_path()).relative(_this2.src, fileParent))));
if (createDirPromises.length > MAX_FILE_REQUESTS) {
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(createDirPromises);
createDirPromises.length = 0;
}
}
continue;
}
const ext = (_path || _load_path()).extname(file);
let shouldUnpack = false;
if (ext === ".dll" || ext === ".exe") {
shouldUnpack = true;
} else if (ext === "") {
shouldUnpack = yield isBinaryFile(file);
}
if (!shouldUnpack) {
continue;
}
(0, (_util || _load_util()).debug)(`${ (_path || _load_path()).relative(_this2.src, nodeModuleDir) } is not packed into asar archive - contains executable code`);
let fileParent = (_path || _load_path()).dirname(file);
// create parent dir to be able to copy file later without directory existence check
createDirPromises.push((0, (_fsExtraP || _load_fsExtraP()).ensureDir)((_path || _load_path()).join(unpackedDest, (_path || _load_path()).relative(_this2.src, fileParent))));
if (createDirPromises.length > MAX_FILE_REQUESTS) {
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(createDirPromises);
createDirPromises.length = 0;
}
while (fileParent !== nodeModuleDir) {
autoUnpackDirs.add(fileParent);
fileParent = (_path || _load_path()).dirname(fileParent);
}
autoUnpackDirs.add(nodeModuleDir);
}
if (readPackageJsonPromises.length > 0) {
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(readPackageJsonPromises);
}
if (createDirPromises.length > 0) {
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(createDirPromises);
createDirPromises.length = 0;
}
})();
}
createPackageFromFiles(files, metadata) {
var _this3 = this;
return (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* () {
// search auto unpacked dir
const autoUnpackDirs = new Set();
const createDirPromises = [(0, (_fsExtraP || _load_fsExtraP()).ensureDir)((_path || _load_path()).dirname(_this3.outFile))];
const unpackedDest = `${ _this3.outFile }.unpacked`;
const fileIndexToModulePackageData = new Array(files.length);
if (_this3.options.smartUnpack !== false) {
yield _this3.detectUnpackedDirs(files, metadata, autoUnpackDirs, createDirPromises, unpackedDest, fileIndexToModulePackageData);
}
const unpackDir = _this3.options.unpackDir == null ? null : new (_minimatch || _load_minimatch()).Minimatch(_this3.options.unpackDir);
const unpack = _this3.options.unpack == null ? null : new (_minimatch || _load_minimatch()).Minimatch(_this3.options.unpack, {
matchBase: true
});
const copyPromises = [];
const mainPackageJson = (_path || _load_path()).join(_this3.src, "package.json");
for (let i = 0, n = files.length; i < n; i++) {
const file = files[i];
const stat = metadata.get(file);
if (stat.isFile()) {
const fileParent = (_path || _load_path()).dirname(file);
const dirNode = _this3.fs.searchNodeFromPath(fileParent);
if (dirNode.unpacked && createDirPromises.length > 0) {
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(createDirPromises);
createDirPromises.length = 0;
}
const packageDataPromise = fileIndexToModulePackageData[i];
let newData = null;
if (packageDataPromise == null) {
if (_this3.options.extraMetadata != null && file === mainPackageJson) {
newData = JSON.stringify((0, (_deepAssign || _load_deepAssign()).deepAssign)((yield (0, (_fsExtraP || _load_fsExtraP()).readJson)(file)), _this3.options.extraMetadata), null, 2);
}
} else {
newData = cleanupPackageJson(packageDataPromise.value());
}
const fileSize = newData == null ? stat.size : Buffer.byteLength(newData);
const node = _this3.fs.searchNodeFromPath(file);
node.size = fileSize;
if (dirNode.unpacked || unpack != null && unpack.match(file)) {
node.unpacked = true;
if (!dirNode.unpacked) {
createDirPromises.push((0, (_fsExtraP || _load_fsExtraP()).ensureDir)((_path || _load_path()).join(unpackedDest, (_path || _load_path()).relative(_this3.src, fileParent))));
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(createDirPromises);
createDirPromises.length = 0;
}
const unpackedFile = (_path || _load_path()).join(unpackedDest, (_path || _load_path()).relative(_this3.src, file));
copyPromises.push(newData == null ? copyFile(file, unpackedFile, stat) : (0, (_fsExtraP || _load_fsExtraP()).writeFile)(unpackedFile, newData));
if (copyPromises.length > MAX_FILE_REQUESTS) {
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(copyPromises);
copyPromises.length = 0;
}
} else {
if (newData != null) {
_this3.changedFiles.set(file, newData);
}
if (fileSize > 4294967295) {
throw new Error(`${ file }: file size can not be larger than 4.2GB`);
}
node.offset = _this3.fs.offset.toString();
//noinspection JSBitwiseOperatorUsage
if (process.platform !== "win32" && stat.mode & 0x40) {
node.executable = true;
}
_this3.toPack.push(file);
_this3.fs.offset.add(UINT64(fileSize));
}
} else if (stat.isDirectory()) {
let unpacked = false;
if (autoUnpackDirs.has(file)) {
unpacked = true;
} else {
unpacked = unpackDir != null && isUnpackDir((_path || _load_path()).relative(_this3.src, file), unpackDir, _this3.options.unpackDir);
if (unpacked) {
createDirPromises.push((0, (_fsExtraP || _load_fsExtraP()).ensureDir)((_path || _load_path()).join(unpackedDest, (_path || _load_path()).relative(_this3.src, file))));
} else {
for (let d of autoUnpackDirs) {
if (file.length > d.length + 2 && file[d.length] === (_path || _load_path()).sep && file.startsWith(d)) {
unpacked = true;
autoUnpackDirs.add(file);
// not all dirs marked as unpacked after first iteration - because node module dir can be marked as unpacked after processing node module dir content
// e.g. node-notifier/example/advanced.js processed, but only on process vendor/terminal-notifier.app module will be marked as unpacked
createDirPromises.push((0, (_fsExtraP || _load_fsExtraP()).ensureDir)((_path || _load_path()).join(unpackedDest, (_path || _load_path()).relative(_this3.src, file))));
break;
}
}
}
}
_this3.fs.insertDirectory(file, unpacked);
} else if (stat.isSymbolicLink()) {
yield _this3.addLink(file);
}
}
yield (_bluebirdLstC2 || _load_bluebirdLstC2()).default.all(copyPromises);
})();
}
addLink(file) {
var _this4 = this;
return (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* () {
const realFile = yield (0, (_fsExtraP || _load_fsExtraP()).realpath)(file);
const link = (_path || _load_path()).relative((yield _this4.getSrcRealPath()), realFile);
if (link.startsWith("..")) {
throw new Error(realFile + ": file links out of the package");
} else {
_this4.fs.searchNodeFromPath(file).link = link;
}
})();
}
writeAsarFile() {
const headerPickle = pickle.createEmpty();
headerPickle.writeString(JSON.stringify(this.fs.header));
const headerBuf = headerPickle.toBuffer();
const sizePickle = pickle.createEmpty();
sizePickle.writeUInt32(headerBuf.length);
const sizeBuf = sizePickle.toBuffer();
const writeStream = (0, (_fsExtraP || _load_fsExtraP()).createWriteStream)(this.outFile);
return new (_bluebirdLstC2 || _load_bluebirdLstC2()).default((resolve, reject) => {
writeStream.on("error", reject);
writeStream.once("finish", resolve);
writeStream.write(sizeBuf);
let w;
w = (list, index) => {
if (list.length === index) {
writeStream.end();
return;
}
const file = list[index];
const data = this.changedFiles.get(file);
if (data != null) {
writeStream.write(data, () => w(list, index + 1));
return;
}
const readStream = (0, (_fsExtraP || _load_fsExtraP()).createReadStream)(file);
readStream.on("error", reject);
readStream.once("end", () => w(list, index + 1));
readStream.pipe(writeStream, {
end: false
});
};
writeStream.write(headerBuf, () => w(this.toPack, 0));
});
}
order(filenames) {
var _this5 = this;
return (0, (_bluebirdLstC || _load_bluebirdLstC()).coroutine)(function* () {
const orderingFiles = (yield (0, (_fsExtraP || _load_fsExtraP()).readFile)(_this5.options.ordering, "utf8")).split("\n").map(function (line) {
if (line.indexOf(":") !== -1) {
line = line.split(":").pop();
}
line = line.trim();
if (line[0] === "/") {
line = line.slice(1);
}
return line;
});
const ordering = [];
for (let file of orderingFiles) {
let pathComponents = file.split((_path || _load_path()).sep);
let str = _this5.src;
for (let pathComponent of pathComponents) {
str = (_path || _load_path()).join(str, pathComponent);
ordering.push(str);
}
}
const filenamesSorted = [];
let missing = 0;
const total = filenames.length;
for (let file of ordering) {
if (!(filenamesSorted.indexOf(file) !== -1) && filenames.indexOf(file) !== -1) {
filenamesSorted.push(file);
}
}
for (let file of filenames) {
if (!(filenamesSorted.indexOf(file) !== -1)) {
filenamesSorted.push(file);
missing += 1;
}
}
(0, (_log || _load_log()).log)(`Ordering file has ${ (total - missing) / total * 100 }% coverage.`);
return filenamesSorted;
})();
}
}
function cleanupPackageJson(data) {
try {
let changed = false;
for (let prop of Object.getOwnPropertyNames(data)) {
if (prop[0] === "_" || prop === "dist" || prop === "gitHead" || prop === "keywords") {
delete data[prop];
changed = true;
}
}
if (changed) {
return JSON.stringify(data, null, 2);
}
} catch (e) {
(0, (_util || _load_util()).debug)(e);
}
return null;
}
function copyFile(src, dest, stats) {
return new (_bluebirdLstC2 || _load_bluebirdLstC2()).default(function (resolve, reject) {
const readStream = (0, (_fsExtraP || _load_fsExtraP()).createReadStream)(src);
const writeStream = (0, (_fsExtraP || _load_fsExtraP()).createWriteStream)(dest, { mode: stats.mode });
readStream.on("error", reject);
writeStream.on("error", reject);
writeStream.on("open", function () {
readStream.pipe(writeStream);
});
writeStream.once("finish", resolve);
});
}
//# sourceMappingURL=asarUtil.js.map