Skip to content

Commit

Permalink
deps: @npmcli/promise-spawn@7.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lukekarrys committed Aug 30, 2023
1 parent dbb18f4 commit 75642c6
Show file tree
Hide file tree
Showing 22 changed files with 1,080 additions and 35 deletions.
2 changes: 0 additions & 2 deletions DEPENDENCIES.md
Expand Up @@ -115,7 +115,6 @@ graph LR;
npm-->npm-profile;
npm-->npm-registry-fetch;
npm-->npm-user-validate;
npm-->npmcli-agent["@npmcli/agent"];
npm-->npmcli-arborist["@npmcli/arborist"];
npm-->npmcli-config["@npmcli/config"];
npm-->npmcli-docs["@npmcli/docs"];
Expand Down Expand Up @@ -541,7 +540,6 @@ graph LR;
npm-->npm-profile;
npm-->npm-registry-fetch;
npm-->npm-user-validate;
npm-->npmcli-agent["@npmcli/agent"];
npm-->npmcli-arborist["@npmcli/arborist"];
npm-->npmcli-config["@npmcli/config"];
npm-->npmcli-docs["@npmcli/docs"];
Expand Down
15 changes: 12 additions & 3 deletions node_modules/.gitignore
Expand Up @@ -30,6 +30,9 @@
!/@npmcli/git
!/@npmcli/git/node_modules/
/@npmcli/git/node_modules/*
!/@npmcli/git/node_modules/@npmcli/
/@npmcli/git/node_modules/@npmcli/*
!/@npmcli/git/node_modules/@npmcli/promise-spawn
!/@npmcli/git/node_modules/which
!/@npmcli/installed-package-contents
!/@npmcli/map-workspaces
Expand All @@ -38,13 +41,13 @@
!/@npmcli/node-gyp
!/@npmcli/package-json
!/@npmcli/promise-spawn
!/@npmcli/promise-spawn/node_modules/
/@npmcli/promise-spawn/node_modules/*
!/@npmcli/promise-spawn/node_modules/which
!/@npmcli/query
!/@npmcli/run-script
!/@npmcli/run-script/node_modules/
/@npmcli/run-script/node_modules/*
!/@npmcli/run-script/node_modules/@npmcli/
/@npmcli/run-script/node_modules/@npmcli/*
!/@npmcli/run-script/node_modules/@npmcli/promise-spawn
!/@npmcli/run-script/node_modules/which
!/@pkgjs/
/@pkgjs/*
Expand Down Expand Up @@ -226,6 +229,12 @@
!/once
!/p-map
!/pacote
!/pacote/node_modules/
/pacote/node_modules/*
!/pacote/node_modules/@npmcli/
/pacote/node_modules/@npmcli/*
!/pacote/node_modules/@npmcli/promise-spawn
!/pacote/node_modules/which
!/parse-conflict-json
!/path-is-absolute
!/path-key
Expand Down
@@ -0,0 +1,15 @@
The ISC License

Copyright (c) npm, Inc.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE NPM DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE NPM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
@@ -0,0 +1,68 @@
'use strict'

// eslint-disable-next-line max-len
// this code adapted from: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
const cmd = (input, doubleEscape) => {
if (!input.length) {
return '""'
}

let result
if (!/[ \t\n\v"]/.test(input)) {
result = input
} else {
result = '"'
for (let i = 0; i <= input.length; ++i) {
let slashCount = 0
while (input[i] === '\\') {
++i
++slashCount
}

if (i === input.length) {
result += '\\'.repeat(slashCount * 2)
break
}

if (input[i] === '"') {
result += '\\'.repeat(slashCount * 2 + 1)
result += input[i]
} else {
result += '\\'.repeat(slashCount)
result += input[i]
}
}
result += '"'
}

// and finally, prefix shell meta chars with a ^
result = result.replace(/[ !%^&()<>|"]/g, '^$&')
if (doubleEscape) {
result = result.replace(/[ !%^&()<>|"]/g, '^$&')
}

return result
}

const sh = (input) => {
if (!input.length) {
return `''`
}

if (!/[\t\n\r "#$&'()*;<>?\\`|~]/.test(input)) {
return input
}

// replace single quotes with '\'' and wrap the whole result in a fresh set of quotes
const result = `'${input.replace(/'/g, `'\\''`)}'`
// if the input string already had single quotes around it, clean those up
.replace(/^(?:'')+(?!$)/, '')
.replace(/\\'''/g, `\\'`)

return result
}

module.exports = {
cmd,
sh,
}
@@ -0,0 +1,195 @@
'use strict'

const { spawn } = require('child_process')
const os = require('os')
const which = require('which')

const escape = require('./escape.js')

// 'extra' object is for decorating the error a bit more
const promiseSpawn = (cmd, args, opts = {}, extra = {}) => {
if (opts.shell) {
return spawnWithShell(cmd, args, opts, extra)
}

let proc

const p = new Promise((res, rej) => {
proc = spawn(cmd, args, opts)

const stdout = []
const stderr = []

const reject = er => rej(Object.assign(er, {
cmd,
args,
...stdioResult(stdout, stderr, opts),
...extra,
}))

proc.on('error', reject)

if (proc.stdout) {
proc.stdout.on('data', c => stdout.push(c)).on('error', reject)
proc.stdout.on('error', er => reject(er))
}

if (proc.stderr) {
proc.stderr.on('data', c => stderr.push(c)).on('error', reject)
proc.stderr.on('error', er => reject(er))
}

proc.on('close', (code, signal) => {
const result = {
cmd,
args,
code,
signal,
...stdioResult(stdout, stderr, opts),
...extra,
}

if (code || signal) {
rej(Object.assign(new Error('command failed'), result))
} else {
res(result)
}
})
})

p.stdin = proc.stdin
p.process = proc
return p
}

const spawnWithShell = (cmd, args, opts, extra) => {
let command = opts.shell
// if shell is set to true, we use a platform default. we can't let the core
// spawn method decide this for us because we need to know what shell is in use
// ahead of time so that we can escape arguments properly. we don't need coverage here.
if (command === true) {
// istanbul ignore next
command = process.platform === 'win32' ? process.env.ComSpec : 'sh'
}

const options = { ...opts, shell: false }
const realArgs = []
let script = cmd

// first, determine if we're in windows because if we are we need to know if we're
// running an .exe or a .cmd/.bat since the latter requires extra escaping
const isCmd = /(?:^|\\)cmd(?:\.exe)?$/i.test(command)
if (isCmd) {
let doubleEscape = false

// find the actual command we're running
let initialCmd = ''
let insideQuotes = false
for (let i = 0; i < cmd.length; ++i) {
const char = cmd.charAt(i)
if (char === ' ' && !insideQuotes) {
break
}

initialCmd += char
if (char === '"' || char === "'") {
insideQuotes = !insideQuotes
}
}

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,
}).toLowerCase()
} catch (err) {
pathToInitial = initialCmd.toLowerCase()
}

doubleEscape = pathToInitial.endsWith('.cmd') || pathToInitial.endsWith('.bat')
for (const arg of args) {
script += ` ${escape.cmd(arg, doubleEscape)}`
}
realArgs.push('/d', '/s', '/c', script)
options.windowsVerbatimArguments = true
} else {
for (const arg of args) {
script += ` ${escape.sh(arg)}`
}
realArgs.push('-c', script)
}

return promiseSpawn(command, realArgs, options, extra)
}

// open a file with the default application as defined by the user's OS
const open = (_args, opts = {}, extra = {}) => {
const options = { ...opts, shell: true }
const args = [].concat(_args)

let platform = process.platform
// process.platform === 'linux' may actually indicate WSL, if that's the case
// we want to treat things as win32 anyway so the host can open the argument
if (platform === 'linux' && os.release().toLowerCase().includes('microsoft')) {
platform = 'win32'
}

let command = options.command
if (!command) {
if (platform === 'win32') {
// spawnWithShell does not do the additional os.release() check, so we
// have to force the shell here to make sure we treat WSL as windows.
options.shell = process.env.ComSpec
// also, the start command accepts a title so to make sure that we don't
// accidentally interpret the first arg as the title, we stick an empty
// string immediately after the start command
command = 'start ""'
} else if (platform === 'darwin') {
command = 'open'
} else {
command = 'xdg-open'
}
}

return spawnWithShell(command, args, options, extra)
}
promiseSpawn.open = open

const isPipe = (stdio = 'pipe', fd) => {
if (stdio === 'pipe' || stdio === null) {
return true
}

if (Array.isArray(stdio)) {
return isPipe(stdio[fd], fd)
}

return false
}

const stdioResult = (stdout, stderr, { stdioString = true, stdio }) => {
const result = {
stdout: null,
stderr: null,
}

// stdio is [stdin, stdout, stderr]
if (isPipe(stdio, 1)) {
result.stdout = Buffer.concat(stdout)
if (stdioString) {
result.stdout = result.stdout.toString().trim()
}
}

if (isPipe(stdio, 2)) {
result.stderr = Buffer.concat(stderr)
if (stdioString) {
result.stderr = result.stderr.toString().trim()
}
}

return result
}

module.exports = promiseSpawn
@@ -0,0 +1,50 @@
{
"name": "@npmcli/promise-spawn",
"version": "6.0.2",
"files": [
"bin/",
"lib/"
],
"main": "./lib/index.js",
"description": "spawn processes the way the npm cli likes to do",
"repository": {
"type": "git",
"url": "https://github.com/npm/promise-spawn.git"
},
"author": "GitHub Inc.",
"license": "ISC",
"scripts": {
"test": "tap",
"snap": "tap",
"lint": "eslint \"**/*.js\"",
"lintfix": "npm run lint -- --fix",
"posttest": "npm run lint",
"postsnap": "npm run lintfix --",
"postlint": "template-oss-check",
"template-oss-apply": "template-oss-apply --force"
},
"tap": {
"check-coverage": true,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"devDependencies": {
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/template-oss": "4.11.0",
"minipass": "^4.0.0",
"spawk": "^1.7.1",
"tap": "^16.0.1"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.11.0"
},
"dependencies": {
"which": "^3.0.0"
}
}

0 comments on commit 75642c6

Please sign in to comment.