1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- const {spawn} = require('cross-spawn')
- const commandConvert = require('./command')
- const varValueConvert = require('./variable')
- module.exports = crossEnv
- const envSetterRegex = /(\w+)=('(.*)'|"(.*)"|(.*))/
- function crossEnv(args, options = {}) {
- const [envSetters, command, commandArgs] = parseCommand(args)
- const env = getEnvVars(envSetters)
- if (command) {
- const proc = spawn(
- // run `path.normalize` for command(on windows)
- commandConvert(command, env, true),
- // by default normalize is `false`, so not run for cmd args
- commandArgs.map(arg => commandConvert(arg, env)),
- {
- stdio: 'inherit',
- shell: options.shell,
- env,
- },
- )
- process.on('SIGTERM', () => proc.kill('SIGTERM'))
- process.on('SIGINT', () => proc.kill('SIGINT'))
- process.on('SIGBREAK', () => proc.kill('SIGBREAK'))
- process.on('SIGHUP', () => proc.kill('SIGHUP'))
- proc.on('exit', (code, signal) => {
- let crossEnvExitCode = code
- // exit code could be null when OS kills the process(out of memory, etc) or due to node handling it
- // but if the signal is SIGINT the user exited the process so we want exit code 0
- if (crossEnvExitCode === null) {
- crossEnvExitCode = signal === 'SIGINT' ? 0 : 1
- }
- process.exit(crossEnvExitCode) //eslint-disable-line no-process-exit
- })
- return proc
- }
- return null
- }
- function parseCommand(args) {
- const envSetters = {}
- let command = null
- let commandArgs = []
- for (let i = 0; i < args.length; i++) {
- const match = envSetterRegex.exec(args[i])
- if (match) {
- let value
- if (typeof match[3] !== 'undefined') {
- value = match[3]
- } else if (typeof match[4] === 'undefined') {
- value = match[5]
- } else {
- value = match[4]
- }
- envSetters[match[1]] = value
- } else {
- // No more env setters, the rest of the line must be the command and args
- let cStart = []
- cStart = args
- .slice(i)
- // Regex:
- // match "\'" or "'"
- // or match "\" if followed by [$"\] (lookahead)
- .map(a => {
- const re = /\\\\|(\\)?'|([\\])(?=[$"\\])/g
- // Eliminate all matches except for "\'" => "'"
- return a.replace(re, m => {
- if (m === '\\\\') return '\\'
- if (m === "\\'") return "'"
- return ''
- })
- })
- command = cStart[0]
- commandArgs = cStart.slice(1)
- break
- }
- }
- return [envSetters, command, commandArgs]
- }
- function getEnvVars(envSetters) {
- const envVars = {...process.env}
- if (process.env.APPDATA) {
- envVars.APPDATA = process.env.APPDATA
- }
- Object.keys(envSetters).forEach(varName => {
- envVars[varName] = varValueConvert(envSetters[varName], varName)
- })
- return envVars
- }
|