diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee index 8b6f7ffd0d30..c039bd12dc46 100644 --- a/atom/browser/api/lib/auto-updater.coffee +++ b/atom/browser/api/lib/auto-updater.coffee @@ -1,7 +1,11 @@ -autoUpdater = process.atomBinding('auto_updater').autoUpdater -EventEmitter = require('events').EventEmitter - -autoUpdater.__proto__ = EventEmitter.prototype +switch process.platform + when 'win32' + autoUpdater = require './auto-updater/auto-updater-win' + else + # take the default binding for the current platform + autoUpdater = process.atomBinding('auto_updater').autoUpdater + EventEmitter = require('events').EventEmitter + autoUpdater.__proto__ = EventEmitter.prototype autoUpdater.on 'update-downloaded-raw', (args...) -> args[3] = new Date(args[3]) # releaseDate 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..764f76a2253f --- /dev/null +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -0,0 +1,45 @@ +{EventEmitter} = require 'events' +SquirrelUpdate = require './auto-updater/squirrel-update-win' +app = require 'app' +url = require 'url' + +class AutoUpdater extends EventEmitter + + quitAndInstall: -> + SquirrelUpdate.processStart -> + app.quit() + + setFeedUrl: (updateUrl) -> + # set feed URL only when it hasn't been set before + unless @updateUrl + @updateUrl = updateUrl + + checkForUpdates: -> + throw new Error('Update URL is not set') unless @updateUrl + + @emit 'checking-for-update' + + unless SquirrelUpdate.supported() + @emit 'update-not-available' + return + + SquirrelUpdate.download (error, update) => + if error? + @emit 'update-not-available' + return + + unless update? + @emit 'update-not-available' + return + + @emit 'update-available' + + SquirrelUpdate.update @updateUrl, (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 + @emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), @updateUrl, => @quitAndInstall() + +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..95d9e1465d8a --- /dev/null +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee @@ -0,0 +1,57 @@ +ChildProcess = require 'child_process' +fs = require 'fs' +path = require 'path' + +appFolder = path.dirname 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. +spawnUpdate = (args, callback) -> + stdout = '' + + try + spawnedProcess = ChildProcess.spawn(updateDotExe, 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) + +processStart = (callback) -> + spawnUpdate(['--processStart', exeName], callback) + +download = (callback) -> + spawnUpdate ['--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) + +update = (updateUrl, callback) -> + spawnUpdate ['--update', updateUrl], callback + +# Is the Update.exe installed with the current application? +exports.supported = -> + fs.accessSync(updateDotExe, fs.R_OK) +exports.processStart = processStart +exports.download = download +exports.update = update diff --git a/filenames.gypi b/filenames.gypi index 1c52cf50b2ae..389c245ffa8a 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -11,6 +11,8 @@ 'atom/browser/api/lib/app.coffee', 'atom/browser/api/lib/atom-delegate.coffee', 'atom/browser/api/lib/auto-updater.coffee', + 'atom/browser/api/lib/auto-updater/auto-updater-win.coffee', + 'atom/browser/api/lib/auto-updater/squirrel-update-win.coffee', 'atom/browser/api/lib/browser-window.coffee', 'atom/browser/api/lib/content-tracing.coffee', 'atom/browser/api/lib/dialog.coffee',