From 621178f5588d36336dd7adb0fbda70b2e8b62ec5 Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Mon, 15 Jun 2015 20:28:47 +0200 Subject: [PATCH 1/9] initial idea --- atom/browser/api/lib/auto-updater.coffee | 7 ++- .../lib/auto-updater/auto-updater-win.coffee | 60 +++++++++++++++++++ .../auto-updater/squirrel-update-win.coffee | 42 +++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 atom/browser/api/lib/auto-updater/auto-updater-win.coffee create mode 100644 atom/browser/api/lib/auto-updater/squirrel-update-win.coffee 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) From 99f352228c62100069df90146536faea82edd981 Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Tue, 16 Jun 2015 11:04:37 +0200 Subject: [PATCH 2/9] addresses suggestions from pull-request --- atom/browser/api/lib/auto-updater.coffee | 7 ++++--- atom/browser/api/lib/auto-updater/auto-updater-win.coffee | 5 ++++- .../api/lib/auto-updater/squirrel-update-win.coffee | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee index 7d7feea7ac95..0b7e84ba7efe 100644 --- a/atom/browser/api/lib/auto-updater.coffee +++ b/atom/browser/api/lib/auto-updater.coffee @@ -1,8 +1,9 @@ switch process.platform - when 'darwin' - autoUpdater = process.atomBinding('auto_updater').autoUpdater when 'win32' - autoUpdater = require('./auto-updater-win') + autoUpdater = require('./auto-updater/auto-updater-win') + default + # take the default binding for the current platform + autoUpdater = process.atomBinding('auto_updater').autoUpdater EventEmitter = require('events').EventEmitter diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee index 043d4c7c419f..556b86cbc95e 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -7,7 +7,10 @@ class AutoUpdater quitAndInstall: -> # TODO - setFeedUrl: (@updateUrl) -> + 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 diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee index faaa907f679f..d57a0130784e 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee @@ -2,8 +2,8 @@ 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/ +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) From 7aa60baafb0749075ac33ff77dc183f2e0bc91cc Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Tue, 16 Jun 2015 11:48:39 +0200 Subject: [PATCH 3/9] switch statement coffee else instead of default --- atom/browser/api/lib/auto-updater.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee index 0b7e84ba7efe..1b6c935f34b6 100644 --- a/atom/browser/api/lib/auto-updater.coffee +++ b/atom/browser/api/lib/auto-updater.coffee @@ -1,7 +1,7 @@ switch process.platform when 'win32' autoUpdater = require('./auto-updater/auto-updater-win') - default + else # take the default binding for the current platform autoUpdater = process.atomBinding('auto_updater').autoUpdater From a8469fc79d4f5c87c7d6f2b1e1b877fccd9c2500 Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Tue, 16 Jun 2015 12:31:55 +0200 Subject: [PATCH 4/9] auto-updater extends event-emitter --- atom/browser/api/lib/auto-updater/auto-updater-win.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee index 556b86cbc95e..1f9fcd185fc1 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -1,8 +1,7 @@ {EventEmitter} = require 'events' SquirrelUpdate = require './auto-updater/squirrel-update-win' -class AutoUpdater - @__proto__ = EventEmitter.prototype +class AutoUpdater extends EventEmitter quitAndInstall: -> # TODO From 62882fe49e6910710b17cb186192fdf67df5544d Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Tue, 16 Jun 2015 16:13:23 +0200 Subject: [PATCH 5/9] auto updater win is an EventEmitter already --- atom/browser/api/lib/auto-updater.coffee | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee index 1b6c935f34b6..a479f5fccfe5 100644 --- a/atom/browser/api/lib/auto-updater.coffee +++ b/atom/browser/api/lib/auto-updater.coffee @@ -3,11 +3,9 @@ switch process.platform 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 = 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 From ae5411c37b9c712e0a6b973eaf729753cd21e7c1 Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Mon, 22 Jun 2015 15:16:50 +0200 Subject: [PATCH 6/9] move squirrel bahaviour into proper place --- .../lib/auto-updater/auto-updater-win.coffee | 23 ++++-------- .../auto-updater/squirrel-update-win.coffee | 35 +++++++++++++------ 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee index 1f9fcd185fc1..a3fbd8822ada 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -1,10 +1,12 @@ {EventEmitter} = require 'events' SquirrelUpdate = require './auto-updater/squirrel-update-win' +app = require('app') class AutoUpdater extends EventEmitter quitAndInstall: -> - # TODO + SquirrelUpdate.processStart -> + app.quit() setFeedUrl: (updateUrl) -> # set feed URL only when it hasn't been set before @@ -36,27 +38,16 @@ class AutoUpdater extends EventEmitter @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() 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) + SquirrelUpdate.download(callback) installUpdate: (callback) -> - SquirrelUpdate.spawn(['--update', @updateUrl], callback) + SquirrelUpdate.update(@updateUrl, callback) supportsUpdates: -> - SquirrelUpdate.existsSync() - + SquirrelUpdate.supported() 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 index d57a0130784e..f07584f4c54d 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee @@ -9,11 +9,11 @@ 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) -> +spawnUpdate = (args, callback) -> stdout = '' try - spawnedProcess = ChildProcess.spawn(command, args) + spawnedProcess = ChildProcess.spawn(updateDotExe, args) catch error # Spawn can throw an error process.nextTick -> callback?(error, stdout) @@ -29,14 +29,29 @@ spawn = (command, args, callback) -> 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) +processStart = (callback) -> + spawnUpdate(['--processStart', exeName], callback) -# Exports -exports.spawn = spawnUpdate +download = (callback) -> + spawnUpdate ['--download', @updateUrl], (error, stdout) -> + return callback(error) if error? -# Is the Update.exe installed with Atom? -exports.existsSync = -> + 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 From 154ca8575ca450405307958004e5c862a7cdda10 Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Mon, 22 Jun 2015 15:33:08 +0200 Subject: [PATCH 7/9] limit the auto-updater-win api to very few methods --- .../api/lib/auto-updater/auto-updater-win.coffee | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee index a3fbd8822ada..2da37ddb035e 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -18,11 +18,11 @@ class AutoUpdater extends EventEmitter @emit 'checking-for-update' - unless SquirrelUpdate.existsSync() + unless SquirrelUpdate.supported() @emit 'update-not-available' return - @downloadUpdate (error, update) => + SquirrelUpdate.download (error, update) => if error? @emit 'update-not-available' return @@ -33,7 +33,7 @@ class AutoUpdater extends EventEmitter @emit 'update-available' - @installUpdate (error) => + SquirrelUpdate.update @updateUrl, (error) => if error? @emit 'update-not-available' return @@ -41,13 +41,4 @@ class AutoUpdater extends EventEmitter # 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() - downloadUpdate: (callback) -> - SquirrelUpdate.download(callback) - - installUpdate: (callback) -> - SquirrelUpdate.update(@updateUrl, callback) - - supportsUpdates: -> - SquirrelUpdate.supported() - module.exports = new AutoUpdater() From 6c4016af462d9f449b7f823ba80eb19f4511ef5e Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Mon, 22 Jun 2015 15:51:47 +0200 Subject: [PATCH 8/9] make sure the query params are stripped from the updateUrl --- .../api/lib/auto-updater/auto-updater-win.coffee | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee index 2da37ddb035e..9a2431577e0b 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -1,6 +1,7 @@ {EventEmitter} = require 'events' SquirrelUpdate = require './auto-updater/squirrel-update-win' app = require('app') +url = require('url') class AutoUpdater extends EventEmitter @@ -11,7 +12,14 @@ class AutoUpdater extends EventEmitter setFeedUrl: (updateUrl) -> # set feed URL only when it hasn't been set before unless @updateUrl - @updateUrl = updateUrl + # See https://github.com/Squirrel/Squirrel.Windows/issues/132 + # This way the Mac and Windows Update URL can be the same, even when + # the Mac version is sending additional data in the query string. + parsedUrl = url.parse(updateUrl) + delete parsedUrl.search + delete parsedUrl.query + + @updateUrl = url.format(parsedUrl) checkForUpdates: -> throw new Error('Update URL is not set') unless @updateUrl From db3bc289379840b466517abb0f16a8d2e349073f Mon Sep 17 00:00:00 2001 From: Patrick Detlefsen Date: Tue, 20 Oct 2015 19:25:03 +0200 Subject: [PATCH 9/9] PR feedback adressed --- atom/browser/api/lib/auto-updater.coffee | 2 +- .../api/lib/auto-updater/auto-updater-win.coffee | 13 +++---------- .../api/lib/auto-updater/squirrel-update-win.coffee | 8 ++++---- filenames.gypi | 2 ++ 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/atom/browser/api/lib/auto-updater.coffee b/atom/browser/api/lib/auto-updater.coffee index a479f5fccfe5..c039bd12dc46 100644 --- a/atom/browser/api/lib/auto-updater.coffee +++ b/atom/browser/api/lib/auto-updater.coffee @@ -1,6 +1,6 @@ switch process.platform when 'win32' - autoUpdater = require('./auto-updater/auto-updater-win') + autoUpdater = require './auto-updater/auto-updater-win' else # take the default binding for the current platform autoUpdater = process.atomBinding('auto_updater').autoUpdater diff --git a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee index 9a2431577e0b..764f76a2253f 100644 --- a/atom/browser/api/lib/auto-updater/auto-updater-win.coffee +++ b/atom/browser/api/lib/auto-updater/auto-updater-win.coffee @@ -1,7 +1,7 @@ {EventEmitter} = require 'events' SquirrelUpdate = require './auto-updater/squirrel-update-win' -app = require('app') -url = require('url') +app = require 'app' +url = require 'url' class AutoUpdater extends EventEmitter @@ -12,14 +12,7 @@ class AutoUpdater extends EventEmitter setFeedUrl: (updateUrl) -> # set feed URL only when it hasn't been set before unless @updateUrl - # See https://github.com/Squirrel/Squirrel.Windows/issues/132 - # This way the Mac and Windows Update URL can be the same, even when - # the Mac version is sending additional data in the query string. - parsedUrl = url.parse(updateUrl) - delete parsedUrl.search - delete parsedUrl.query - - @updateUrl = url.format(parsedUrl) + @updateUrl = updateUrl checkForUpdates: -> throw new Error('Update URL is not set') unless @updateUrl diff --git a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee index f07584f4c54d..95d9e1465d8a 100644 --- a/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee +++ b/atom/browser/api/lib/auto-updater/squirrel-update-win.coffee @@ -2,10 +2,10 @@ 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) +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. diff --git a/filenames.gypi b/filenames.gypi index ebd1fb41aaf2..35139dbdfcd5 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',