"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/npm/lib/utils/lifecycle.js" (8 Mar 2017, 11230 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 exports = module.exports = lifecycle
    2 exports.cmd = cmd
    3 exports.makeEnv = makeEnv
    4 exports._incorrectWorkingDirectory = _incorrectWorkingDirectory
    5 
    6 var log = require('npmlog')
    7 var spawn = require('./spawn')
    8 var npm = require('../npm.js')
    9 var path = require('path')
   10 var fs = require('graceful-fs')
   11 var chain = require('slide').chain
   12 var Stream = require('stream').Stream
   13 var PATH = 'PATH'
   14 var uidNumber = require('uid-number')
   15 var umask = require('./umask')
   16 var usage = require('./usage')
   17 var output = require('./output.js')
   18 
   19 // windows calls it's path 'Path' usually, but this is not guaranteed.
   20 if (process.platform === 'win32') {
   21   PATH = 'Path'
   22   Object.keys(process.env).forEach(function (e) {
   23     if (e.match(/^PATH$/i)) {
   24       PATH = e
   25     }
   26   })
   27 }
   28 
   29 function logid (pkg, stage) {
   30   return pkg._id + '~' + stage + ':'
   31 }
   32 
   33 function lifecycle (pkg, stage, wd, unsafe, failOk, cb) {
   34   if (typeof cb !== 'function') {
   35     cb = failOk
   36     failOk = false
   37   }
   38   if (typeof cb !== 'function') {
   39     cb = unsafe
   40     unsafe = false
   41   }
   42   if (typeof cb !== 'function') {
   43     cb = wd
   44     wd = null
   45   }
   46 
   47   while (pkg && pkg._data) pkg = pkg._data
   48   if (!pkg) return cb(new Error('Invalid package data'))
   49 
   50   log.info('lifecycle', logid(pkg, stage), pkg._id)
   51   if (!pkg.scripts) pkg.scripts = {}
   52 
   53   if (npm.config.get('ignore-scripts')) {
   54     log.info('lifecycle', logid(pkg, stage), 'ignored because ignore-scripts is set to true', pkg._id)
   55     pkg.scripts = {}
   56   }
   57 
   58   validWd(wd || path.resolve(npm.dir, pkg.name), function (er, wd) {
   59     if (er) return cb(er)
   60 
   61     unsafe = unsafe || npm.config.get('unsafe-perm')
   62 
   63     if ((wd.indexOf(npm.dir) !== 0 || _incorrectWorkingDirectory(wd, pkg)) &&
   64         !unsafe && pkg.scripts[stage]) {
   65       log.warn('lifecycle', logid(pkg, stage), 'cannot run in wd',
   66         '%s %s (wd=%s)', pkg._id, pkg.scripts[stage], wd
   67       )
   68       return cb()
   69     }
   70 
   71     // set the env variables, then run scripts as a child process.
   72     var env = makeEnv(pkg)
   73     env.npm_lifecycle_event = stage
   74     env.npm_node_execpath = env.NODE = env.NODE || process.execPath
   75     env.npm_execpath = require.main.filename
   76 
   77     // 'nobody' typically doesn't have permission to write to /tmp
   78     // even if it's never used, sh freaks out.
   79     if (!npm.config.get('unsafe-perm')) env.TMPDIR = wd
   80 
   81     lifecycle_(pkg, stage, wd, env, unsafe, failOk, cb)
   82   })
   83 }
   84 
   85 function _incorrectWorkingDirectory (wd, pkg) {
   86   return wd.lastIndexOf(pkg.name) !== wd.length - pkg.name.length
   87 }
   88 
   89 function lifecycle_ (pkg, stage, wd, env, unsafe, failOk, cb) {
   90   var pathArr = []
   91   var p = wd.split('node_modules')
   92   var acc = path.resolve(p.shift())
   93 
   94   p.forEach(function (pp) {
   95     pathArr.unshift(path.join(acc, 'node_modules', '.bin'))
   96     acc = path.join(acc, 'node_modules', pp)
   97   })
   98   pathArr.unshift(path.join(acc, 'node_modules', '.bin'))
   99 
  100   // we also unshift the bundled node-gyp-bin folder so that
  101   // the bundled one will be used for installing things.
  102   pathArr.unshift(path.join(__dirname, '..', '..', 'bin', 'node-gyp-bin'))
  103 
  104   // prefer current node interpreter in child scripts
  105   pathArr.push(path.dirname(process.execPath))
  106 
  107   if (env[PATH]) pathArr.push(env[PATH])
  108   env[PATH] = pathArr.join(process.platform === 'win32' ? ';' : ':')
  109 
  110   var packageLifecycle = pkg.scripts && pkg.scripts.hasOwnProperty(stage)
  111 
  112   if (packageLifecycle) {
  113     // define this here so it's available to all scripts.
  114     env.npm_lifecycle_script = pkg.scripts[stage]
  115   } else {
  116     log.silly('lifecycle', logid(pkg, stage), 'no script for ' + stage + ', continuing')
  117   }
  118 
  119   function done (er) {
  120     if (er) {
  121       if (npm.config.get('force')) {
  122         log.info('lifecycle', logid(pkg, stage), 'forced, continuing', er)
  123         er = null
  124       } else if (failOk) {
  125         log.warn('lifecycle', logid(pkg, stage), 'continuing anyway', er.message)
  126         er = null
  127       }
  128     }
  129     cb(er)
  130   }
  131 
  132   chain(
  133     [
  134       packageLifecycle && [runPackageLifecycle, pkg, env, wd, unsafe],
  135       [runHookLifecycle, pkg, env, wd, unsafe]
  136     ],
  137     done
  138   )
  139 }
  140 
  141 function validWd (d, cb) {
  142   fs.stat(d, function (er, st) {
  143     if (er || !st.isDirectory()) {
  144       var p = path.dirname(d)
  145       if (p === d) {
  146         return cb(new Error('Could not find suitable wd'))
  147       }
  148       return validWd(p, cb)
  149     }
  150     return cb(null, d)
  151   })
  152 }
  153 
  154 function runPackageLifecycle (pkg, env, wd, unsafe, cb) {
  155   // run package lifecycle scripts in the package root, or the nearest parent.
  156   var stage = env.npm_lifecycle_event
  157   var cmd = env.npm_lifecycle_script
  158 
  159   var note = '\n> ' + pkg._id + ' ' + stage + ' ' + wd +
  160              '\n> ' + cmd + '\n'
  161   runCmd(note, cmd, pkg, env, stage, wd, unsafe, cb)
  162 }
  163 
  164 var running = false
  165 var queue = []
  166 function dequeue () {
  167   running = false
  168   if (queue.length) {
  169     var r = queue.shift()
  170     runCmd.apply(null, r)
  171   }
  172 }
  173 
  174 function runCmd (note, cmd, pkg, env, stage, wd, unsafe, cb) {
  175   if (running) {
  176     queue.push([note, cmd, pkg, env, stage, wd, unsafe, cb])
  177     return
  178   }
  179 
  180   running = true
  181   log.pause()
  182   var user = unsafe ? null : npm.config.get('user')
  183   var group = unsafe ? null : npm.config.get('group')
  184 
  185   if (log.level !== 'silent') {
  186     output(note)
  187   }
  188   log.verbose('lifecycle', logid(pkg, stage), 'unsafe-perm in lifecycle', unsafe)
  189 
  190   if (process.platform === 'win32') {
  191     unsafe = true
  192   }
  193 
  194   if (unsafe) {
  195     runCmd_(cmd, pkg, env, wd, stage, unsafe, 0, 0, cb)
  196   } else {
  197     uidNumber(user, group, function (er, uid, gid) {
  198       runCmd_(cmd, pkg, env, wd, stage, unsafe, uid, gid, cb)
  199     })
  200   }
  201 }
  202 
  203 function runCmd_ (cmd, pkg, env, wd, stage, unsafe, uid, gid, cb_) {
  204   function cb (er) {
  205     cb_.apply(null, arguments)
  206     log.resume()
  207     process.nextTick(dequeue)
  208   }
  209 
  210   var conf = {
  211     cwd: wd,
  212     env: env,
  213     stdio: [ 0, 1, 2 ]
  214   }
  215 
  216   if (!unsafe) {
  217     conf.uid = uid ^ 0
  218     conf.gid = gid ^ 0
  219   }
  220 
  221   var sh = 'sh'
  222   var shFlag = '-c'
  223 
  224   if (process.platform === 'win32') {
  225     sh = process.env.comspec || 'cmd'
  226     shFlag = '/d /s /c'
  227     conf.windowsVerbatimArguments = true
  228   }
  229 
  230   log.verbose('lifecycle', logid(pkg, stage), 'PATH:', env[PATH])
  231   log.verbose('lifecycle', logid(pkg, stage), 'CWD:', wd)
  232   log.silly('lifecycle', logid(pkg, stage), 'Args:', [shFlag, cmd])
  233 
  234   var proc = spawn(sh, [shFlag, cmd], conf)
  235 
  236   proc.on('error', procError)
  237   proc.on('close', function (code, signal) {
  238     log.silly('lifecycle', logid(pkg, stage), 'Returned: code:', code, ' signal:', signal)
  239     if (signal) {
  240       process.kill(process.pid, signal)
  241     } else if (code) {
  242       var er = new Error('Exit status ' + code)
  243     }
  244     procError(er)
  245   })
  246   process.once('SIGTERM', procKill)
  247 
  248   function procError (er) {
  249     if (er) {
  250       log.info('lifecycle', logid(pkg, stage), 'Failed to exec ' + stage + ' script')
  251       er.message = pkg._id + ' ' + stage + ': `' + cmd + '`\n' +
  252                    er.message
  253       if (er.code !== 'EPERM') {
  254         er.code = 'ELIFECYCLE'
  255       }
  256       fs.stat(npm.dir, function (statError, d) {
  257         if (statError && statError.code === 'ENOENT' && npm.dir.split(path.sep).slice(-1)[0] === 'node_modules') {
  258           log.warn('', 'Local package.json exists, but node_modules missing, did you mean to install?')
  259         }
  260       })
  261       er.pkgid = pkg._id
  262       er.stage = stage
  263       er.script = cmd
  264       er.pkgname = pkg.name
  265     }
  266     process.removeListener('SIGTERM', procKill)
  267     return cb(er)
  268   }
  269   function procKill () {
  270     proc.kill()
  271   }
  272 }
  273 
  274 function runHookLifecycle (pkg, env, wd, unsafe, cb) {
  275   // check for a hook script, run if present.
  276   var stage = env.npm_lifecycle_event
  277   var hook = path.join(npm.dir, '.hooks', stage)
  278   var cmd = hook
  279 
  280   fs.stat(hook, function (er) {
  281     if (er) return cb()
  282     var note = '\n> ' + pkg._id + ' ' + stage + ' ' + wd +
  283                '\n> ' + cmd
  284     runCmd(note, hook, pkg, env, stage, wd, unsafe, cb)
  285   })
  286 }
  287 
  288 function makeEnv (data, prefix, env) {
  289   prefix = prefix || 'npm_package_'
  290   if (!env) {
  291     env = {}
  292     for (var i in process.env) {
  293       if (!i.match(/^npm_/)) {
  294         env[i] = process.env[i]
  295       }
  296     }
  297 
  298     // npat asks for tap output
  299     if (npm.config.get('npat')) env.TAP = 1
  300 
  301     // express and others respect the NODE_ENV value.
  302     if (npm.config.get('production')) env.NODE_ENV = 'production'
  303   } else if (!data.hasOwnProperty('_lifecycleEnv')) {
  304     Object.defineProperty(data, '_lifecycleEnv',
  305       {
  306         value: env,
  307         enumerable: false
  308       }
  309     )
  310   }
  311 
  312   for (i in data) {
  313     if (i.charAt(0) !== '_') {
  314       var envKey = (prefix + i).replace(/[^a-zA-Z0-9_]/g, '_')
  315       if (i === 'readme') {
  316         continue
  317       }
  318       if (data[i] && typeof data[i] === 'object') {
  319         try {
  320           // quick and dirty detection for cyclical structures
  321           JSON.stringify(data[i])
  322           makeEnv(data[i], envKey + '_', env)
  323         } catch (ex) {
  324           // usually these are package objects.
  325           // just get the path and basic details.
  326           var d = data[i]
  327           makeEnv(
  328             { name: d.name, version: d.version, path: d.path },
  329             envKey + '_',
  330             env
  331           )
  332         }
  333       } else {
  334         env[envKey] = String(data[i])
  335         env[envKey] = env[envKey].indexOf('\n') !== -1
  336                         ? JSON.stringify(env[envKey])
  337                         : env[envKey]
  338       }
  339     }
  340   }
  341 
  342   if (prefix !== 'npm_package_') return env
  343 
  344   prefix = 'npm_config_'
  345   var pkgConfig = {}
  346   var keys = npm.config.keys
  347   var pkgVerConfig = {}
  348   var namePref = data.name + ':'
  349   var verPref = data.name + '@' + data.version + ':'
  350 
  351   keys.forEach(function (i) {
  352     // in some rare cases (e.g. working with nerf darts), there are segmented
  353     // "private" (underscore-prefixed) config names -- don't export
  354     if (i.charAt(0) === '_' && i.indexOf('_' + namePref) !== 0 || i.match(/:_/)) {
  355       return
  356     }
  357     var value = npm.config.get(i)
  358     if (value instanceof Stream || Array.isArray(value)) return
  359     if (i.match(/umask/)) value = umask.toString(value)
  360     if (!value) value = ''
  361     else if (typeof value === 'number') value = '' + value
  362     else if (typeof value !== 'string') value = JSON.stringify(value)
  363 
  364     value = value.indexOf('\n') !== -1
  365           ? JSON.stringify(value)
  366           : value
  367     i = i.replace(/^_+/, '')
  368     var k
  369     if (i.indexOf(namePref) === 0) {
  370       k = i.substr(namePref.length).replace(/[^a-zA-Z0-9_]/g, '_')
  371       pkgConfig[k] = value
  372     } else if (i.indexOf(verPref) === 0) {
  373       k = i.substr(verPref.length).replace(/[^a-zA-Z0-9_]/g, '_')
  374       pkgVerConfig[k] = value
  375     }
  376     var envKey = (prefix + i).replace(/[^a-zA-Z0-9_]/g, '_')
  377     env[envKey] = value
  378   })
  379 
  380   prefix = 'npm_package_config_'
  381   ;[pkgConfig, pkgVerConfig].forEach(function (conf) {
  382     for (var i in conf) {
  383       var envKey = (prefix + i)
  384       env[envKey] = conf[i]
  385     }
  386   })
  387 
  388   return env
  389 }
  390 
  391 function cmd (stage) {
  392   function CMD (args, cb) {
  393     npm.commands['run-script']([stage].concat(args), cb)
  394   }
  395   CMD.usage = usage(stage, 'npm ' + stage + ' [-- <args>]')
  396   var installedShallow = require('./completion/installed-shallow.js')
  397   CMD.completion = function (opts, cb) {
  398     installedShallow(opts, function (d) {
  399       return d.scripts && d.scripts[stage]
  400     }, cb)
  401   }
  402   return CMD
  403 }