Skip to content

Commit

Permalink
fix(npx): look for bins in local package.json
Browse files Browse the repository at this point in the history
  • Loading branch information
wraithgar authored and lukekarrys committed Nov 9, 2022
1 parent 1b29306 commit a767aae
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 31 deletions.
42 changes: 28 additions & 14 deletions workspaces/libnpmexec/lib/index.js
Expand Up @@ -79,7 +79,6 @@ const exec = async (opts) => {
const {
args = [],
call = '',
color = false,
localBin = resolve('./node_modules/.bin'),
locationMsg = undefined,
globalBin = '',
Expand All @@ -97,7 +96,6 @@ const exec = async (opts) => {
const run = () => runScript({
args,
call,
color,
flatOptions,
locationMsg,
output,
Expand All @@ -114,20 +112,36 @@ const exec = async (opts) => {

const needPackageCommandSwap = (args.length > 0) && (packages.length === 0)
// If they asked for a command w/o specifying a package, see if there is a
// bin that directly matches that name either globally or in the local tree.
// bin that directly matches that name:
// - in the local package itself
// - in the local tree
// - globally
if (needPackageCommandSwap) {
const dir = dirname(dirname(localBin))
const localBinPath = await localFileExists(dir, args[0], '/')
if (localBinPath) {
binPaths.push(localBinPath)
return await run()
} else if (globalPath && await fileExists(`${globalBin}/${args[0]}`)) {
binPaths.push(globalBin)
return await run()
let localManifest
try {
localManifest = await pacote.manifest(path, flatOptions)
} catch {
// no local package.json? no problem, move one.
}
if (localManifest?.bin?.[args[0]]) {
// we have to install the local package into the npx cache so that its
// bin links get set up
packages.push(path)
yes = true
flatOptions.installLinks = false
} else {
const dir = dirname(dirname(localBin))
const localBinPath = await localFileExists(dir, args[0], '/')
if (localBinPath) {
binPaths.push(localBinPath)
return await run()
} else if (globalPath && await fileExists(`${globalBin}/${args[0]}`)) {
binPaths.push(globalBin)
return await run()
}
// We swap out args[0] with the bin from the manifest later
packages.push(args[0])
}

// We swap out args[0] with the bin from the manifest later
packages.push(args[0])
}

// Resolve any directory specs so that the npx directory is unique to the
Expand Down
2 changes: 1 addition & 1 deletion workspaces/libnpmexec/lib/run-script.js
Expand Up @@ -15,7 +15,6 @@ const nocolor = {
const run = async ({
args,
call,
color,
flatOptions,
locationMsg,
output = () => {},
Expand All @@ -26,6 +25,7 @@ const run = async ({
}) => {
// turn list of args into command string
const script = call || args.shift() || scriptShell
const color = !!flatOptions.color
const colorize = color ? chalk : nocolor

// do the fakey runScript dance
Expand Down
22 changes: 7 additions & 15 deletions workspaces/libnpmexec/test/index.js
Expand Up @@ -24,39 +24,31 @@ const baseOpts = {
yes: true,
}

t.test('local pkg', async t => {
t.test('bin in local pkg', async t => {
const pkg = {
name: 'pkg',
name: '@npmcli/local-pkg-bin-test',
bin: {
a: 'index.js',
a: 'local-bin-test.js',
},
}
const path = t.testdir({
cache: {},
npxCache: {},
node_modules: {
'.bin': {},
a: {
'index.js': `#!/usr/bin/env node
'local-bin-test.js': `#!/usr/bin/env node
require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`,
},
},
'package.json': JSON.stringify(pkg),
})
const localBin = resolve(path, 'node_modules/.bin')
const runPath = path
const npxCache = resolve(path, 'npxCache')

const executable = resolve(path, 'node_modules/a')
const executable = resolve(path, 'local-bin-test.js')
fs.chmodSync(executable, 0o775)

await binLinks({
path: resolve(path, 'node_modules/a'),
pkg,
})

await libexec({
...baseOpts,
args: ['a', 'resfile'],
npxCache,
localBin,
path,
runPath,
Expand Down
3 changes: 2 additions & 1 deletion workspaces/libnpmexec/test/run-script.js
Expand Up @@ -4,6 +4,7 @@ const baseOpts = {
args: [],
call: '',
color: false,
flatOptions: {},
path: '',
runPath: '',
shell: process.platform === 'win32'
Expand Down Expand Up @@ -73,7 +74,7 @@ t.test('colorized interactive mode msg', async t => {
OUTPUT.push(msg)
},
runPath: '/foo/',
color: true,
flatOptions: { color: true },
})
t.matchSnapshot(OUTPUT.join('\n'), 'should print colorized output')
})
Expand Down

0 comments on commit a767aae

Please sign in to comment.