extract Windows registry operations from squirrel-update

This commit is contained in:
Giuseppe Piscopo
2016-04-21 03:25:09 +02:00
parent 77dcf37ee3
commit 63c45cc8fd
4 changed files with 83 additions and 59 deletions

View File

@@ -13,7 +13,7 @@ describe "Spawner", ->
else
originalSpawn('ls')
spyOn(ChildProcess, 'spawn').andCallFake (command, args, callback) ->
spyOn(ChildProcess, 'spawn').andCallFake (command, args, callback) ->
harmlessSpawn
it "invokes passed callback", ->

View File

@@ -4,8 +4,15 @@ path = require 'path'
temp = require 'temp'
SquirrelUpdate = require '../src/browser/squirrel-update'
Spawner = require '../src/browser/spawner'
WinRegistry = require '../src/browser/win-registry'
describe "Windows Squirrel Update", ->
# Run passed callback as Spawner.spawn() would do
invokeCallback = (callback) ->
error = null
stdout = ''
callback?(error, stdout)
fdescribe "Windows Squirrel Update", ->
tempHomeDirectory = null
beforeEach ->
@@ -14,10 +21,17 @@ describe "Windows Squirrel Update", ->
spyOn(fs, 'getHomeDirectory').andReturn(tempHomeDirectory)
# Prevent any spawned command from actually running and affecting the host
spyOn(Spawner, 'spawn').andCallFake (command, args, callback) ->
spyOn(Spawner, 'spawn').andCallFake (command, args, callback) ->
# do nothing on command, just run passed callback
invokeCallback callback
# Prevent any actual change to Windows registry
for own method of WinRegistry
# all WinRegistry APIs share the same signature
spyOn(WinRegistry, method).andCallFake (callback) ->
# do nothing on registry, just run passed callback
invokeCallback callback
it "quits the app on all squirrel events", ->
app = quit: jasmine.createSpy('quit')
@@ -113,9 +127,3 @@ describe "Windows Squirrel Update", ->
app.emit('will-quit')
expect(Spawner.spawn.callCount).toBe 1
expect(path.basename(Spawner.spawn.argsForCall[0][0])).toBe 'atom.cmd'
# Run passed callback as Spawner.spawn() would do
invokeCallback = (callback) ->
error = null
stdout = ''
callback?(error, stdout)

View File

@@ -1,6 +1,7 @@
fs = require 'fs-plus'
path = require 'path'
Spawner = require './spawner'
WinRegistry = require './win-registry'
appFolder = path.resolve(process.execPath, '..')
rootAtomFolder = path.resolve(appFolder, '..')
@@ -10,25 +11,12 @@ exeName = path.basename(process.execPath)
if process.env.SystemRoot
system32Path = path.join(process.env.SystemRoot, 'System32')
regPath = path.join(system32Path, 'reg.exe')
powershellPath = path.join(system32Path, 'WindowsPowerShell', 'v1.0', 'powershell.exe')
setxPath = path.join(system32Path, 'setx.exe')
else
regPath = 'reg.exe'
powershellPath = 'powershell.exe'
setxPath = 'setx.exe'
# Registry keys used for context menu
fileKeyPath = 'HKCU\\Software\\Classes\\*\\shell\\Atom'
directoryKeyPath = 'HKCU\\Software\\Classes\\directory\\shell\\Atom'
backgroundKeyPath = 'HKCU\\Software\\Classes\\directory\\background\\shell\\Atom'
applicationsKeyPath = 'HKCU\\Software\\Classes\\Applications\\atom.exe'
environmentKeyPath = 'HKCU\\Environment'
# Spawn reg.exe and callback when it completes
spawnReg = (args, callback) ->
Spawner.spawn(regPath, args, callback)
# Spawn powershell.exe and callback when it completes
spawnPowershell = (args, callback) ->
# set encoding and execute the command, capture the output, and return it via .NET's console in order to have consistent UTF-8 encoding
@@ -54,30 +42,6 @@ spawnSetx = (args, callback) ->
spawnUpdate = (args, callback) ->
Spawner.spawn(updateDotExe, args, callback)
# Install the Open with Atom explorer context menu items via the registry.
installContextMenu = (callback) ->
addToRegistry = (args, callback) ->
args.unshift('add')
args.push('/f')
spawnReg(args, callback)
installFileHandler = (callback) ->
args = ["#{applicationsKeyPath}\\shell\\open\\command", '/ve', '/d', "\"#{process.execPath}\" \"%1\""]
addToRegistry(args, callback)
installMenu = (keyPath, arg, callback) ->
args = [keyPath, '/ve', '/d', 'Open with Atom']
addToRegistry args, ->
args = [keyPath, '/v', 'Icon', '/d', "\"#{process.execPath}\""]
addToRegistry args, ->
args = ["#{keyPath}\\command", '/ve', '/d', "\"#{process.execPath}\" \"#{arg}\""]
addToRegistry(args, callback)
installMenu fileKeyPath, '%1', ->
installMenu directoryKeyPath, '%1', ->
installMenu backgroundKeyPath, '%V', ->
installFileHandler(callback)
# Get the user's PATH environment variable registry value.
getPath = (callback) ->
spawnPowershell ['[environment]::GetEnvironmentVariable(\'Path\',\'User\')'], (error, stdout) ->
@@ -87,16 +51,6 @@ getPath = (callback) ->
pathOutput = stdout.replace(/^\s+|\s+$/g, '')
callback(null, pathOutput)
# Uninstall the Open with Atom explorer context menu items via the registry.
uninstallContextMenu = (callback) ->
deleteFromRegistry = (keyPath, callback) ->
spawnReg(['delete', keyPath, '/f'], callback)
deleteFromRegistry fileKeyPath, ->
deleteFromRegistry directoryKeyPath, ->
deleteFromRegistry backgroundKeyPath, ->
deleteFromRegistry(applicationsKeyPath, callback)
# Add atom and apm to the PATH
#
# This is done by adding .cmd shims to the root bin folder in the Atom
@@ -202,19 +156,19 @@ exports.handleStartupEvent = (app, squirrelCommand) ->
switch squirrelCommand
when '--squirrel-install'
createShortcuts ->
installContextMenu ->
WinRegistry.installContextMenu ->
addCommandsToPath ->
app.quit()
true
when '--squirrel-updated'
updateShortcuts ->
installContextMenu ->
WinRegistry.installContextMenu ->
addCommandsToPath ->
app.quit()
true
when '--squirrel-uninstall'
removeShortcuts ->
uninstallContextMenu ->
WinRegistry.uninstallContextMenu ->
removeCommandsFromPath ->
app.quit()
true

