vrrv-installer-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
260 lines (258 loc) • 10 kB
JavaScript
;
const child_process_1 = require("child_process");
const bluebird_1 = require("bluebird");
const os_1 = require("os");
const path = require("path");
const fs_extra_p_1 = require("fs-extra-p");
const chalk_1 = require("chalk");
const debugFactory = require("debug");
const log_1 = require("./log");
const crypto_1 = require("crypto");
//noinspection JSUnusedLocalSymbols
const __awaiter = require("./awaiter");
exports.debug = debugFactory("electron-builder");
exports.debug7z = debugFactory("electron-builder:7z");
const DEFAULT_APP_DIR_NAMES = ["app", "www"];
function installDependencies(appDir, electronVersion) {
let arch = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : process.arch;
let command = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "install";
return log_1.task(`${ command === "install" ? "Installing" : "Rebuilding" } app dependencies for arch ${ arch } to ${ appDir }`, spawnNpmProduction(command, appDir, getGypEnv(electronVersion, arch)));
}
exports.installDependencies = installDependencies;
function getGypEnv(electronVersion, arch) {
const gypHome = path.join(os_1.homedir(), ".electron-gyp");
return Object.assign({}, process.env, {
npm_config_disturl: "https://atom.io/download/atom-shell",
npm_config_target: electronVersion,
npm_config_runtime: "electron",
npm_config_arch: arch,
HOME: gypHome,
USERPROFILE: gypHome
});
}
exports.getGypEnv = getGypEnv;
function spawnNpmProduction(command, appDir, env) {
let npmExecPath = process.env.npm_execpath || process.env.NPM_CLI_JS;
const npmExecArgs = [command, "--production", "--build-from-source", "--cache-min", "999999999"];
if (npmExecPath == null) {
npmExecPath = process.platform === "win32" ? "npm.cmd" : "npm";
} else {
npmExecArgs.unshift(npmExecPath);
npmExecPath = process.env.npm_node_execpath || process.env.NODE_EXE || "node";
}
return spawn(npmExecPath, npmExecArgs, {
cwd: appDir,
env: env || process.env
});
}
exports.spawnNpmProduction = spawnNpmProduction;
function removePassword(input) {
return input.replace(/(-P |pass:|\/p|-pass )([^ ]+)/, function (match, p1, p2) {
return `${ p1 }${ crypto_1.createHash("sha256").update(p2).digest("hex") } (sha256 hash)`;
});
}
exports.removePassword = removePassword;
function exec(file, args, options) {
if (exports.debug.enabled) {
exports.debug(`Executing ${ file } ${ args == null ? "" : removePassword(args.join(" ")) }`);
}
return new bluebird_1.Promise((resolve, reject) => {
child_process_1.execFile(file, args, options, function (error, stdout, stderr) {
if (error == null) {
if (exports.debug.enabled) {
if (stderr.length !== 0) {
log_1.log(stderr);
}
}
resolve(stdout);
} else {
let message = chalk_1.red(removePassword(`Exit code: ${ error.code }. ${ error.message }`));
if (stdout.length !== 0) {
message += `\n${ chalk_1.yellow(stdout) }`;
}
if (stderr.length !== 0) {
message += `\n${ chalk_1.red(stderr) }`;
}
reject(new Error(message));
}
});
});
}
exports.exec = exec;
function doSpawn(command, args, options, pipeInput) {
if (options == null) {
options = {};
}
if (options.stdio == null) {
options.stdio = [pipeInput ? "pipe" : "ignore", exports.debug.enabled ? "inherit" : "pipe", "pipe"];
}
if (exports.debug.enabled) {
exports.debug(`Spawning ${ command } ${ removePassword(args.join(" ")) }`);
}
return child_process_1.spawn(command, args, options);
}
exports.doSpawn = doSpawn;
function spawn(command, args, options) {
return new bluebird_1.Promise((resolve, reject) => {
handleProcess("close", doSpawn(command, args || [], options), command, resolve, reject);
});
}
exports.spawn = spawn;
function handleProcess(event, childProcess, command, resolve, reject) {
childProcess.on("error", reject);
let out = "";
if (!exports.debug.enabled && childProcess.stdout != null) {
childProcess.stdout.on("data", data => {
out += data;
});
}
let errorOut = "";
if (childProcess.stderr != null) {
childProcess.stderr.on("data", data => {
errorOut += data;
});
}
childProcess.once(event, code => {
if (code === 0 && exports.debug.enabled) {
exports.debug(`${ command } (${ childProcess.pid }) exited with code ${ code }`);
}
if (code !== 0) {
function formatOut(text, title) {
if (text.length === 0) {
return "";
} else {
return `\n${ title }:\n${ text }`;
}
}
reject(new Error(`${ command } exited with code ${ code }${ formatOut(out, "Output") }${ formatOut(errorOut, "Error output") }`));
} else if (resolve != null) {
resolve();
}
});
}
exports.handleProcess = handleProcess;
function getElectronVersion(packageData, packageJsonPath) {
return __awaiter(this, void 0, void 0, function* () {
const build = packageData.build;
// build is required, but this check is performed later, so, we should check for null
if (build != null && build.electronVersion != null) {
return build.electronVersion;
}
for (let name of ["electron", "electron-prebuilt", "electron-prebuilt-compile"]) {
try {
return (yield fs_extra_p_1.readJson(path.join(path.dirname(packageJsonPath), "node_modules", name, "package.json"))).version;
} catch (e) {
if (e.code !== "ENOENT") {
log_1.warn(`Cannot read electron version from ${ name } package.json: ${ e.message }`);
}
}
}
const electronPrebuiltDep = findFromElectronPrebuilt(packageData);
if (electronPrebuiltDep == null) {
throw new Error("Cannot find electron dependency to get electron version in the '" + packageJsonPath + "'");
}
const firstChar = electronPrebuiltDep[0];
return firstChar === "^" || firstChar === "~" ? electronPrebuiltDep.substring(1) : electronPrebuiltDep;
});
}
exports.getElectronVersion = getElectronVersion;
function findFromElectronPrebuilt(packageData) {
for (let name of ["electron", "electron-prebuilt", "electron-prebuilt-compile"]) {
const devDependencies = packageData.devDependencies;
let dep = devDependencies == null ? null : devDependencies[name];
if (dep == null) {
const dependencies = packageData.dependencies;
dep = dependencies == null ? null : dependencies[name];
}
if (dep != null) {
return dep;
}
}
return null;
}
function statOrNull(file) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield fs_extra_p_1.stat(file);
} catch (e) {
if (e.code === "ENOENT") {
return null;
} else {
throw e;
}
}
});
}
exports.statOrNull = statOrNull;
function computeDefaultAppDirectory(projectDir, userAppDir) {
return __awaiter(this, void 0, void 0, function* () {
if (userAppDir != null) {
const absolutePath = path.resolve(projectDir, userAppDir);
const stat = yield statOrNull(absolutePath);
if (stat == null) {
throw new Error(`Application directory ${ userAppDir } doesn't exists`);
} else if (!stat.isDirectory()) {
throw new Error(`Application directory ${ userAppDir } is not a directory`);
} else if (projectDir === absolutePath) {
log_1.warn(`Specified application directory "${ userAppDir }" equals to project dir — superfluous or wrong configuration`);
}
return absolutePath;
}
for (let dir of DEFAULT_APP_DIR_NAMES) {
const absolutePath = path.join(projectDir, dir);
const packageJson = path.join(absolutePath, "package.json");
const stat = yield statOrNull(packageJson);
if (stat != null && stat.isFile()) {
return absolutePath;
}
}
return projectDir;
});
}
exports.computeDefaultAppDirectory = computeDefaultAppDirectory;
function use(value, task) {
return value == null ? null : task(value);
}
exports.use = use;
function debug7zArgs(command) {
const args = [command, "-bd"];
if (exports.debug7z.enabled) {
args.push("-bb3");
} else if (!exports.debug.enabled) {
args.push("-bb0");
}
return args;
}
exports.debug7zArgs = debug7zArgs;
let tmpDirCounter = 0;
// add date to avoid use stale temp dir
const tempDirPrefix = `${ process.pid.toString(16) }-${ Date.now().toString(16) }`;
function getTempName(prefix) {
return `${ prefix == null ? "" : `${ prefix }-` }${ tempDirPrefix }-${ (tmpDirCounter++).toString(16) }`;
}
exports.getTempName = getTempName;
function isEmptyOrSpaces(s) {
return s == null || s.trim().length === 0;
}
exports.isEmptyOrSpaces = isEmptyOrSpaces;
function unlinkIfExists(file) {
return fs_extra_p_1.unlink(file).catch(() => {
// ignore
});
}
exports.unlinkIfExists = unlinkIfExists;
function asArray(v) {
if (v == null) {
return [];
} else if (Array.isArray(v)) {
return v;
} else {
return [v];
}
}
exports.asArray = asArray;
function isCi() {
return (process.env.CI || "").toLowerCase() === "true";
}
exports.isCi = isCi;
//# sourceMappingURL=util.js.map