update-process-env.js
1 const fs = require('fs'); 2 const childProcess = require('child_process'); 3 4 const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set([ 5 'NODE_ENV', 6 'NODE_PATH', 7 'ATOM_HOME', 8 'ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT' 9 ]); 10 11 const PLATFORMS_KNOWN_TO_WORK = new Set(['darwin', 'linux']); 12 13 async function updateProcessEnv(launchEnv) { 14 let envToAssign; 15 if (launchEnv) { 16 if (shouldGetEnvFromShell(launchEnv)) { 17 envToAssign = await getEnvFromShell(launchEnv); 18 } else if (launchEnv.PWD || launchEnv.PROMPT || launchEnv.PSModulePath) { 19 envToAssign = launchEnv; 20 } 21 } 22 23 if (envToAssign) { 24 for (let key in process.env) { 25 if (!ENVIRONMENT_VARIABLES_TO_PRESERVE.has(key)) { 26 delete process.env[key]; 27 } 28 } 29 30 for (let key in envToAssign) { 31 if ( 32 !ENVIRONMENT_VARIABLES_TO_PRESERVE.has(key) || 33 (!process.env[key] && envToAssign[key]) 34 ) { 35 process.env[key] = envToAssign[key]; 36 } 37 } 38 39 if (envToAssign.ATOM_HOME && fs.existsSync(envToAssign.ATOM_HOME)) { 40 process.env.ATOM_HOME = envToAssign.ATOM_HOME; 41 } 42 } 43 } 44 45 function shouldGetEnvFromShell(env) { 46 if (!PLATFORMS_KNOWN_TO_WORK.has(process.platform)) { 47 return false; 48 } 49 50 if (!env || !env.SHELL || env.SHELL.trim() === '') { 51 return false; 52 } 53 54 const disableSellingOut = 55 env.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT || 56 process.env.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT; 57 58 if (disableSellingOut === 'true') { 59 return false; 60 } 61 62 return true; 63 } 64 65 async function getEnvFromShell(env) { 66 let { stdout, error } = await new Promise(resolve => { 67 let child; 68 let error; 69 let stdout = ''; 70 let done = false; 71 const cleanup = () => { 72 if (!done && child) { 73 child.kill(); 74 done = true; 75 } 76 }; 77 process.once('exit', cleanup); 78 setTimeout(() => { 79 cleanup(); 80 }, 5000); 81 child = childProcess.spawn(env.SHELL, ['-ilc', 'command env'], { 82 encoding: 'utf8', 83 detached: true, 84 stdio: ['ignore', 'pipe', process.stderr] 85 }); 86 const buffers = []; 87 child.on('error', e => { 88 done = true; 89 error = e; 90 }); 91 child.stdout.on('data', data => { 92 buffers.push(data); 93 }); 94 child.on('close', (code, signal) => { 95 done = true; 96 process.removeListener('exit', cleanup); 97 if (buffers.length) { 98 stdout = Buffer.concat(buffers).toString('utf8'); 99 } 100 101 resolve({ stdout, error }); 102 }); 103 }); 104 105 if (error) { 106 if (error.handle) { 107 error.handle(); 108 } 109 console.log( 110 'warning: ' + 111 env.SHELL + 112 ' -ilc "command env" failed with signal (' + 113 error.signal + 114 ')' 115 ); 116 console.log(error); 117 } 118 119 if (!stdout || stdout.trim() === '') { 120 return null; 121 } 122 123 let result = {}; 124 for (let line of stdout.split('\n')) { 125 if (line.includes('=')) { 126 let components = line.split('='); 127 let key = components.shift(); 128 let value = components.join('='); 129 result[key] = value; 130 } 131 } 132 return result; 133 } 134 135 module.exports = { updateProcessEnv, shouldGetEnvFromShell };