View File

@@ -0,0 +1,62 @@
path = require 'path'
Spawner = require './spawner'
if process.env.SystemRoot
system32Path = path.join(process.env.SystemRoot, 'System32')
regPath = path.join(system32Path, 'reg.exe')
else
regPath = 'reg.exe'
# Registry keys used for context menu
fileKeyPath = 'HKCU\\Software\\Classes\\*\\shell\\Atom'
directoryKeyPath = 'HKCU\\Software\\Classes\\directory\\shell\\Atom'
backgroundKeyPath = 'HKCU\\Software\\Classes\\directory\\background\\shell\\Atom'
applicationsKeyPath = 'HKCU\\Software\\Classes\\Applications\\atom.exe'
# Spawn reg.exe and callback when it completes
spawnReg = (args, callback) ->
Spawner.spawn(regPath, args, callback)
# Install the Open with Atom explorer context menu items via the registry.
#
# * `callback` The {Function} to call after registry operation is done.
# It will be invoked with the same arguments provided by {Spawner.spawn}.
#
# Returns `undefined`.
exports.installContextMenu = (callback) ->
addToRegistry = (args, callback) ->
args.unshift('add')
args.push('/f')
spawnReg(args, callback)
installFileHandler = (callback) ->
args = ["#{applicationsKeyPath}\\shell\\open\\command", '/ve', '/d', "\"#{process.execPath}\" \"%1\""]
addToRegistry(args, callback)
installMenu = (keyPath, arg, callback) ->
args = [keyPath, '/ve', '/d', 'Open with Atom']
addToRegistry args, ->
args = [keyPath, '/v', 'Icon', '/d', "\"#{process.execPath}\""]
addToRegistry args, ->
args = ["#{keyPath}\\command", '/ve', '/d', "\"#{process.execPath}\" \"#{arg}\""]
addToRegistry(args, callback)
installMenu fileKeyPath, '%1', ->
installMenu directoryKeyPath, '%1', ->
installMenu backgroundKeyPath, '%V', ->
installFileHandler(callback)
# Uninstall the Open with Atom explorer context menu items via the registry.
#
# * `callback` The {Function} to call after registry operation is done.
# It will be invoked with the same arguments provided by {Spawner.spawn}.
#
# Returns `undefined`.
exports.uninstallContextMenu = (callback) ->
deleteFromRegistry = (keyPath, callback) ->
spawnReg(['delete', keyPath, '/f'], callback)
deleteFromRegistry fileKeyPath, ->
deleteFromRegistry directoryKeyPath, ->
deleteFromRegistry backgroundKeyPath, ->
deleteFromRegistry(applicationsKeyPath, callback)