Skip to content

Commit

Permalink
fix: parse options.env more similarly to process.env (#98)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
thecodrr committed Dec 21, 2023
1 parent d3ba687 commit 46fad5a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 2 deletions.
14 changes: 12 additions & 2 deletions lib/index.js
Expand Up @@ -100,8 +100,8 @@ const spawnWithShell = (cmd, args, opts, extra) => {
let pathToInitial
try {
pathToInitial = which.sync(initialCmd, {
path: (options.env && options.env.PATH) || process.env.PATH,
pathext: (options.env && options.env.PATHEXT) || process.env.PATHEXT,
path: (options.env && findInObject(options.env, 'PATH')) || process.env.PATH,
pathext: (options.env && findInObject(options.env, 'PATHEXT')) || process.env.PATHEXT,
}).toLowerCase()
} catch (err) {
pathToInitial = initialCmd.toLowerCase()
Expand Down Expand Up @@ -192,4 +192,14 @@ const stdioResult = (stdout, stderr, { stdioString = true, stdio }) => {
return result
}

// case insensitive lookup in an object
const findInObject = (obj, key) => {
key = key.toLowerCase()
for (const objKey of Object.keys(obj).sort()) {
if (objKey.toLowerCase() === key) {
return obj[objKey]
}
}
}

module.exports = promiseSpawn
37 changes: 37 additions & 0 deletions test/shell.js
Expand Up @@ -206,5 +206,42 @@ t.test('cmd', (t) => {
t.ok(proc.called)
})

t.test('which respects variant casing for provided env PATH/PATHEXT', async (t) => {
const PATH = 'C:\\Windows\\System32'
const PATHEXT = 'EXE'

const promiseSpawnMock = t.mock('../lib/index.js', {
which: {
sync: (key, opts) => {
t.equal(key, 'dir')
t.equal(opts.path, PATH)
t.equal(opts.pathext, PATHEXT)
return 'dir.exe'
},
},
})

const proc = spawk.spawn('cmd.exe', ['/d', '/s', '/c', 'dir ^"with^ spaces^"'], {
shell: false,
windowsVerbatimArguments: true,
})

const result = await promiseSpawnMock('dir', ['with spaces'], {
env: {
pAtH: PATH,
pathEXT: PATHEXT,
},
shell: 'cmd.exe',
})
t.hasStrict(result, {
code: 0,
signal: undefined,
stdout: '',
stderr: '',
})

t.ok(proc.called)
})

t.end()
})

0 comments on commit 46fad5a

Please sign in to comment.