Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/make-spawn-args.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const makeSpawnArgs = options => {
npm_lifecycle_event: event,
npm_lifecycle_script: cmd,
npm_config_node_gyp,
})
}, event)

const spawnOpts = {
env: spawnEnv,
Expand Down
9 changes: 8 additions & 1 deletion lib/set-path.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const { log } = require('proc-log')
const { resolve, dirname, delimiter } = require('path')
// the path here is relative, even though it does not need to be
// in order to make the posix tests pass in windows
Expand All @@ -6,14 +7,20 @@ const nodeGypPath = resolve(__dirname, '../lib/node-gyp-bin')
// Windows typically calls its PATH environ 'Path', but this is not
// guaranteed, nor is it guaranteed to be the only one. Merge them
// all together in the order they appear in the object.
const setPATH = (projectPath, binPaths, env) => {
const setPATH = (projectPath, binPaths, env, event) => {
const PATH = Object.keys(env).filter(p => /^path$/i.test(p) && env[p])
.map(p => env[p].split(delimiter))
.reduce((set, p) => set.concat(p.filter(concatted => !set.includes(concatted))), [])
.join(delimiter)

const pathArr = []
if (binPaths) {
for (const bin of binPaths) {
if (bin.includes(delimiter)) {
const context = event ? `"${event}" script` : 'script execution'
log.warn('run-script', `Project path contains delimiter ("${delimiter}"), ${context} may not behave as expected.`)
}
}
pathArr.push(...binPaths)
}
// unshift the ./node_modules/.bin from every folder
Expand Down
48 changes: 48 additions & 0 deletions test/make-spawn-args.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,52 @@ t.test('spawn args', async t => {
}))
t.ok(spawk.done())
})

await t.test('binPaths containing delimiter logs warning', async t => {
const { delimiter } = require('path')
const { log } = require('proc-log')
const originalWarn = log.warn
let warningLogged = false

log.warn = (category, message) => {
if (category === 'run-script' && message.includes('delimiter') && message.includes('"test" script')) {
warningLogged = true
}
}
spawk.spawn(
/.*/,
false,
e => (e.env.PATH || e.env.Path).includes(`/path/with${delimiter}delimiter`)
)
await t.resolves(() => runScript({
pkg,
binPaths: [`/path/with${delimiter}delimiter`],
path: testdir,
event: 'test',
}))

t.ok(warningLogged, 'warning should be logged when binPath contains delimiter')
t.ok(spawk.done())
log.warn = originalWarn
})

await t.test('binPaths containing delimiter logs generic warning without event', async t => {
const { delimiter } = require('path')
const { log } = require('proc-log')
const setPATH = require('../lib/set-path.js')
const originalWarn = log.warn
let warningLogged = false

log.warn = (category, message) => {
if (category === 'run-script' && message.includes('delimiter') && message.includes('script execution')) {
warningLogged = true
}
}

// Test setPATH directly with no event (simulates npx/exec scenario)
setPATH(testdir, [`/path/with${delimiter}delimiter`], {}, '')

t.ok(warningLogged, 'warning should be logged with generic message when no event')
log.warn = originalWarn
})
})
Loading