electron/lib/browser/api/auto-updater/squirrel-update-win.js

120 lines
3.7 KiB
JavaScript
Raw Normal View History

2020-03-20 20:28:31 +00:00
'use strict';
2020-03-20 20:28:31 +00:00
const fs = require('fs');
const path = require('path');
const spawn = require('child_process').spawn;
2016-01-12 02:40:23 +00:00
2016-01-14 18:35:29 +00:00
// i.e. my-app/app-0.1.13/
2020-03-20 20:28:31 +00:00
const appFolder = path.dirname(process.execPath);
2016-01-12 02:40:23 +00:00
2016-01-14 18:35:29 +00:00
// i.e. my-app/Update.exe
2020-03-20 20:28:31 +00:00
const updateExe = path.resolve(appFolder, '..', 'Update.exe');
const exeName = path.basename(process.execPath);
let spawnedArgs = [];
let spawnedProcess;
2020-03-20 20:28:31 +00:00
const isSameArgs = (args) => args.length === spawnedArgs.length && args.every((e, i) => e === spawnedArgs[i]);
2016-01-12 02:40:23 +00:00
2016-01-14 18:44:21 +00:00
// Spawn a command and invoke the callback when it completes with an error
// and the output from standard out.
const spawnUpdate = function (args, detached, callback) {
2020-03-20 20:28:31 +00:00
let error, errorEmitted, stderr, stdout;
2016-01-12 02:40:23 +00:00
try {
// Ensure we don't spawn multiple squirrel processes
// Process spawned, same args: Attach events to alread running process
// Process spawned, different args: Return with error
// No process spawned: Spawn new process
if (spawnedProcess && !isSameArgs(args)) {
// Disabled for backwards compatibility:
// eslint-disable-next-line standard/no-callback-literal
2020-03-20 20:28:31 +00:00
return callback(`AutoUpdater process with arguments ${args} is already running`);
} else if (!spawnedProcess) {
spawnedProcess = spawn(updateExe, args, {
2017-12-02 01:18:37 +00:00
detached: detached,
windowsHide: true
2020-03-20 20:28:31 +00:00
});
spawnedArgs = args || [];
}
2016-01-12 02:40:23 +00:00
} catch (error1) {
2020-03-20 20:28:31 +00:00
error = error1;
2016-01-12 02:40:23 +00:00
2016-01-14 18:35:29 +00:00
// Shouldn't happen, but still guard it.
process.nextTick(function () {
2020-03-20 20:28:31 +00:00
return callback(error);
});
return;
2016-01-12 02:40:23 +00:00
}
2020-03-20 20:28:31 +00:00
stdout = '';
stderr = '';
2020-03-20 20:28:31 +00:00
spawnedProcess.stdout.on('data', (data) => { stdout += data; });
spawnedProcess.stderr.on('data', (data) => { stderr += data; });
2020-03-20 20:28:31 +00:00
errorEmitted = false;
spawnedProcess.on('error', (error) => {
2020-03-20 20:28:31 +00:00
errorEmitted = true;
callback(error);
});
return spawnedProcess.on('exit', function (code, signal) {
2020-03-20 20:28:31 +00:00
spawnedProcess = undefined;
spawnedArgs = [];
2016-01-14 18:35:29 +00:00
// We may have already emitted an error.
2016-01-12 02:40:23 +00:00
if (errorEmitted) {
2020-03-20 20:28:31 +00:00
return;
2016-01-12 02:40:23 +00:00
}
2016-01-14 18:35:29 +00:00
// Process terminated with error.
2016-01-12 02:40:23 +00:00
if (code !== 0) {
// Disabled for backwards compatibility:
// eslint-disable-next-line standard/no-callback-literal
2020-03-20 20:28:31 +00:00
return callback(`Command failed: ${signal != null ? signal : code}\n${stderr}`);
2016-01-12 02:40:23 +00:00
}
2016-01-14 18:35:29 +00:00
// Success.
2020-03-20 20:28:31 +00:00
callback(null, stdout);
});
};
2016-01-12 02:40:23 +00:00
2016-01-14 18:35:29 +00:00
// Start an instance of the installed app.
exports.processStart = function () {
2020-03-20 20:28:31 +00:00
return spawnUpdate(['--processStartAndWait', exeName], true, function () {});
};
2016-01-12 02:40:23 +00:00
2016-01-14 18:35:29 +00:00
// Download the releases specified by the URL and write new results to stdout.
exports.checkForUpdate = function (updateURL, callback) {
return spawnUpdate(['--checkForUpdate', updateURL], false, function (error, stdout) {
2020-03-20 20:28:31 +00:00
let ref, ref1, update;
2016-01-12 02:40:23 +00:00
if (error != null) {
2020-03-20 20:28:31 +00:00
return callback(error);
2016-01-12 02:40:23 +00:00
}
try {
2016-01-14 18:35:29 +00:00
// Last line of output is the JSON details about the releases
2020-03-20 20:28:31 +00:00
const json = stdout.trim().split('\n').pop();
update = (ref = JSON.parse(json)) != null ? (ref1 = ref.releasesToApply) != null ? typeof ref1.pop === 'function' ? ref1.pop() : undefined : undefined : undefined;
} catch {
// Disabled for backwards compatibility:
// eslint-disable-next-line standard/no-callback-literal
2020-03-20 20:28:31 +00:00
return callback(`Invalid result:\n${stdout}`);
2016-01-12 02:40:23 +00:00
}
2020-03-20 20:28:31 +00:00
return callback(null, update);
});
};
2016-01-12 02:40:23 +00:00
2016-01-14 18:35:29 +00:00
// Update the application to the latest remote version specified by URL.
exports.update = function (updateURL, callback) {
2020-03-20 20:28:31 +00:00
return spawnUpdate(['--update', updateURL], false, callback);
};
2016-01-12 02:40:23 +00:00
2016-01-14 18:35:29 +00:00
// Is the Update.exe installed with the current application?
exports.supported = function () {
2016-01-12 02:40:23 +00:00
try {
2020-03-20 20:28:31 +00:00
fs.accessSync(updateExe, fs.R_OK);
return true;
} catch {
2020-03-20 20:28:31 +00:00
return false;
2016-01-12 02:40:23 +00:00
}
2020-03-20 20:28:31 +00:00
};