Files
atom/src/main-process/squirrel-update.js

188 lines
6.5 KiB
JavaScript

let setxPath
const fs = require('fs-plus')
const path = require('path')
const Spawner = require('./spawner')
const WinShell = require('./win-shell')
const WinPowerShell = require('./win-powershell')
const appFolder = path.resolve(process.execPath, '..')
const rootAtomFolder = path.resolve(appFolder, '..')
const binFolder = path.join(rootAtomFolder, 'bin')
const updateDotExe = path.join(rootAtomFolder, 'Update.exe')
const exeName = path.basename(process.execPath)
if (process.env.SystemRoot) {
const system32Path = path.join(process.env.SystemRoot, 'System32')
setxPath = path.join(system32Path, 'setx.exe')
} else {
setxPath = 'setx.exe'
}
// Spawn setx.exe and callback when it completes
const spawnSetx = (args, callback) => Spawner.spawn(setxPath, args, callback)
// Spawn the Update.exe with the given arguments and invoke the callback when
// the command completes.
const spawnUpdate = (args, callback) => Spawner.spawn(updateDotExe, args, callback)
// Add atom and apm to the PATH
//
// This is done by adding .cmd shims to the root bin folder in the Atom
// install directory that point to the newly installed versions inside
// the versioned app directories.
const addCommandsToPath = callback => {
const installCommands = callback => {
const atomCommandPath = path.join(binFolder, 'atom.cmd')
const relativeAtomPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'atom.cmd'))
const atomCommand = `@echo off\r\n\"%~dp0\\${relativeAtomPath}\" %*`
const atomShCommandPath = path.join(binFolder, 'atom')
const relativeAtomShPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'atom.sh'))
const atomShCommand = `#!/bin/sh\r\n\"$(dirname \"$0\")/${relativeAtomShPath.replace(/\\/g, '/')}\" \"$@\"\r\necho`
const apmCommandPath = path.join(binFolder, 'apm.cmd')
const relativeApmPath = path.relative(binFolder, path.join(process.resourcesPath, 'app', 'apm', 'bin', 'apm.cmd'))
const apmCommand = `@echo off\r\n\"%~dp0\\${relativeApmPath}\" %*`
const apmShCommandPath = path.join(binFolder, 'apm')
const relativeApmShPath = path.relative(binFolder, path.join(appFolder, 'resources', 'cli', 'apm.sh'))
const apmShCommand = `#!/bin/sh\r\n\"$(dirname \"$0\")/${relativeApmShPath.replace(/\\/g, '/')}\" \"$@\"`
fs.writeFile(atomCommandPath, atomCommand, () =>
fs.writeFile(atomShCommandPath, atomShCommand, () =>
fs.writeFile(apmCommandPath, apmCommand, () =>
fs.writeFile(apmShCommandPath, apmShCommand, () => callback())
)
)
)
}
const addBinToPath = (pathSegments, callback) => {
pathSegments.push(binFolder)
const newPathEnv = pathSegments.join(';')
spawnSetx(['Path', newPathEnv], callback)
}
installCommands(error => {
if (error) return callback(error)
WinPowerShell.getPath((error, pathEnv) => {
if (error) return callback(error)
const pathSegments = pathEnv.split(/;+/).filter(pathSegment => pathSegment)
if (pathSegments.indexOf(binFolder) === -1) {
addBinToPath(pathSegments, callback)
} else {
callback()
}
})
})
}
// Remove atom and apm from the PATH
const removeCommandsFromPath = callback =>
WinPowerShell.getPath((error, pathEnv) => {
if (error != null) { return callback(error) }
const pathSegments = pathEnv.split(/;+/).filter(pathSegment => pathSegment && (pathSegment !== binFolder))
const newPathEnv = pathSegments.join(';')
if (pathEnv !== newPathEnv) {
return spawnSetx(['Path', newPathEnv], callback)
} else {
return callback()
}
})
// Create a desktop and start menu shortcut by using the command line API
// provided by Squirrel's Update.exe
const createShortcuts = (locations, callback) => spawnUpdate(['--createShortcut', exeName, '-l', locations.join(',')], callback)
// Update the desktop and start menu shortcuts by using the command line API
// provided by Squirrel's Update.exe
const updateShortcuts = (callback) => {
const homeDirectory = fs.getHomeDirectory()
if (homeDirectory) {
const desktopShortcutPath = path.join(homeDirectory, 'Desktop', 'Atom.lnk')
// Check if the desktop shortcut has been previously deleted and
// and keep it deleted if it was
fs.exists(desktopShortcutPath, (desktopShortcutExists) => {
const locations = ['StartMenu']
if (desktopShortcutExists) { locations.push('Desktop') }
createShortcuts(locations, callback)
})
} else {
createShortcuts(['Desktop', 'StartMenu'], callback)
}
}
// Remove the desktop and start menu shortcuts by using the command line API
// provided by Squirrel's Update.exe
const removeShortcuts = callback => spawnUpdate(['--removeShortcut', exeName], callback)
exports.spawn = spawnUpdate
// Is the Update.exe installed with Atom?
exports.existsSync = () => fs.existsSync(updateDotExe)
// Restart Atom using the version pointed to by the atom.cmd shim
exports.restartAtom = (app) => {
let args
if (global.atomApplication && global.atomApplication.lastFocusedWindow) {
const {projectPath} = global.atomApplication.lastFocusedWindow
if (projectPath) args = [projectPath]
}
app.once('will-quit', () => Spawner.spawn(path.join(binFolder, 'atom.cmd'), args))
app.quit()
}
const updateContextMenus = callback =>
WinShell.fileContextMenu.update(() =>
WinShell.folderContextMenu.update(() =>
WinShell.folderBackgroundContextMenu.update(() => callback())
)
)
// Handle squirrel events denoted by --squirrel-* command line arguments.
exports.handleStartupEvent = (app, squirrelCommand) => {
switch (squirrelCommand) {
case '--squirrel-install':
createShortcuts(['Desktop', 'StartMenu'], () =>
addCommandsToPath(() =>
WinShell.fileHandler.register(() =>
updateContextMenus(() => app.quit())
)
)
)
return true
case '--squirrel-updated':
updateShortcuts(() =>
addCommandsToPath(() =>
WinShell.fileHandler.update(() =>
updateContextMenus(() => app.quit())
)
)
)
return true
case '--squirrel-uninstall':
removeShortcuts(() =>
removeCommandsFromPath(() =>
WinShell.fileHandler.deregister(() =>
WinShell.fileContextMenu.deregister(() =>
WinShell.folderContextMenu.deregister(() =>
WinShell.folderBackgroundContextMenu.deregister(() => app.quit())
)
)
)
)
)
return true
case '--squirrel-obsolete':
app.quit()
return true
default:
return false
}
}