asarfuckery/appasar/stable/app_bootstrap/squirrelUpdate.js
2019-01-17 19:22:05 +01:00

224 lines
No EOL
7.3 KiB
JavaScript

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.spawnUpdateInstall = spawnUpdateInstall;
exports.spawnUpdate = spawnUpdate;
exports.handleStartupEvent = handleStartupEvent;
exports.updateExistsSync = updateExistsSync;
exports.restart = restart;
var _child_process = require('child_process');
var _child_process2 = _interopRequireDefault(_child_process);
var _fs = require('fs');
var _fs2 = _interopRequireDefault(_fs);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _autoStart = require('./autoStart');
var autoStart = _interopRequireWildcard(_autoStart);
var _windowsUtils = require('./windowsUtils');
var windowsUtils = _interopRequireWildcard(_windowsUtils);
var _singleInstance = require('./singleInstance');
var singleInstance = _interopRequireWildcard(_singleInstance);
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 }; }
// citron note: this assumes the execPath is in the format Discord/someVersion/Discord.exe
var appFolder = _path2.default.resolve(process.execPath, '..');
var rootFolder = _path2.default.resolve(appFolder, '..');
var exeName = _path2.default.basename(process.execPath);
var updateExe = _path2.default.join(rootFolder, 'Update.exe');
// Specialized spawn function specifically used for spawning the updater in
// update mode. Calls back with progress percentages.
// Returns Promise.
function spawnUpdateInstall(updateUrl, progressCallback) {
return new Promise(function (resolve, reject) {
var proc = _child_process2.default.spawn(updateExe, ['--update', updateUrl]);
proc.on('error', reject);
proc.on('exit', function (code) {
if (code !== 0) {
return reject(new Error('Update failed with exit code ' + code));
}
return resolve();
});
var lastProgress = -1;
function parseProgress() {
var lines = stdout.split(/\r?\n/);
if (lines.length === 1) return;
// return the last (possibly incomplete) line to stdout for parsing again
stdout = lines.pop();
var currentProgress = void 0;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = lines[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var line = _step.value;
if (!/^\d\d?$/.test(line)) continue;
var progress = Number(line);
// make sure that this number is steadily increasing
if (lastProgress > progress) continue;
currentProgress = progress;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (currentProgress == null) return;
lastProgress = currentProgress;
progressCallback(Math.min(currentProgress, 100));
}
var stdout = '';
proc.stdout.on('data', function (chunk) {
stdout += String(chunk);
parseProgress();
});
});
}
// Spawn the Update.exe with the given arguments and invoke the callback when
// the command completes.
function spawnUpdate(args, callback) {
windowsUtils.spawn(updateExe, args, callback);
}
// Create a desktop and start menu shortcut by using the command line API
// provided by Squirrel's Update.exe
function createShortcuts(callback, updateOnly) {
// move icon out to a more stable location, to keep shortcuts from breaking as much
var icoSrc = _path2.default.join(appFolder, 'app.ico');
var icoDest = _path2.default.join(rootFolder, 'app.ico');
var icoForTarget = icoDest;
try {
var ico = _fs2.default.readFileSync(icoSrc);
_fs2.default.writeFileSync(icoDest, ico);
} catch (e) {
// if we can't write there for some reason, just use the source.
icoForTarget = icoSrc;
}
var createShortcutArgs = ['--createShortcut', exeName, '--setupIcon', icoForTarget];
if (updateOnly) {
createShortcutArgs.push('--updateOnly');
}
spawnUpdate(createShortcutArgs, callback);
}
// Add a protocol registration for this application.
function installProtocol(protocol, callback) {
var queue = [['HKCU\\Software\\Classes\\' + protocol, '/ve', '/d', 'URL:' + protocol + ' Protocol'], ['HKCU\\Software\\Classes\\' + protocol, '/v', 'URL Protocol'], ['HKCU\\Software\\Classes\\' + protocol + '\\DefaultIcon', '/ve', '/d', '"' + process.execPath + '",-1'], ['HKCU\\Software\\Classes\\' + protocol + '\\shell\\open\\command', '/ve', '/d', '"' + process.execPath + '" --url -- "%1"']];
windowsUtils.addToRegistry(queue, callback);
}
function terminate(app) {
app.quit();
process.exit(0);
}
// Remove the desktop and start menu shortcuts by using the command line API
// provided by Squirrel's Update.exe
function removeShortcuts(callback) {
spawnUpdate(['--removeShortcut', exeName], callback);
}
// Update the desktop and start menu shortcuts by using the command line API
// provided by Squirrel's Update.exe
function updateShortcuts(callback) {
createShortcuts(callback, true);
}
// Purge the protocol for this applicationstart.
function uninstallProtocol(protocol, callback) {
windowsUtils.spawnReg(['delete', 'HKCU\\Software\\Classes\\' + protocol, '/f'], callback);
}
// Handle squirrel events denoted by --squirrel-* command line arguments.
// returns `true` if regular startup should be prevented
function handleStartupEvent(protocol, app, squirrelCommand) {
switch (squirrelCommand) {
case '--squirrel-install':
createShortcuts(function () {
autoStart.install(function () {
installProtocol(protocol, function () {
terminate(app);
});
});
}, false);
return true;
case '--squirrel-updated':
updateShortcuts(function () {
autoStart.update(function () {
installProtocol(protocol, function () {
terminate(app);
});
});
});
return true;
case '--squirrel-uninstall':
removeShortcuts(function () {
autoStart.uninstall(function () {
uninstallProtocol(protocol, function () {
singleInstance.pipeCommandLineArgs(function () {
return terminate(app);
}, function () {
return terminate(app);
});
});
});
});
return true;
case '--squirrel-obsolete':
terminate(app);
return true;
default:
return false;
}
}
// Are we using Squirrel for updates?
function updateExistsSync() {
return _fs2.default.existsSync(updateExe);
}
// Restart app as the new version
function restart(app, newVersion) {
app.once('will-quit', function () {
var execPath = _path2.default.resolve(rootFolder, 'app-' + newVersion + '/' + exeName);
_child_process2.default.spawn(execPath, [], { detached: true });
});
app.quit();
}