Skip to content

Commit 46fad5a

Browse files
authored
fix: parse options.env more similarly to process.env (#98)
This fix attempts to parse `options.env` in a similar way to how it is parsed in `child_process.spawn`, namely by doing a simple sorted case-insensitive lookup for `path` and `pathext`. The intent is to support folks who pass in to opts `{ env: ...process.env}`, as this removes the built in case insensitivity that is present on the original `process.env` object.
1 parent d3ba687 commit 46fad5a

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

lib/index.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ const spawnWithShell = (cmd, args, opts, extra) => {
100100
let pathToInitial
101101
try {
102102
pathToInitial = which.sync(initialCmd, {
103-
path: (options.env && options.env.PATH) || process.env.PATH,
104-
pathext: (options.env && options.env.PATHEXT) || process.env.PATHEXT,
103+
path: (options.env && findInObject(options.env, 'PATH')) || process.env.PATH,
104+
pathext: (options.env && findInObject(options.env, 'PATHEXT')) || process.env.PATHEXT,
105105
}).toLowerCase()
106106
} catch (err) {
107107
pathToInitial = initialCmd.toLowerCase()
@@ -192,4 +192,14 @@ const stdioResult = (stdout, stderr, { stdioString = true, stdio }) => {
192192
return result
193193
}
194194

195+
// case insensitive lookup in an object
196+
const findInObject = (obj, key) => {
197+
key = key.toLowerCase()
198+
for (const objKey of Object.keys(obj).sort()) {
199+
if (objKey.toLowerCase() === key) {
200+
return obj[objKey]
201+
}
202+
}
203+
}
204+
195205
module.exports = promiseSpawn

test/shell.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,5 +206,42 @@ t.test('cmd', (t) => {
206206
t.ok(proc.called)
207207
})
208208

209+
t.test('which respects variant casing for provided env PATH/PATHEXT', async (t) => {
210+
const PATH = 'C:\\Windows\\System32'
211+
const PATHEXT = 'EXE'
212+
213+
const promiseSpawnMock = t.mock('../lib/index.js', {
214+
which: {
215+
sync: (key, opts) => {
216+
t.equal(key, 'dir')
217+
t.equal(opts.path, PATH)
218+
t.equal(opts.pathext, PATHEXT)
219+
return 'dir.exe'
220+
},
221+
},
222+
})
223+
224+
const proc = spawk.spawn('cmd.exe', ['/d', '/s', '/c', 'dir ^"with^ spaces^"'], {
225+
shell: false,
226+
windowsVerbatimArguments: true,
227+
})
228+
229+
const result = await promiseSpawnMock('dir', ['with spaces'], {
230+
env: {
231+
pAtH: PATH,
232+
pathEXT: PATHEXT,
233+
},
234+
shell: 'cmd.exe',
235+
})
236+
t.hasStrict(result, {
237+
code: 0,
238+
signal: undefined,
239+
stdout: '',
240+
stderr: '',
241+
})
242+
243+
t.ok(proc.called)
244+
})
245+
209246
t.end()
210247
})

0 commit comments

Comments
 (0)