123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- 'use strict';
-
- module.exports = wrap
- wrap.runMain = runMain
-
- const Module = require('module')
- const fs = require('fs')
- const cp = require('child_process')
- const ChildProcess = cp.ChildProcess
- const assert = require('assert')
- const crypto = require('crypto')
- const IS_WINDOWS = require('is-windows')()
- const makeDir = require('make-dir')
- const rimraf = require('rimraf')
- const path = require('path')
- const signalExit = require('signal-exit')
- const {IS_DEBUG, debug} = require("./lib/debug")
- const munge = require("./lib/munge")
- const homedir = require("./lib/homedir")
-
- const shebang = process.platform === 'os390' ?
- '#!/bin/env ' : '#!'
-
- const shim = shebang + process.execPath + '\n' +
- fs.readFileSync(path.join(__dirname, 'shim.js'))
-
- function wrap(argv, env, workingDir) {
- const spawnSyncBinding = process.binding('spawn_sync')
-
- // if we're passed in the working dir, then it means that setup
- // was already done, so no need.
- const doSetup = !workingDir
- if (doSetup) {
- workingDir = setup(argv, env)
- }
- const spawn = ChildProcess.prototype.spawn
- const spawnSync = spawnSyncBinding.spawn
-
- function unwrap() {
- if (doSetup && !IS_DEBUG) {
- rimraf.sync(workingDir)
- }
- ChildProcess.prototype.spawn = spawn
- spawnSyncBinding.spawn = spawnSync
- }
-
- spawnSyncBinding.spawn = wrappedSpawnFunction(spawnSync, workingDir)
- ChildProcess.prototype.spawn = wrappedSpawnFunction(spawn, workingDir)
-
- return unwrap
- }
-
- function wrappedSpawnFunction (fn, workingDir) {
- return wrappedSpawn
-
- function wrappedSpawn (options) {
- const mungedOptions = munge(workingDir, options)
- debug('WRAPPED', mungedOptions)
- return fn.call(this, mungedOptions)
- }
- }
-
- function setup(argv, env) {
- if (argv && typeof argv === 'object' && !env && !Array.isArray(argv)) {
- env = argv
- argv = []
- }
-
- if (!argv && !env) {
- throw new Error('at least one of "argv" and "env" required')
- }
-
- if (argv) {
- assert(Array.isArray(argv), 'argv must be an array')
- } else {
- argv = []
- }
-
- if (env) {
- assert(typeof env === 'object', 'env must be an object')
- } else {
- env = {}
- }
-
- debug('setup argv=%j env=%j', argv, env)
-
- // For stuff like --use_strict or --harmony, we need to inject
- // the argument *before* the wrap-main.
- const execArgv = []
- for (let i = 0; i < argv.length; i++) {
- if (argv[i].startsWith('-')) {
- execArgv.push(argv[i])
- if (argv[i] === '-r' || argv[i] === '--require') {
- execArgv.push(argv[++i])
- }
- } else {
- break
- }
- }
- if (execArgv.length) {
- if (execArgv.length === argv.length) {
- argv.length = 0
- } else {
- argv = argv.slice(execArgv.length)
- }
- }
-
- const key = process.pid + '-' + crypto.randomBytes(6).toString('hex')
- let workingDir = path.resolve(homedir, `.node-spawn-wrap-${key}`)
-
- const settings = JSON.stringify({
- module: __filename,
- deps: {
- foregroundChild: require.resolve('foreground-child'),
- signalExit: require.resolve('signal-exit'),
- debug: require.resolve('./lib/debug')
- },
- isWindows: IS_WINDOWS,
- key,
- workingDir,
- argv,
- execArgv,
- env,
- root: process.pid
- }, null, 2) + '\n'
-
- if (!IS_DEBUG) {
- signalExit(() => rimraf.sync(workingDir))
- }
-
- makeDir.sync(workingDir)
- workingDir = fs.realpathSync(workingDir)
- if (IS_WINDOWS) {
- const cmdShim =
- '@echo off\r\n' +
- 'SETLOCAL\r\n' +
- 'CALL :find_dp0\r\n' +
- 'SET PATHEXT=%PATHEXT:;.JS;=;%\r\n' +
- '"' + process.execPath + '" "%dp0%node" %*\r\n' +
- 'EXIT /b %errorlevel%\r\n'+
- ':find_dp0\r\n' +
- 'SET dp0=%~dp0\r\n' +
- 'EXIT /b\r\n'
-
- fs.writeFileSync(path.join(workingDir, 'node.cmd'), cmdShim)
- fs.chmodSync(path.join(workingDir, 'node.cmd'), '0755')
- }
- fs.writeFileSync(path.join(workingDir, 'node'), shim)
- fs.chmodSync(path.join(workingDir, 'node'), '0755')
- const cmdname = path.basename(process.execPath).replace(/\.exe$/i, '')
- if (cmdname !== 'node') {
- fs.writeFileSync(path.join(workingDir, cmdname), shim)
- fs.chmodSync(path.join(workingDir, cmdname), '0755')
- }
- fs.writeFileSync(path.join(workingDir, 'settings.json'), settings)
-
- return workingDir
- }
-
- function runMain () {
- process.argv.splice(1, 1)
- process.argv[1] = path.resolve(process.argv[1])
- delete require.cache[process.argv[1]]
- Module.runMain()
- }
|