diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee index 8b6f7ffd0d30..7d7feea7ac95 100644 --- a/atom/browser/api/lib/auto-updater.coffee +++ b/atom/browser/api/lib/auto-updater.coffee @@ -1,4 +1,9 @@ -autoUpdater = process.atomBinding('auto_updater').autoUpdater +switch process.platform + when 'darwin' + autoUpdater = process.atomBinding('auto_updater').autoUpdater + when 'win32' + autoUpdater = require('./auto-updater-win') + EventEmitter = require('events').EventEmitter autoUpdater.__proto__ = EventEmitter.prototype diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee new file mode 100644 index 000000000000..043d4c7c419f --- /dev/null +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -0,0 +1,60 @@ +{EventEmitter} = require 'events' +SquirrelUpdate = require './auto-updater/squirrel-update-win' + +class AutoUpdater + @__proto__ = EventEmitter.prototype + + quitAndInstall: -> + # TODO + + setFeedUrl: (@updateUrl) -> + + checkForUpdates: -> + throw new Error('Update URL is not set') unless @updateUrl + + @emit 'checking-for-update' + + unless SquirrelUpdate.existsSync() + @emit 'update-not-available' + return + + @downloadUpdate (error, update) => + if error? + @emit 'update-not-available' + return + + unless update? + @emit 'update-not-available' + return + + @emit 'update-available' + + @installUpdate (error) => + if error? + @emit 'update-not-available' + return + + @emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), @updateUrl, => @quitAndInstall() + + downloadUpdate: (callback) -> + SquirrelUpdate.spawn ['--download', @updateUrl], (error, stdout) -> + return callback(error) if error? + + try + # Last line of output is the JSON details about the releases + json = stdout.trim().split('\n').pop() + update = JSON.parse(json)?.releasesToApply?.pop?() + catch error + error.stdout = stdout + return callback(error) + + callback(null, update) + + installUpdate: (callback) -> + SquirrelUpdate.spawn(['--update', @updateUrl], callback) + + supportsUpdates: -> + SquirrelUpdate.existsSync() + + +module.exports = new AutoUpdater() diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee new file mode 100644 index 000000000000..faaa907f679f --- /dev/null +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee @@ -0,0 +1,42 @@ +ChildProcess = require 'child_process' +fs = require 'fs' +path = require 'path' + +appFolder = path.resolve(process.execPath, '..') # i.e. my-app/app-0.1.13/ +rootApplicationFolder = path.resolve(appFolder, '..') # i.e. my-app/ +updateDotExe = path.join(rootApplicationFolder, 'Update.exe') +exeName = path.basename(process.execPath) + +# Spawn a command and invoke the callback when it completes with an error +# and the output from standard out. +spawn = (command, args, callback) -> + stdout = '' + + try + spawnedProcess = ChildProcess.spawn(command, args) + catch error + # Spawn can throw an error + process.nextTick -> callback?(error, stdout) + return + + spawnedProcess.stdout.on 'data', (data) -> stdout += data + + error = null + spawnedProcess.on 'error', (processError) -> error ?= processError + spawnedProcess.on 'close', (code, signal) -> + error ?= new Error("Command failed: #{signal ? code}") if code isnt 0 + error?.code ?= code + error?.stdout ?= stdout + callback?(error, stdout) + +# Spawn the Update.exe with the given arguments and invoke the callback when +# the command completes. +spawnUpdate = (args, callback) -> + spawn(updateDotExe, args, callback) + +# Exports +exports.spawn = spawnUpdate + +# Is the Update.exe installed with Atom? +exports.existsSync = -> + fs.accessSync(updateDotExe, fs.R_OK)