Get Environment From Shell On Linux

This commit is contained in:
Joe Fitzgerald
2016-08-30 19:52:56 +00:00
parent c397bcd46e
commit c570e14420
2 changed files with 98 additions and 32 deletions

View File

@@ -31,9 +31,10 @@ describe('updateProcessEnv(launchEnv)', function () {
}
const initialProcessEnv = process.env
updateProcessEnv({PWD: '/the/dir', KEY1: 'value1', KEY2: 'value2'})
updateProcessEnv({PWD: '/the/dir', TERM: 'xterm-something', KEY1: 'value1', KEY2: 'value2'})
expect(process.env).toEqual({
PWD: '/the/dir',
TERM: 'xterm-something',
KEY1: 'value1',
KEY2: 'value2',
NODE_ENV: 'the-node-env',
@@ -57,26 +58,29 @@ describe('updateProcessEnv(launchEnv)', function () {
ATOM_HOME: '/the/atom/home'
}
updateProcessEnv({PWD: '/the/dir'})
updateProcessEnv({PWD: '/the/dir', TERM: 'xterm-something'})
expect(process.env).toEqual({
PWD: '/the/dir',
TERM: 'xterm-something',
NODE_ENV: 'the-node-env',
NODE_PATH: '/the/node/path',
ATOM_HOME: '/the/atom/home'
})
updateProcessEnv({PWD: '/the/dir', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')})
updateProcessEnv({PWD: '/the/dir', TERM: 'xterm-something', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')})
expect(process.env).toEqual({
PWD: '/the/dir',
TERM: 'xterm-something',
NODE_ENV: 'the-node-env',
NODE_PATH: '/the/node/path',
ATOM_HOME: '/the/atom/home'
})
updateProcessEnv({PWD: '/the/dir', ATOM_HOME: newAtomHomePath})
updateProcessEnv({PWD: '/the/dir', TERM: 'xterm-something', ATOM_HOME: newAtomHomePath})
expect(process.env).toEqual({
PWD: '/the/dir',
TERM: 'xterm-something',
NODE_ENV: 'the-node-env',
NODE_PATH: '/the/node/path',
ATOM_HOME: newAtomHomePath
@@ -111,6 +115,33 @@ describe('updateProcessEnv(launchEnv)', function () {
})
})
describe('on linux', function () {
it('updates process.env to match the environment in the user\'s login shell', function () {
process.platform = 'linux'
process.env.SHELL = '/my/custom/bash'
delete process.env.TERM
spyOn(child_process, 'spawnSync').andReturn({
stdout: dedent`
FOO=BAR=BAZ=QUUX
TERM=xterm-something
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
`
})
updateProcessEnv(process.env)
expect(child_process.spawnSync.mostRecentCall.args[0]).toBe('/my/custom/bash')
expect(process.env).toEqual({
FOO: 'BAR=BAZ=QUUX',
TERM: 'xterm-something',
PATH: '/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path'
})
// Doesn't error
updateProcessEnv(null)
})
})
describe('not on osx', function () {
it('does not update process.env', function () {
process.platform = 'win32'
@@ -124,30 +155,49 @@ describe('updateProcessEnv(launchEnv)', function () {
})
describe('shouldGetEnvFromShell()', function () {
it('returns the shell when the shell should be patched', function () {
it('indicates when the environment should be fetched from the shell', function () {
process.platform = 'darwin'
expect(shouldGetEnvFromShell('/bin/sh')).toBe(true)
expect(shouldGetEnvFromShell('/usr/local/bin/sh')).toBe(true)
expect(shouldGetEnvFromShell('/bin/bash')).toBe(true)
expect(shouldGetEnvFromShell('/usr/local/bin/bash')).toBe(true)
expect(shouldGetEnvFromShell('/bin/zsh')).toBe(true)
expect(shouldGetEnvFromShell('/usr/local/bin/zsh')).toBe(true)
expect(shouldGetEnvFromShell('/bin/fish')).toBe(true)
expect(shouldGetEnvFromShell('/usr/local/bin/fish')).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/bin/sh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/sh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/bin/bash'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/bash'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/bin/zsh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/zsh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/bin/fish'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/fish'})).toBe(true)
process.platform = 'linux'
expect(shouldGetEnvFromShell({SHELL: '/bin/sh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/sh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/bin/bash'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/bash'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/bin/zsh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/zsh'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/bin/fish'})).toBe(true)
expect(shouldGetEnvFromShell({SHELL: '/usr/local/bin/fish'})).toBe(true)
})
it('returns false when the shell should not be patched', function () {
process.platform = 'darwin'
expect(shouldGetEnvFromShell('/bin/unsupported')).toBe(false)
expect(shouldGetEnvFromShell('/bin/shh')).toBe(false)
expect(shouldGetEnvFromShell('/bin/tcsh')).toBe(false)
expect(shouldGetEnvFromShell('/usr/csh')).toBe(false)
expect(shouldGetEnvFromShell({SHELL: '/bin/unsupported'})).toBe(false)
expect(shouldGetEnvFromShell({SHELL: '/bin/shh'})).toBe(false)
expect(shouldGetEnvFromShell({SHELL: '/bin/tcsh'})).toBe(false)
expect(shouldGetEnvFromShell({SHELL: '/usr/csh'})).toBe(false)
process.platform = 'linux'
expect(shouldGetEnvFromShell({SHELL: '/bin/unsupported'})).toBe(false)
expect(shouldGetEnvFromShell({SHELL: '/bin/shh'})).toBe(false)
expect(shouldGetEnvFromShell({SHELL: '/bin/tcsh'})).toBe(false)
expect(shouldGetEnvFromShell({SHELL: '/usr/csh'})).toBe(false)
})
it('returns false when the shell is undefined or empty', function () {
process.platform = 'darwin'
expect(shouldGetEnvFromShell(undefined)).toBe(false)
expect(shouldGetEnvFromShell('')).toBe(false)
expect(shouldGetEnvFromShell({})).toBe(false)
process.platform = 'linux'
expect(shouldGetEnvFromShell(undefined)).toBe(false)
expect(shouldGetEnvFromShell({})).toBe(false)
})
})
})

View File

@@ -9,21 +9,25 @@ const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set([
'ATOM_HOME'
])
const OSX_SHELLS = new Set([
const SHELLS_KNOWN_TO_WORK = new Set([
'/sh',
'/bash',
'/zsh',
'/fish'
])
const PLATFORMS_KNOWN_TO_WORK = new Set([
'darwin',
'linux'
])
function updateProcessEnv (launchEnv) {
let envToAssign
if (launchEnv && launchEnv.PWD) {
if (launchEnv && shouldGetEnvFromShell(launchEnv)) {
envToAssign = getEnvFromShell(launchEnv)
} else if (launchEnv && launchEnv.PWD) { // Launched from shell
envToAssign = launchEnv
} else {
if (process.platform === 'darwin') {
envToAssign = getEnvFromShell()
}
}
if (envToAssign) {
@@ -45,12 +49,25 @@ function updateProcessEnv (launchEnv) {
}
}
function shouldGetEnvFromShell (shell) {
if (!shell || shell.trim() === '') {
function shouldGetEnvFromShell (env) {
if (!PLATFORMS_KNOWN_TO_WORK.has(process.platform)) { // Untested platforms
return false
}
for (let s of OSX_SHELLS) {
if (shell.endsWith(s)) {
if (!env || !env.SHELL || env.SHELL.trim() === '') { // Nothing to launch
return false
}
if (process.platform === 'linux' && env.TERM) { // Launched from shell
return false
}
if (process.platform === 'darwin' && env.PWD) { // Launched from shell
return false
}
for (let s of SHELLS_KNOWN_TO_WORK) {
if (env.SHELL.endsWith(s)) {
return true
}
}
@@ -58,13 +75,12 @@ function shouldGetEnvFromShell (shell) {
return false
}
function getEnvFromShell () {
let shell = process.env.SHELL
if (!shouldGetEnvFromShell(shell)) {
function getEnvFromShell (env) {
if (!shouldGetEnvFromShell(env)) {
return
}
let {stdout} = spawnSync(shell, ['-ilc', 'command env'], {encoding: 'utf8'})
let {stdout} = spawnSync(env.SHELL, ['-ilc', 'command env'], {encoding: 'utf8'})
if (stdout) {
let result = {}
for (let line of stdout.split('\n')) {