diff --git a/src/command-installer.coffee b/src/command-installer.coffee index a0374bf99..63066cb30 100644 --- a/src/command-installer.coffee +++ b/src/command-installer.coffee @@ -3,6 +3,7 @@ _ = require 'underscore-plus' async = require 'async' fs = require 'fs-plus' mkdirp = require 'mkdirp' +runas = require 'runas' symlinkCommand = (sourcePath, destinationPath, callback) -> mkdirp path.dirname(destinationPath), (error) -> @@ -15,6 +16,10 @@ symlinkCommand = (sourcePath, destinationPath, callback) -> else fs.chmod(destinationPath, 0o755, callback) +symlinkCommandWithPrivilegeSync = (sourcePath, destinationPath) -> + runas('/bin/mkdir', ['-p', path.dirname(destinationPath)], admin: true) + runas('/bin/ln', ['-s', sourcePath, destinationPath], admin: true) is 0 + unlinkCommand = (destinationPath, callback) -> fs.unlink destinationPath, (error) -> if error? and error.code isnt 'ENOENT' @@ -22,6 +27,9 @@ unlinkCommand = (destinationPath, callback) -> else callback() +unlinkCommandWithPrivilegeSync = (destinationPath) -> + runas('/bin/rm', ['-f', destinationPath], admin: true) is 0 + module.exports = getInstallDirectory: -> "/usr/local/bin" @@ -34,11 +42,19 @@ module.exports = if fs.existsSync(directory) destinationPath = path.join(directory, commandName) unlinkCommand destinationPath, (error) => + # Retry with privilige escalation. + if error?.code is 'EACCES' and unlinkCommandWithPrivilegeSync(destinationPath) + error = null + if error? error = new Error "Could not remove file at #{destinationPath}." if error callback?(error) else symlinkCommand commandPath, destinationPath, (error) => + # Retry with privilige escalation. + if error?.code is 'EACCES' and symlinkCommandWithPrivilegeSync(commandPath, destinationPath) + error = null + error = new Error "Failed to symlink #{commandPath} to #{destinationPath}." if error callback?(error) else