From 9726618069fdb8c3343e4560dc316c30141a1a77 Mon Sep 17 00:00:00 2001 From: Evan Morikawa Date: Tue, 12 Jan 2016 18:17:05 -0500 Subject: [PATCH] fix(squirrel): fix win32 update to enable restart and launch from path --- src/browser/squirrel-update.coffee | 88 ++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/src/browser/squirrel-update.coffee b/src/browser/squirrel-update.coffee index 4010b16ee..fee374c20 100644 --- a/src/browser/squirrel-update.coffee +++ b/src/browser/squirrel-update.coffee @@ -54,11 +54,23 @@ spawnSetx = (args, callback) -> spawnUpdate = (args, callback) -> spawn(updateDotExe, args, callback) +isAscii = (text) -> + index = 0 + while index < text.length + return false if text.charCodeAt(index) > 127 + index++ + true + # Get the user's PATH environment variable registry value. getPath = (callback) -> spawnReg ['query', environmentKeyPath, '/v', 'Path'], (error, stdout) -> if error? if error.code is 1 + # FIXME Don't overwrite path when reading value is disabled + # https://github.com/atom/atom/issues/5092 + if stdout.indexOf('ERROR: Registry editing has been disabled by your administrator.') isnt -1 + return callback(error) + # The query failed so the Path does not exist yet in the registry return callback(null, '') else @@ -74,10 +86,75 @@ getPath = (callback) -> segments = lines[lines.length - 1]?.split(' ') if segments[1] is 'Path' and segments.length >= 3 pathEnv = segments?[3..].join(' ') - callback(null, pathEnv) + if isAscii(pathEnv) + callback(null, pathEnv) + else + # FIXME Don't corrupt non-ASCII PATH values + # https://github.com/atom/atom/issues/5063 + callback(new Error('PATH contains non-ASCII values')) else callback(new Error('Registry query for PATH failed')) +# Add atom and apm to the PATH +# +# This is done by adding .cmd shims to the root bin folder in the N1 +# install directory that point to the newly installed versions inside +# the versioned app directories. +addCommandsToPath = (callback) -> + installCommands = (callback) -> + nylasCommandPath = path.join(binFolder, 'N1.cmd') + relativeN1Path = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'N1.cmd')) + nylasCommand = "@echo off\r\n\"%~dp0\\#{relativeN1Path}\" %*" + + nylasShCommandPath = path.join(binFolder, 'N1') + relativeN1ShPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'N1.sh')) + nylasShCommand = "#!/bin/sh\r\n\"$(dirname \"$0\")/#{relativeN1ShPath.replace(/\\/g, '/')}\" \"$@\"" + + apmCommandPath = path.join(binFolder, 'apm.cmd') + relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd')) + apmCommand = "@echo off\r\n\"%~dp0\\#{relativeApmPath}\" %*" + + apmShCommandPath = path.join(binFolder, 'apm') + relativeApmShPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'apm.sh')) + apmShCommand = "#!/bin/sh\r\n\"$(dirname \"$0\")/#{relativeApmShPath.replace(/\\/g, '/')}\" \"$@\"" + + fs.writeFile nylasCommandPath, nylasCommand, -> + fs.writeFile nylasShCommandPath, nylasShCommand, -> + fs.writeFile apmCommandPath, apmCommand, -> + fs.writeFile apmShCommandPath, apmShCommand, -> + callback() + + addBinToPath = (pathSegments, callback) -> + pathSegments.push(binFolder) + newPathEnv = pathSegments.join(';') + spawnSetx(['Path', newPathEnv], callback) + + installCommands (error) -> + return callback(error) if error? + + getPath (error, pathEnv) -> + return callback(error) if error? + + pathSegments = pathEnv.split(/;+/).filter (pathSegment) -> pathSegment + if pathSegments.indexOf(binFolder) is -1 + addBinToPath(pathSegments, callback) + else + callback() + +# Remove N1 and apm from the PATH +removeCommandsFromPath = (callback) -> + getPath (error, pathEnv) -> + return callback(error) if error? + + pathSegments = pathEnv.split(/;+/).filter (pathSegment) -> + pathSegment and pathSegment isnt binFolder + newPathEnv = pathSegments.join(';') + + if pathEnv isnt newPathEnv + spawnSetx(['Path', newPathEnv], callback) + else + callback() + # Create a desktop and start menu shortcut by using the command line API # provided by Squirrel's Update.exe createShortcuts = (callback) -> @@ -123,15 +200,18 @@ exports.handleStartupEvent = (app, squirrelCommand) -> switch squirrelCommand when '--squirrel-install' createShortcuts -> - app.quit() + addCommandsToPath -> + app.quit() true when '--squirrel-updated' updateShortcuts -> - app.quit() + addCommandsToPath -> + app.quit() true when '--squirrel-uninstall' removeShortcuts -> - app.quit() + removeCommandsFromPath -> + app.quit() true when '--squirrel-obsolete' app.quit()