command-installer.js
1 const path = require('path'); 2 const fs = require('fs-plus'); 3 4 module.exports = class CommandInstaller { 5 constructor(applicationDelegate) { 6 this.applicationDelegate = applicationDelegate; 7 } 8 9 initialize(appVersion) { 10 this.appVersion = appVersion; 11 } 12 13 getInstallDirectory() { 14 return '/usr/local/bin'; 15 } 16 17 getResourcesDirectory() { 18 return process.resourcesPath; 19 } 20 21 installShellCommandsInteractively() { 22 const showErrorDialog = error => { 23 this.applicationDelegate.confirm( 24 { 25 message: 'Failed to install shell commands', 26 detail: error.message 27 }, 28 () => {} 29 ); 30 }; 31 32 this.installAtomCommand(true, (error, atomCommandName) => { 33 if (error) return showErrorDialog(error); 34 this.installApmCommand(true, (error, apmCommandName) => { 35 if (error) return showErrorDialog(error); 36 this.applicationDelegate.confirm( 37 { 38 message: 'Commands installed.', 39 detail: `The shell commands \`${atomCommandName}\` and \`${apmCommandName}\` are installed.` 40 }, 41 () => {} 42 ); 43 }); 44 }); 45 } 46 47 getCommandNameForChannel(commandName) { 48 let channelMatch = this.appVersion.match(/beta|nightly/); 49 let channel = channelMatch ? channelMatch[0] : ''; 50 51 switch (channel) { 52 case 'beta': 53 return `${commandName}-beta`; 54 case 'nightly': 55 return `${commandName}-nightly`; 56 default: 57 return commandName; 58 } 59 } 60 61 installAtomCommand(askForPrivilege, callback) { 62 this.installCommand( 63 path.join(this.getResourcesDirectory(), 'app', 'atom.sh'), 64 this.getCommandNameForChannel('atom'), 65 askForPrivilege, 66 callback 67 ); 68 } 69 70 installApmCommand(askForPrivilege, callback) { 71 this.installCommand( 72 path.join( 73 this.getResourcesDirectory(), 74 'app', 75 'apm', 76 'node_modules', 77 '.bin', 78 'apm' 79 ), 80 this.getCommandNameForChannel('apm'), 81 askForPrivilege, 82 callback 83 ); 84 } 85 86 installCommand(commandPath, commandName, askForPrivilege, callback) { 87 if (process.platform !== 'darwin') return callback(); 88 89 const destinationPath = path.join(this.getInstallDirectory(), commandName); 90 91 fs.readlink(destinationPath, (error, realpath) => { 92 if (error && error.code !== 'ENOENT') return callback(error); 93 if (realpath === commandPath) return callback(null, commandName); 94 this.createSymlink(fs, commandPath, destinationPath, error => { 95 if (error && error.code === 'EACCES' && askForPrivilege) { 96 const fsAdmin = require('fs-admin'); 97 this.createSymlink(fsAdmin, commandPath, destinationPath, error => { 98 callback(error, commandName); 99 }); 100 } else { 101 callback(error); 102 } 103 }); 104 }); 105 } 106 107 createSymlink(fs, sourcePath, destinationPath, callback) { 108 fs.unlink(destinationPath, error => { 109 if (error && error.code !== 'ENOENT') return callback(error); 110 fs.makeTree(path.dirname(destinationPath), error => { 111 if (error) return callback(error); 112 fs.symlink(sourcePath, destinationPath, callback); 113 }); 114 }); 115 } 116 };