win: Make auto-updater really work
Apparently that PR was never tested.
This commit is contained in:
parent
aeafc46ded
commit
fae2c7bc7a
2 changed files with 71 additions and 64 deletions
|
@ -1,45 +1,42 @@
|
||||||
|
app = require 'app'
|
||||||
|
url = require 'url'
|
||||||
{EventEmitter} = require 'events'
|
{EventEmitter} = require 'events'
|
||||||
SquirrelUpdate = require './auto-updater/squirrel-update-win'
|
|
||||||
app = require 'app'
|
squirrelUpdate = require './squirrel-update-win'
|
||||||
url = require 'url'
|
|
||||||
|
|
||||||
class AutoUpdater extends EventEmitter
|
class AutoUpdater extends EventEmitter
|
||||||
|
|
||||||
quitAndInstall: ->
|
quitAndInstall: ->
|
||||||
SquirrelUpdate.processStart ->
|
squirrelUpdate.processStart()
|
||||||
app.quit()
|
app.quit()
|
||||||
|
|
||||||
setFeedUrl: (updateUrl) ->
|
setFeedUrl: (updateUrl) ->
|
||||||
# set feed URL only when it hasn't been set before
|
@updateUrl = updateUrl
|
||||||
unless @updateUrl
|
|
||||||
@updateUrl = updateUrl
|
|
||||||
|
|
||||||
checkForUpdates: ->
|
checkForUpdates: ->
|
||||||
throw new Error('Update URL is not set') unless @updateUrl
|
return @emitError 'Update URL is not set' unless @updateUrl
|
||||||
|
return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported()
|
||||||
|
|
||||||
@emit 'checking-for-update'
|
@emit 'checking-for-update'
|
||||||
|
|
||||||
unless SquirrelUpdate.supported()
|
squirrelUpdate.download @updateUrl, (error, update) =>
|
||||||
@emit 'update-not-available'
|
return @emitError error if error?
|
||||||
return
|
return @emit 'update-not-available' unless update?
|
||||||
|
|
||||||
SquirrelUpdate.download (error, update) =>
|
|
||||||
if error?
|
|
||||||
@emit 'update-not-available'
|
|
||||||
return
|
|
||||||
|
|
||||||
unless update?
|
|
||||||
@emit 'update-not-available'
|
|
||||||
return
|
|
||||||
|
|
||||||
@emit 'update-available'
|
@emit 'update-available'
|
||||||
|
|
||||||
SquirrelUpdate.update @updateUrl, (error) =>
|
squirrelUpdate.update @updateUrl, (error) =>
|
||||||
if error?
|
return @emitError error if error?
|
||||||
@emit 'update-not-available'
|
|
||||||
return
|
|
||||||
|
|
||||||
# info about the newly installed version and a function any of the event listeners can call to restart the application
|
{releaseNotes, version} = update
|
||||||
@emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), @updateUrl, => @quitAndInstall()
|
# Following information is not available on Windows, so fake them.
|
||||||
|
date = new Date
|
||||||
|
url = @updateUrl
|
||||||
|
|
||||||
module.exports = new AutoUpdater()
|
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
|
||||||
|
|
||||||
|
# Private: Emit both error object and message, this is to keep compatibility
|
||||||
|
# with Old APIs.
|
||||||
|
emitError: (message) ->
|
||||||
|
@emit 'error', new Error(message), message
|
||||||
|
|
||||||
|
module.exports = new AutoUpdater
|
||||||
|
|
|
@ -1,57 +1,67 @@
|
||||||
ChildProcess = require 'child_process'
|
fs = require 'fs'
|
||||||
fs = require 'fs'
|
path = require 'path'
|
||||||
path = require 'path'
|
{spawn} = require 'child_process'
|
||||||
|
|
||||||
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
|
||||||
rootApplicationFolder = path.resolve appFolder, '..' # i.e. my-app/
|
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
|
||||||
updateDotExe = path.join rootApplicationFolder, 'Update.exe'
|
exeName = path.basename process.execPath
|
||||||
exeName = path.basename process.execPath
|
|
||||||
|
|
||||||
# Spawn a command and invoke the callback when it completes with an error
|
# Spawn a command and invoke the callback when it completes with an error
|
||||||
# and the output from standard out.
|
# and the output from standard out.
|
||||||
spawnUpdate = (args, callback) ->
|
spawnUpdate = (args, detached, callback) ->
|
||||||
stdout = ''
|
|
||||||
|
|
||||||
try
|
try
|
||||||
spawnedProcess = ChildProcess.spawn(updateDotExe, args)
|
spawnedProcess = spawn updateExe, args, {detached}
|
||||||
catch error
|
catch error
|
||||||
# Spawn can throw an error
|
# Shouldn't happen, but still guard it.
|
||||||
process.nextTick -> callback?(error, stdout)
|
process.nextTick -> callback error
|
||||||
return
|
return
|
||||||
|
|
||||||
|
stdout = ''
|
||||||
|
stderr = ''
|
||||||
spawnedProcess.stdout.on 'data', (data) -> stdout += data
|
spawnedProcess.stdout.on 'data', (data) -> stdout += data
|
||||||
|
spawnedProcess.stderr.on 'data', (data) -> stderr += data
|
||||||
|
|
||||||
error = null
|
errorEmitted = false
|
||||||
spawnedProcess.on 'error', (processError) -> error ?= processError
|
spawnedProcess.on 'error', (error) ->
|
||||||
spawnedProcess.on 'close', (code, signal) ->
|
errorEmitted = true
|
||||||
error ?= new Error("Command failed: #{signal ? code}") if code isnt 0
|
callback error
|
||||||
error?.code ?= code
|
spawnedProcess.on 'exit', (code, signal) ->
|
||||||
error?.stdout ?= stdout
|
# We may have already emitted an error.
|
||||||
callback?(error, stdout)
|
return if errorEmitted
|
||||||
|
|
||||||
processStart = (callback) ->
|
# Process terminated with error.
|
||||||
spawnUpdate(['--processStart', exeName], callback)
|
if code isnt 0
|
||||||
|
return callback "Command failed: #{signal ? code}\n#{stderr}"
|
||||||
|
|
||||||
download = (callback) ->
|
# Success.
|
||||||
spawnUpdate ['--download', @updateUrl], (error, stdout) ->
|
callback null, stdout
|
||||||
|
|
||||||
|
# Start an instance of the installed app.
|
||||||
|
exports.processStart = (callback) ->
|
||||||
|
spawnUpdate ['--processStart', exeName], true, ->
|
||||||
|
|
||||||
|
# Download the releases specified by the URL and write new results to stdout.
|
||||||
|
exports.download = (updateUrl, callback) ->
|
||||||
|
spawnUpdate ['--download', updateUrl], false, (error, stdout) ->
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
|
|
||||||
try
|
try
|
||||||
# Last line of output is the JSON details about the releases
|
# Last line of output is the JSON details about the releases
|
||||||
json = stdout.trim().split('\n').pop()
|
json = stdout.trim().split('\n').pop()
|
||||||
update = JSON.parse(json)?.releasesToApply?.pop?()
|
update = JSON.parse(json)?.releasesToApply?.pop?()
|
||||||
catch error
|
catch
|
||||||
error.stdout = stdout
|
return callback "Invalid result:\n#{stdout}"
|
||||||
return callback(error)
|
|
||||||
|
|
||||||
callback(null, update)
|
callback null, update
|
||||||
|
|
||||||
update = (updateUrl, callback) ->
|
# Update the application to the latest remote version specified by URL.
|
||||||
spawnUpdate ['--update', updateUrl], callback
|
exports.update = (updateUrl, callback) ->
|
||||||
|
spawnUpdate ['--update', updateUrl], false, callback
|
||||||
|
|
||||||
# Is the Update.exe installed with the current application?
|
# Is the Update.exe installed with the current application?
|
||||||
exports.supported = ->
|
exports.supported = ->
|
||||||
fs.accessSync(updateDotExe, fs.R_OK)
|
try
|
||||||
exports.processStart = processStart
|
fs.accessSync updateExe, fs.R_OK
|
||||||
exports.download = download
|
return true
|
||||||
exports.update = update
|
catch
|
||||||
|
return false
|
||||||
|
|
Loading…
Reference in a new issue