Comparing version 2.1.0 to 3.0.0
'use strict' | ||
const POSIX = ` | ||
command_not_found_handler() { | ||
function mkPosix (opts) { | ||
return ` | ||
command_not_found_${opts.isBash ? 'handle' : 'handler'}() { | ||
# Do not run within a pipe | ||
@@ -12,7 +13,9 @@ if test ! -t 1; then | ||
echo "Trying with npx..." | ||
npx $* | ||
npx ${opts.install ? '' : '--no-install '}$* | ||
return $? | ||
}` | ||
} | ||
const FISH = ` | ||
function mkFish (opts) { | ||
return ` | ||
function __fish_command_not_found_on_interactive --on-event fish_prompt | ||
@@ -24,3 +27,3 @@ functions --erase __fish_command_not_found_handler | ||
echo "Trying with npx..." | ||
npx $argv | ||
npx ${opts.install ? '' : '--no-install '}$argv | ||
end | ||
@@ -30,20 +33,23 @@ | ||
end` | ||
} | ||
module.exports = function autoFallback (shell) { | ||
const SHELL = process.env.SHELL || '' | ||
module.exports = autoFallback | ||
function autoFallback (shell, fromEnv, opts) { | ||
if (shell.includes('bash')) { | ||
return mkPosix({isBash: true, install: opts.install}) | ||
} | ||
if (shell === 'bash' || SHELL.includes('bash')) { | ||
return POSIX.replace('handler()', 'handle()') | ||
if (shell.includes('zsh')) { | ||
return mkPosix({isBash: false, install: opts.install}) | ||
} | ||
if (shell === 'zsh' || SHELL.includes('zsh')) { | ||
return POSIX | ||
if (shell.includes('fish')) { | ||
return mkFish(opts) | ||
} | ||
if (shell === 'fish' || SHELL.includes('fish')) { | ||
return FISH | ||
if (fromEnv) { | ||
return autoFallback(fromEnv, null, opts) | ||
} | ||
console.error('Only Bash, Zsh, and Fish shells are supported :(') | ||
process.exit(1) | ||
} |
@@ -5,2 +5,34 @@ # Change Log | ||
<a name="3.0.0"></a> | ||
# [3.0.0](https://github.com/zkat/npx/compare/v2.1.0...v3.0.0) (2017-06-03) | ||
### Bug Fixes | ||
* **args:** accept argv as arg and fix minor bugs ([46f10fe](https://github.com/zkat/npx/commit/46f10fe)) | ||
* **deps:** explicitly add mkdirp and rimraf to devDeps ([832c75d](https://github.com/zkat/npx/commit/832c75d)) | ||
* **docs:** misc tweaks to docs ([ed70a7b](https://github.com/zkat/npx/commit/ed70a7b)) | ||
* **exec:** escape binaries and args to cp.exec (#18) ([55d6a11](https://github.com/zkat/npx/commit/55d6a11)) | ||
* **fallback:** shells were sometimes ignored based on $SHELL ([07b7efc](https://github.com/zkat/npx/commit/07b7efc)) | ||
* **get-prefix:** nudge isRootPath ([1ab31eb](https://github.com/zkat/npx/commit/1ab31eb)) | ||
* **help:** correctly enable -h and --help ([adc2f45](https://github.com/zkat/npx/commit/adc2f45)) | ||
* **startup:** delay loading some things to speed up startup ([6b32bf5](https://github.com/zkat/npx/commit/6b32bf5)) | ||
### Features | ||
* **cmd:** do some heuristic guesswork on default command names (#23) ([2404420](https://github.com/zkat/npx/commit/2404420)) | ||
* **ignore:** add --ignore-existing option (#20) ([0866a83](https://github.com/zkat/npx/commit/0866a83)) | ||
* **install:** added --no-install option to prevent install fallbacks ([a5fbdaf](https://github.com/zkat/npx/commit/a5fbdaf)) | ||
* **package:** multiple --package options are now accepted ([f2fa6b3](https://github.com/zkat/npx/commit/f2fa6b3)) | ||
* **save:** remove all save-related functionality (#19) ([ab77f6c](https://github.com/zkat/npx/commit/ab77f6c)) | ||
* **shell:** run -c strings inside a system shell (#22) ([17db461](https://github.com/zkat/npx/commit/17db461)) | ||
### BREAKING CHANGES | ||
* **save:** npx can no longer be used to save packages locally or globally. Use an actual package manager for that, instead. | ||
<a name="2.1.0"></a> | ||
@@ -7,0 +39,0 @@ # [2.1.0](https://github.com/zkat/npx/compare/v2.0.1...v2.1.0) (2017-06-01) |
@@ -5,3 +5,3 @@ 'use strict' | ||
const fs = BB.promisifyAll(require('fs')) | ||
const statAsync = BB.promisify(require('fs').stat) | ||
const path = require('path') | ||
@@ -34,2 +34,5 @@ | ||
if (parent === current) { | ||
// This _should_ only happen for root paths, but we already | ||
// guard against that above. I think this is pretty much dead | ||
// code, but npm was doing it, and I'm paranoid :s | ||
return current | ||
@@ -46,3 +49,3 @@ } else { | ||
function fileExists (f) { | ||
return fs.statAsync(f).catch({code: 'ENOENT'}, () => false) | ||
return statAsync(f).catch({code: 'ENOENT'}, () => false) | ||
} | ||
@@ -52,4 +55,4 @@ | ||
return process.platform === 'win32' | ||
? p.match(/[a-z]:[/\\]?/i) | ||
? p.match(/^[a-z]+:[/\\]?$/i) | ||
: p === '/' | ||
} |
136
index.js
@@ -6,4 +6,3 @@ #!/usr/bin/env node | ||
const autoFallback = require('./auto-fallback.js') | ||
const cp = require('child_process') | ||
const child = require('./child') | ||
const getPrefix = require('./get-prefix.js') | ||
@@ -13,5 +12,5 @@ const parseArgs = require('./parse-args.js') | ||
const pkg = require('./package.json') | ||
let rimraf | ||
const updateNotifier = require('update-notifier') | ||
const which = BB.promisify(require('which')) | ||
const yargs = require('yargs') | ||
@@ -23,7 +22,15 @@ const PATH_SEP = process.platform === 'win32' ? ';' : ':' | ||
module.exports = main | ||
function main (argv) { | ||
const shell = argv['shell-auto-fallback'] | ||
if (shell || shell === '') { | ||
console.log(autoFallback(shell)) | ||
process.exit(0) | ||
const fallback = require('./auto-fallback.js')( | ||
shell, process.env.SHELL, argv | ||
) | ||
if (fallback) { | ||
console.log(fallback) | ||
process.exit(0) | ||
} else { | ||
process.exit(1) | ||
} | ||
} | ||
@@ -33,3 +40,3 @@ | ||
console.error('\nERROR: You must supply a command.\n') | ||
yargs.showHelp() | ||
parseArgs.showHelp() | ||
process.exit(1) | ||
@@ -43,3 +50,3 @@ } | ||
).then(cmdPath => { | ||
return runCommand(cmdPath, argv.cmdOpts) | ||
return child.runCommand(cmdPath, argv.cmdOpts, argv) | ||
}).catch(err => { | ||
@@ -52,2 +59,3 @@ console.error(err.message) | ||
module.exports._localBinPath = localBinPath | ||
function localBinPath (cwd) { | ||
@@ -59,3 +67,4 @@ return getPrefix(cwd).then(prefix => { | ||
function getCmdPath (command, spec, npmOpts) { | ||
module.exports._getCmdPath = getCmdPath | ||
function getCmdPath (command, specs, npmOpts) { | ||
return getExistingPath(command, npmOpts).then(cmdPath => { | ||
@@ -69,7 +78,11 @@ if (cmdPath) { | ||
const prefix = path.join(cache, '_npx') | ||
return installPackage(spec, prefix, npmOpts).then(() => { | ||
process.env.PATH = `${ | ||
path.join(prefix, 'bin') | ||
}${PATH_SEP}${process.env.PATH}` | ||
return which(command) | ||
if (!rimraf) { rimraf = BB.promisify(require('rimraf')) } | ||
// TODO: this is a bit heavy-handed but it's the safest one right now | ||
return rimraf(prefix).then(() => { | ||
return installPackages(specs, prefix, npmOpts).then(() => { | ||
process.env.PATH = `${ | ||
path.join(prefix, 'bin') | ||
}${PATH_SEP}${process.env.PATH}` | ||
return which(command) | ||
}) | ||
}) | ||
@@ -81,46 +94,33 @@ }) | ||
module.exports._getExistingPath = getExistingPath | ||
function getExistingPath (command, opts) { | ||
if ( | ||
opts.saveProd || | ||
opts.saveDev || | ||
opts.saveOptional || | ||
opts.saveBundle || | ||
opts.saveExact || | ||
opts.global || | ||
opts.prefix || | ||
opts.cmdHadVersion || | ||
opts.packageRequested | ||
) { | ||
if (opts.cmdHadVersion || opts.packageRequested || opts.ignoreExisting) { | ||
return BB.resolve(false) | ||
} else { | ||
return which(command).catch({code: 'ENOENT'}, () => false) | ||
return which(command).catch({code: 'ENOENT'}, err => { | ||
if (!opts.install) { | ||
throw err | ||
} | ||
}) | ||
} | ||
} | ||
module.exports._getNpmCache = getNpmCache | ||
function getNpmCache (opts) { | ||
return which('npm').then(npmPath => { | ||
return BB.fromNode(cb => { | ||
cp.exec(`${npmPath} config get cache${ | ||
opts.userconfig ? ` --userconfig ${opts.userconfig}` : '' | ||
}`, {}, cb) | ||
}).then(cache => cache.trim()) | ||
}) | ||
const args = ['config', 'get', 'cache'] | ||
if (opts.userconfig) { | ||
args.push('--userconfig', opts.userconfig) | ||
} | ||
return child.exec(npmPath, ['config', 'get', 'cache']) | ||
}).then(cache => cache.trim()) | ||
} | ||
function buildArgs (spec, prefix, opts) { | ||
const args = ['install', spec] | ||
if (opts.saveProd) args.push('--save', '--save-prod') | ||
if (opts.saveDev) args.push('--save-dev') | ||
if (opts.saveOptional) args.push('--save-optional') | ||
if (opts.saveBundle) args.push('--save-bundle') | ||
if (opts.saveExact) args.push('--save-exact') | ||
if (opts.global) args.push('--global') | ||
if (opts.prefix) args.push('--prefix', opts.prefix) | ||
if (args.length === 2) { | ||
// No save opts passed in. Save it to the SUPERSEKRIT cache | ||
args.push('--global', '--prefix', prefix) | ||
} | ||
module.exports._buildArgs = buildArgs | ||
function buildArgs (specs, prefix, opts) { | ||
const args = ['install'].concat(specs) | ||
args.push('--global', '--prefix', prefix) | ||
if (opts.cache) args.push('--cache', opts.cache) | ||
if (opts.userconfig) args.push('--userconfig', opts.userconfig) | ||
args.push('--loglevel', 'error') | ||
args.push('--loglevel', 'error', '--json') | ||
@@ -130,43 +130,15 @@ return args | ||
function installPackage (spec, prefix, npmOpts) { | ||
const args = buildArgs(spec, prefix, npmOpts) | ||
module.exports._installPackages = installPackages | ||
function installPackages (specs, prefix, npmOpts) { | ||
const args = buildArgs(specs, prefix, npmOpts) | ||
return which('npm').then(npmPath => { | ||
return BB.fromNode(cb => { | ||
const child = cp.spawn(npmPath, args, { | ||
stdio: [0, 2, 2] // pipe npm's output to stderr | ||
}) | ||
child.on('error', cb) | ||
child.on('close', code => { | ||
if (code === 0) { | ||
cb() | ||
} else { | ||
cb(new Error(`Install for ${spec} failed with code ${code}`)) | ||
} | ||
}) | ||
}) | ||
}) | ||
} | ||
function runCommand (cmdPath, cmdOpts) { | ||
return spawn(cmdPath, cmdOpts, { | ||
stdio: 'inherit' | ||
}).catch({code: 'ENOENT'}, () => { | ||
throw new Error(`npx: command not found: ${path.basename(cmdPath)}`) | ||
}) | ||
} | ||
function spawn (cmd, args, opts) { | ||
return BB.fromNode(cb => { | ||
const child = cp.spawn(cmd, args, opts) | ||
child.on('error', cb) | ||
child.on('close', code => { | ||
if (code) { | ||
const err = new Error(`Command failed: ${cmd} ${args}`) | ||
err.exitCode = code | ||
cb(err) | ||
} else { | ||
cb() | ||
return child.spawn(npmPath, args, { | ||
stdio: [0, 'ignore', 2] // pipe npm's output to stderr | ||
}).catch(err => { | ||
if (err.exitCode) { | ||
err.message = `Install for ${specs} failed with code ${err.exitCode}` | ||
} | ||
throw err | ||
}) | ||
}) | ||
} |
{ | ||
"name": "npx", | ||
"version": "2.1.0", | ||
"version": "3.0.0", | ||
"description": "execute npm package binaries", | ||
@@ -40,2 +40,3 @@ "main": "index.js", | ||
"npm-package-arg": "^5.0.1", | ||
"rimraf": "^2.6.1", | ||
"update-notifier": "^2.1.0", | ||
@@ -54,5 +55,7 @@ "which": "^1.2.14", | ||
"marked-man": "^0.2.1", | ||
"mkdirp": "^0.5.1", | ||
"nyc": "^10.3.2", | ||
"standard": "^9.0.2", | ||
"standard-version": "^4.0.0", | ||
"tacks": "^1.2.6", | ||
"tap": "^10.3.2", | ||
@@ -59,0 +62,0 @@ "weallbehave": "^1.2.0", |
'use strict' | ||
const npa = require('npm-package-arg') | ||
const path = require('path') | ||
const yargs = require('yargs') | ||
const usage = `$0 [--package|-p <package>] [--cache <path>] [--save-dev|-D] [--save-prod|-P] [--save-optional|-O] [--save-bundle|-B] [--save-exact|-E] [--global|-g] [--prefix|-C] [--userconfig <path>] [-c <string>] [--shell-auto-fallback [shell]] [--version|-v] [--] <command>[@version] [command-arg]...` | ||
const usage = `$0 [--package|-p <package>] [--cache <path>] [--no-install] [--userconfig <path>] [-c <string>] [--shell <string>] [--shell-auto-fallback [<shell>]] [--ignore-existing] [--version|-v] [--] <command>[@version] [command-arg]...` | ||
module.exports = parseArgs | ||
function parseArgs () { | ||
function parseArgs (argv) { | ||
argv = argv || process.argv | ||
const parser = yargs | ||
.usage(`Execute a binary from an npm package\n${usage}`) | ||
.usage(`Execute binaries from npm packages.\n${usage}`) | ||
.option('package', { | ||
alias: 'p', | ||
type: 'string', | ||
describe: 'package to be installed' | ||
describe: 'Package to be installed.' | ||
}) | ||
.option('cache', { | ||
type: 'string', | ||
describe: 'location of the npm cache' | ||
describe: 'Location of the npm cache.' | ||
}) | ||
.option('save-prod', { | ||
alias: 'P', | ||
.option('install', { | ||
type: 'boolean', | ||
describe: 'add to project\'s dependencies' | ||
describe: 'Skip installation if a package is missing.', | ||
default: true | ||
}) | ||
.option('save-dev', { | ||
alias: 'D', | ||
type: 'boolean', | ||
describe: 'add to project\'s devDependencies' | ||
}) | ||
.option('save-optional', { | ||
alias: 'O', | ||
type: 'boolean', | ||
describe: 'add to project\'s optionalDependencies' | ||
}) | ||
.option('save-bundle', { | ||
alias: 'B', | ||
type: 'boolean', | ||
describe: 'add to project\'s bundleDependencies' | ||
}) | ||
.option('save-exact', { | ||
alias: 'E', | ||
type: 'boolean', | ||
describe: 'save the exact specifier instead of a semver range' | ||
}) | ||
.option('global', { | ||
alias: 'g', | ||
type: 'boolean', | ||
describe: 'install the package globally' | ||
}) | ||
.option('prefix', { | ||
alias: 'C', | ||
type: 'boolean', | ||
describe: 'location to install global items, or where to run the install if not used with -g' | ||
}) | ||
.option('userconfig', { | ||
type: 'string', | ||
describe: 'path to user npmrc' | ||
describe: 'Path to user npmrc.' | ||
}) | ||
@@ -63,21 +35,33 @@ .option('call', { | ||
type: 'string', | ||
describe: 'execute string as if inside `npm run-script`' | ||
describe: 'Execute string as if inside `npm run-script`.' | ||
}) | ||
.option('shell', { | ||
alias: 's', | ||
type: 'string', | ||
describe: 'Shell to execute the command with, if any.', | ||
default: false | ||
}) | ||
.option('shell-auto-fallback', { | ||
choices: ['', 'bash', 'fish', 'zsh'], | ||
describe: 'generate shell code to use npx as the "command not found" fallback', | ||
describe: 'Generate shell code to use npx as the "command not found" fallback.', | ||
requireArg: false, | ||
type: 'string' | ||
}) | ||
.option('ignore-existing', { | ||
describe: 'Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.', | ||
type: 'boolean' | ||
}) | ||
.version() | ||
.alias('version', 'v') | ||
.help() | ||
.alias('help', 'h') | ||
.epilogue('For the full documentation, see the manual page for npx(1).') | ||
const opts = parser.getOptions() | ||
const bools = new Set(opts.boolean) | ||
const raw = process.argv | ||
let cmdIndex | ||
let hasDashDash | ||
for (let i = 2; i < raw.length; i++) { | ||
const opt = raw[i] | ||
for (let i = 2; i < argv.length; i++) { | ||
const opt = argv[i] | ||
if (opt === '--') { | ||
@@ -87,3 +71,3 @@ hasDashDash = true | ||
} else if (opt[0] === '-') { | ||
if (!bools.has(opt.replace(/^--?/, ''))) { | ||
if (!bools.has(opt.replace(/^--?(no-)?/i, ''))) { | ||
i++ | ||
@@ -97,15 +81,23 @@ } | ||
if (cmdIndex) { | ||
const parsed = parser.parse(process.argv.slice(0, cmdIndex)) | ||
const parsedCmd = npa(process.argv[cmdIndex]) | ||
const parsed = parser.parse(argv.slice(0, cmdIndex)) | ||
const parsedCmd = npa(argv[cmdIndex]) | ||
parsed.command = parsed.package | ||
? process.argv[cmdIndex] | ||
: parsedCmd.name | ||
parsed.cmdOpts = process.argv.slice(cmdIndex + 1) | ||
? argv[cmdIndex] | ||
: guessCmdName(parsedCmd) | ||
parsed.cmdOpts = argv.slice(cmdIndex + 1) | ||
if (typeof parsed.package === 'string') { | ||
parsed.package = [parsed.package] | ||
} | ||
parsed.packageRequested = !!parsed.package | ||
parsed.cmdHadVersion = parsedCmd.name !== parsedCmd.raw | ||
const pkg = parsed.package || process.argv[cmdIndex] | ||
parsed.p = parsed.package = npa(pkg).toString() | ||
parsed.cmdHadVersion = parsed.package | ||
? false | ||
: parsedCmd.name !== parsedCmd.raw | ||
const pkg = parsed.package || [argv[cmdIndex]] | ||
parsed.p = parsed.package = pkg.map(p => npa(p).toString()) | ||
return parsed | ||
} else { | ||
const parsed = parser.argv | ||
const parsed = parser.parse(argv) | ||
if (typeof parsed.package === 'string') { | ||
parsed.package = [parsed.package] | ||
} | ||
if (parsed.call) { | ||
@@ -116,17 +108,23 @@ const splitCmd = parsed.call.trim().split(/\s+/) | ||
? splitCmd[0] | ||
: parsedCmd.name | ||
: guessCmdName(parsedCmd) | ||
parsed.cmdOpts = splitCmd.slice(1) | ||
parsed.packageRequested = !!parsed.package | ||
parsed.cmdHadVersion = parsedCmd.name !== parsedCmd.raw | ||
const pkg = parsed.package || splitCmd[0] | ||
parsed.p = parsed.package = npa(pkg).toString() | ||
parsed.cmdHadVersion = parsed.package | ||
? false | ||
: parsedCmd.name !== parsedCmd.raw | ||
const pkg = parsed.package || [splitCmd[0]] | ||
parsed.p = parsed.package = pkg.map(p => npa(p).toString()) | ||
} else if (hasDashDash) { | ||
const splitCmd = parsed._ | ||
const splitCmd = parsed._.slice(2) | ||
const parsedCmd = npa(splitCmd[0]) | ||
parsed.command = parsed.package | ||
? splitCmd[0] | ||
: parsedCmd.name | ||
: guessCmdName(parsedCmd) | ||
parsed.cmdOpts = splitCmd.slice(1) | ||
parsed.packageRequested = !!parsed.package | ||
parsed.cmdHadVersion = parsedCmd.name !== parsedCmd.raw | ||
parsed.cmdHadVersion = parsed.package | ||
? false | ||
: parsedCmd.name !== parsedCmd.raw | ||
const pkg = parsed.package || [splitCmd[0]] | ||
parsed.p = parsed.package = pkg.map(p => npa(p).toString()) | ||
} | ||
@@ -136,1 +134,29 @@ return parsed | ||
} | ||
parseArgs.showHelp = () => yargs.showHelp() | ||
module.exports._guessCmdName = guessCmdName | ||
function guessCmdName (spec) { | ||
if (typeof spec === 'string') { spec = npa(spec) } | ||
if (spec.scope) { | ||
return spec.name.slice(spec.scope.length + 1) | ||
} else if (spec.registry) { | ||
return spec.name | ||
} else if (spec.hosted && spec.hosted.project) { | ||
return spec.hosted.project | ||
} else if (spec.type === 'git') { | ||
const match = spec.fetchSpec.match(/([a-z0-9-]+)(?:\.git)?$/i) | ||
return match[1] | ||
} else if (spec.type === 'directory') { | ||
return path.basename(spec.fetchSpec) | ||
} else if (spec.type === 'file' || spec.type === 'remote') { | ||
let ext = path.extname(spec.fetchSpec) | ||
if (ext === '.gz') { | ||
ext = path.extname(path.basename(spec.fetchSpec, ext)) + ext | ||
} | ||
return path.basename(spec.fetchSpec, ext).replace(/-\d+\.\d+\.\d+(?:-[a-z0-9.\-+]+)?$/i, '') | ||
} | ||
console.error(`Unable to guess a binary name from ${spec.raw}. Please use --package.`) | ||
return null | ||
} |
@@ -7,3 +7,3 @@ [![npm](https://img.shields.io/npm/v/npx.svg)](https://npm.im/npx) [![license](https://img.shields.io/npm/l/npx.svg)](https://npm.im/npx) [![Travis](https://img.shields.io/travis/zkat/npx.svg)](https://travis-ci.org/zkat/npx) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/zkat/npx?svg=true)](https://ci.appveyor.com/project/zkat/npx) [![Coverage Status](https://coveralls.io/repos/github/zkat/npx/badge.svg?branch=latest)](https://coveralls.io/github/zkat/npx?branch=latest) | ||
`npx [--package|-p <package>] [--cache <path>] [--save-dev|-D] [--save-prod|-P] [--save-optional|-O] [--save-bundle|-B] [--save-exact|-E] [--global|-g] [--prefix|-C] [--userconfig <path>] [-c <string>] [--version|-v] [--] <command>[@version] [command-arg]...` | ||
`npx [--package|-p <package>] [--cache <path>] [--userconfig <path>] [-c <string>] [--shell|-s <string>] [--no-install] [--shell-auto-fallback [<shell>]] [--ignore-existing] [--version|-v] [--] <command>[@version] [command-arg]...` | ||
@@ -18,22 +18,26 @@ ## INSTALL | ||
By default, `<command>` will be installed prior to execution. An optional `@version` may be appended to specify the package version required. | ||
By default, `npx` will check whether `<command>` exists in `$PATH`, or in the local project binaries, and execute that. If `<command>` is not found, it will be installed prior to execution. | ||
If a version specifier is included, or if `--package` is used, npx will ignore the version of the package in the current path, if it exists. | ||
Unless a `--package` option is specified, `npx` will try to guess the name of the binary to invoke depending on the specifier provided. All package specifiers understood by `npm` may be used with `npx`, including git specifiers, remote tarballs, local directories, or scoped packages. | ||
* `-p, --package <package>` - define the package to be installed. This defaults to the value of `<command>`. This is only needed for packages with multiple binaries if you want to call one of the other executables, or where the binary name does not match the package name. If this option is provided `<command>` will be executed as-is, without interpreting `@version` if it's there. | ||
An optional `@version` may be appended to specify the package version required, which defaults to `latest` only if `<command>` is not in the path. If the command is already present and no explicit version specifier was requested, the existing command will be used. | ||
If a version specifier is included, or if `--package` is used, npx will ignore the version of the package in the current path, if it exists. This can also be forced with the `--ignore-existing` flag. | ||
* `-p, --package <package>` - define the package to be installed. This defaults to the value of `<command>`. This is only needed for packages with multiple binaries if you want to call one of the other executables, or where the binary name does not match the package name. If this option is provided `<command>` will be executed as-is, without interpreting `@version` if it's there. Multiple `--package` options may be provided, and all the packages specified will be installed. | ||
* `--no-install` - If passed to `npx`, it will only try to run `<command>` if it already exists in the current path or in `$prefix/node_modules/.bin`. It won't try to install missing commands. | ||
* `--cache <path>` - set the location of the npm cache. Defaults to npm's own cache settings. | ||
* `-g, --global` - install the package globally before execution. | ||
* `--userconfig <path>` - path to the user configuration file to pass to npm. Defaults to whatever npm's current default is. | ||
* `-D, --save-dev, -P, --save-prod, -O, --save-optional, -B, --save-bundle, -E, --save-exact` - install the package in the current npm project and save it to `package.json` following the same option conventions for this as `npm install` would. | ||
* `-c <string>` - Execute `<string>` inside a shell. For unix, this will be `/bin/sh -c <string>`. For Windows, it will be `cmd.exe /d /s /c <string>`. Only the first item in `<string>` will be automatically used as `<command>`. Any others _must_ use `-p`. | ||
* `-C, --prefix` - The location to install global items. If used without `-g`, will force any installs to run in the specified folder. Defaults to whatever npm's default is. | ||
* `--shell <string>` - The shell to invoke the command with, if any. Defaults to `false`. | ||
* `--userconfig` - path to the user configuration file to pass to npm. Defaults to whatever npm's current default is. | ||
* `--shell-auto-fallback [<shell>]` - Generates shell code to override your shell's "command not found" handler with one that calls `npx`. Tries to figure out your shell, or you can pass its name (either `bash`, `fish`, or `zsh`) as an option. See below for how to install. | ||
* `-c <string>` - Execute `<string>` with delayed environment variable evaluation. | ||
* `--ignore-existing` - If this flag is set, npx will not look in `$PATH`, or in the current package's `node_modules/.bin` for an existing version before deciding whether to install. Binaries in those paths will still be available for execution, but will be shadowed by any packages requested by this install. | ||
* `--shell-auto-fallback [shell]` - Generates shell code to override your shell's "command not found" handler with one that calls `npx`. Tries to figure out your shell, or you can pass its name (either `bash`, `fish`, or `zsh`) as an option. See below for how to install. | ||
* `-v, --version` - Show the current npx version. | ||
@@ -47,3 +51,3 @@ | ||
$ npm i -D webpack | ||
$ npx webpack -- ... | ||
$ npx webpack ... | ||
``` | ||
@@ -60,16 +64,36 @@ | ||
### Execute binary and add it to package.json as a devDependency | ||
### Invoking a command from a github repository | ||
``` | ||
$ npx -D webpack -- ... | ||
$ cat package.json | ||
...webpack added to "devDependencies" | ||
$ npx github:piuccio/cowsay | ||
...or... | ||
$ npx git+ssh://my.hosted.git:cowsay.git#semver:^1 | ||
...etc... | ||
``` | ||
### Execute a full shell command using one npx call w/ multiple packages | ||
``` | ||
$ npx -p lolcatjs -p cowsay -c 'echo "foo" | cowsay | lolcatjs' | ||
... | ||
_____ | ||
< foo > | ||
----- | ||
\ ^__^ | ||
\ (oo)\_______ | ||
(__)\ )\/\ | ||
||----w | | ||
|| || | ||
``` | ||
## SHELL AUTO FALLBACK | ||
To install permanently, add the relevant line to your `~/.bashrc`, `~/.zshrc`, `~/.config/fish/config.fish`, or as needed. To install just for the shell session, simply run the line. | ||
You can configure `npx` to run as your default fallback command when you type something in the command line but the command is not found. This includes installing packages that were not found in the local prefix either. | ||
Be warned that this _will_ send (almost) all your missed commands over the internet, then fetch and execute code automatically. | ||
Currently, `zsh`, `bash`, and `fish` are supported. You can access these completion scripts using `npx --shell-auto-fallback <shell>`. | ||
To install permanently, add the relevant line below to your `~/.bashrc`, `~/.zshrc`, `~/.config/fish/config.fish`, or as needed. To install just for the shell session, simply run the line. | ||
You can optionally pass through `--no-install` when generating the fallback to prevent it from installing packages if the command is missing. | ||
### For Bash: | ||
@@ -81,12 +105,12 @@ | ||
### For Fish: | ||
### For Zsh: | ||
``` | ||
$ source (npx --shell-auto-fallback fish | psub) | ||
$ source <(npx --shell-auto-fallback zsh) | ||
``` | ||
### For Zsh: | ||
### For Fish: | ||
``` | ||
$ source <(npx --shell-auto-fallback zsh) | ||
$ source (npx --shell-auto-fallback fish | psub) | ||
``` | ||
@@ -93,0 +117,0 @@ |
Sorry, the diff of this file is not supported yet
2156902
701
32642
134
6
9
160
+ Addedrimraf@^2.6.1
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedfs.realpath@1.0.0(transitive)
+ Addedglob@7.2.3(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedrimraf@2.7.1(transitive)
+ Addedwrappy@1.0.2(transitive)