Make updateProcessEnv asynchronous

Signed-off-by: Nathan Sobo <nathan@github.com>
This commit is contained in:
Antonio Scandurra
2016-11-11 18:39:18 +01:00
committed by Nathan Sobo
parent 31eb91c0a7
commit e34bc188d0
4 changed files with 61 additions and 49 deletions

View File

@@ -1,6 +1,7 @@
/** @babel */
/* eslint-env jasmine */
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
import path from 'path'
import temp from 'temp'
import child_process from 'child_process'
@@ -22,7 +23,7 @@ describe('updateProcessEnv(launchEnv)', function () {
})
describe('when the launch environment appears to come from a shell', function () {
it('updates process.env to match the launch environment', function () {
it('updates process.env to match the launch environment', async function () {
process.env = {
WILL_BE_DELETED: 'hi',
NODE_ENV: 'the-node-env',
@@ -32,7 +33,7 @@ describe('updateProcessEnv(launchEnv)', function () {
const initialProcessEnv = process.env
updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', TERM: 'xterm-something', KEY1: 'value1', KEY2: 'value2'})
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', TERM: 'xterm-something', KEY1: 'value1', KEY2: 'value2'})
expect(process.env).toEqual({
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
PWD: '/the/dir',
@@ -50,7 +51,7 @@ describe('updateProcessEnv(launchEnv)', function () {
expect(process.env).toBe(initialProcessEnv)
})
it('allows ATOM_HOME to be overwritten only if the new value is a valid path', function () {
it('allows ATOM_HOME to be overwritten only if the new value is a valid path', async function () {
let newAtomHomePath = temp.mkdirSync('atom-home')
process.env = {
@@ -60,7 +61,7 @@ describe('updateProcessEnv(launchEnv)', function () {
ATOM_HOME: '/the/atom/home'
}
updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir'})
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir'})
expect(process.env).toEqual({
PWD: '/the/dir',
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
@@ -69,7 +70,7 @@ describe('updateProcessEnv(launchEnv)', function () {
ATOM_HOME: '/the/atom/home'
})
updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')})
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: path.join(newAtomHomePath, 'non-existent')})
expect(process.env).toEqual({
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
PWD: '/the/dir',
@@ -78,7 +79,7 @@ describe('updateProcessEnv(launchEnv)', function () {
ATOM_HOME: '/the/atom/home'
})
updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: newAtomHomePath})
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', ATOM_HOME: newAtomHomePath})
expect(process.env).toEqual({
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
PWD: '/the/dir',
@@ -88,7 +89,7 @@ describe('updateProcessEnv(launchEnv)', function () {
})
})
it('allows ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT to be preserved if set', function () {
it('allows ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT to be preserved if set', async function () {
process.env = {
WILL_BE_DELETED: 'hi',
NODE_ENV: 'the-node-env',
@@ -96,7 +97,7 @@ describe('updateProcessEnv(launchEnv)', function () {
ATOM_HOME: '/the/atom/home'
}
updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'})
await updateProcessEnv({ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true', PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'})
expect(process.env).toEqual({
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
PWD: '/the/dir',
@@ -105,7 +106,7 @@ describe('updateProcessEnv(launchEnv)', function () {
ATOM_HOME: '/the/atom/home'
})
updateProcessEnv({PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'})
await updateProcessEnv({PWD: '/the/dir', NODE_ENV: 'the-node-env', NODE_PATH: '/the/node/path', ATOM_HOME: '/the/atom/home'})
expect(process.env).toEqual({
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT: 'true',
PWD: '/the/dir',
@@ -115,7 +116,7 @@ describe('updateProcessEnv(launchEnv)', function () {
})
})
it('allows an existing env variable to be updated', function () {
it('allows an existing env variable to be updated', async function () {
process.env = {
WILL_BE_UPDATED: 'old-value',
NODE_ENV: 'the-node-env',
@@ -123,7 +124,7 @@ describe('updateProcessEnv(launchEnv)', function () {
ATOM_HOME: '/the/atom/home'
}
updateProcessEnv(process.env)
await updateProcessEnv(process.env)
expect(process.env).toEqual(process.env)
let updatedEnv = {
@@ -135,27 +136,31 @@ describe('updateProcessEnv(launchEnv)', function () {
PWD: '/the/dir'
}
updateProcessEnv(updatedEnv)
await updateProcessEnv(updatedEnv)
expect(process.env).toEqual(updatedEnv)
})
})
describe('when the launch environment does not come from a shell', function () {
describe('on osx', function () {
it('updates process.env to match the environment in the user\'s login shell', function () {
it('updates process.env to match the environment in the user\'s login shell', async function () {
process.platform = 'darwin'
process.env.SHELL = '/my/custom/bash'
spyOn(child_process, 'spawnSync').andReturn({
stdout: dedent`
FOO=BAR=BAZ=QUUX
TERM=xterm-something
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
`
spyOn(child_process, 'execFile').andCallFake((cmd, args, opts, callback) => {
expect(cmd).toBe('/my/custom/bash')
callback(
null,
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')
await updateProcessEnv(process.env)
expect(process.env).toEqual({
FOO: 'BAR=BAZ=QUUX',
TERM: 'xterm-something',
@@ -163,25 +168,29 @@ describe('updateProcessEnv(launchEnv)', function () {
})
// Doesn't error
updateProcessEnv(null)
await updateProcessEnv(null)
})
})
describe('on linux', function () {
it('updates process.env to match the environment in the user\'s login shell', function () {
it('updates process.env to match the environment in the user\'s login shell', async function () {
process.platform = 'linux'
process.env.SHELL = '/my/custom/bash'
spyOn(child_process, 'spawnSync').andReturn({
stdout: dedent`
FOO=BAR=BAZ=QUUX
TERM=xterm-something
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/crazy/path
`
spyOn(child_process, 'execFile').andCallFake((cmd, args, opts, callback) => {
expect(cmd).toBe('/my/custom/bash')
callback(
null,
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')
await updateProcessEnv(process.env)
expect(process.env).toEqual({
FOO: 'BAR=BAZ=QUUX',
TERM: 'xterm-something',
@@ -189,18 +198,18 @@ describe('updateProcessEnv(launchEnv)', function () {
})
// Doesn't error
updateProcessEnv(null)
await updateProcessEnv(null)
})
})
describe('on windows', function () {
it('does not update process.env', function () {
it('does not update process.env', async function () {
process.platform = 'win32'
spyOn(child_process, 'spawnSync')
spyOn(child_process, 'execFile')
process.env = {FOO: 'bar'}
updateProcessEnv(process.env)
expect(child_process.spawnSync).not.toHaveBeenCalled()
await updateProcessEnv(process.env)
expect(child_process.execFile).not.toHaveBeenCalled()
expect(process.env).toEqual({FOO: 'bar'})
})
})

View File

@@ -675,7 +675,8 @@ class AtomEnvironment extends Model
# Call this method when establishing a real application window.
startEditorWindow: ->
@unloaded = false
@loadState().then (state) =>
updateProcessEnvPromise = updateProcessEnv(@getLoadSettings().env)
loadStatePromise = @loadState().then (state) =>
@windowDimensions = state?.windowDimensions
@displayWindow().then =>
@commandInstaller.installAtomCommand false, (error) ->
@@ -716,6 +717,8 @@ class AtomEnvironment extends Model
@openInitialEmptyEditorIfNecessary()
Promise.all([loadStatePromise, updateProcessEnvPromise])
serialize: (options) ->
version: @constructor.version
project: @project.serialize(options)

View File

@@ -8,8 +8,6 @@ module.exports = ({blobStore}) ->
{resourcePath, devMode, env} = getWindowLoadSettings()
require './electron-shims'
updateProcessEnv(env)
# Add application-specific exports to module search path.
exportsPath = path.join(resourcePath, 'exports')
require('module').globalPaths.push(exportsPath)

View File

@@ -1,7 +1,7 @@
/** @babel */
import fs from 'fs'
import {spawnSync} from 'child_process'
import childProcess from 'child_process'
const ENVIRONMENT_VARIABLES_TO_PRESERVE = new Set([
'NODE_ENV',
@@ -15,10 +15,10 @@ const PLATFORMS_KNOWN_TO_WORK = new Set([
'linux'
])
function updateProcessEnv (launchEnv) {
async function updateProcessEnv (launchEnv) {
let envToAssign
if (launchEnv && shouldGetEnvFromShell(launchEnv)) {
envToAssign = getEnvFromShell(launchEnv)
envToAssign = await getEnvFromShell(launchEnv)
} else if (launchEnv && launchEnv.PWD) {
envToAssign = launchEnv
}
@@ -58,23 +58,25 @@ function shouldGetEnvFromShell (env) {
return true
}
function getEnvFromShell (env) {
async function getEnvFromShell (env) {
if (!shouldGetEnvFromShell(env)) {
return
return null
}
let {stdout, error, status, signal} = spawnSync(env.SHELL, ['-ilc', 'command env'], {encoding: 'utf8', timeout: 5000})
let {stdout, error} = await new Promise((resolve) => {
childProcess.execFile(env.SHELL, ['-ilc', 'command env'], {encoding: 'utf8', timeout: 5000}, (error, stdout) => {
resolve({stdout, error})
})
})
if (error) {
if (error.handle) {
error.handle()
}
console.log('warning: ' + env.SHELL + '-ilc "command env" failed with signal (' + error.signal + ')')
console.log(error)
}
if (status !== 0) {
console.log('warning: ' + env.SHELL + '-ilc "command env" failed with status (' + status + ') and signal (' + signal + ')')
}
if (stdout) {
let result = {}
for (let line of stdout.split('\n')) {