Spaces:
Running
Running
| 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 | |
| } | |