You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							219 lines
						
					
					
						
							5.6 KiB
						
					
					
				
			
		
		
	
	
							219 lines
						
					
					
						
							5.6 KiB
						
					
					
				'use strict'; | 
						|
 | 
						|
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | 
						|
 | 
						|
var fs = require('fs'); | 
						|
var path = require('path'); | 
						|
var which = require('which'); | 
						|
 | 
						|
var findPrefix = require('./find-prefix'); | 
						|
 | 
						|
var PATH = getPATHKey(); | 
						|
var SEPARATOR = getPATHSeparator(); | 
						|
 | 
						|
/** | 
						|
 * Get new $PATH setting with additional paths supplied by the npm. | 
						|
 * | 
						|
 * @param Object options Config options Object. | 
						|
 * @param Object options.env Environment to use. Default: process.env | 
						|
 * @param String options.wd Working directory. Default: process.cwd() | 
						|
 * @param Function fn callback function. | 
						|
 */ | 
						|
 | 
						|
function getPath(options, fn) { | 
						|
  options.cwd = options.cwd || process.cwd(); | 
						|
  var env = options.env = options.env || process.env; | 
						|
  var pathArr = getPathArr(options); | 
						|
 | 
						|
  findPrefix(options, function (err, prefixPath) { | 
						|
    if (!err && prefixPath) { | 
						|
      // ignore err if cannot find prefix | 
						|
      pathArr.unshift(path.join(prefixPath, 'node_modules', '.bin')); | 
						|
    } | 
						|
 | 
						|
    whichNpm(options, function (err, npmPath) { | 
						|
      // we also unshift the bundled node-gyp-bin folder so that | 
						|
      // the bundled one will be used for installing things. | 
						|
 | 
						|
      // simply ignore this step if there was no npm found | 
						|
      if (err || !npmPath) { | 
						|
        // ...unless npm path was explicitly passed in | 
						|
        if (options.npm) { | 
						|
          return fn(err || new Error('Cannot find ' + options.npm)); | 
						|
        } | 
						|
      } else { | 
						|
        pathArr.unshift(path.join(path.dirname(npmPath), 'node-gyp-bin')); | 
						|
      } | 
						|
 | 
						|
      if (env[PATH]) pathArr = pathArr.concat(env[PATH].split(SEPARATOR)); | 
						|
 | 
						|
      // Remove duplicated entries | 
						|
      pathArr = [].concat(_toConsumableArray(new Set(pathArr))); | 
						|
 | 
						|
      fn(null, pathArr.join(SEPARATOR)); | 
						|
    }); | 
						|
  }); | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Async wrapper around `getPath`. | 
						|
 */ | 
						|
 | 
						|
function getPathAsync(options, fn) { | 
						|
  // options is optional | 
						|
  if (typeof options === 'function') { | 
						|
    fn = options; | 
						|
    options = {}; | 
						|
  } | 
						|
  // if no fn, execute as sync | 
						|
  if (typeof fn !== 'function') return getPathSync(options); | 
						|
  options = options || {}; | 
						|
  options.isSync = false; | 
						|
  return getPath(options, fn); | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Sync wrapper around `getPath`. | 
						|
 */ | 
						|
 | 
						|
function getPathSync(options) { | 
						|
  options = options || {}; | 
						|
  options.isSync = true; | 
						|
  var thePath = null; | 
						|
  // sync magic: if sync true, callback is executed sync | 
						|
  // therefore we can set thePath from inside it before returning | 
						|
  getPath(options, function (err, foundPath) { | 
						|
    if (err) throw err; | 
						|
    thePath = foundPath; | 
						|
  }); | 
						|
  return thePath; | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Change environment to include npm path adjustments. | 
						|
 * | 
						|
 * @param Object options Config options Object. | 
						|
 * @param Object options.env Environment to use. Default: process.env | 
						|
 * @param String options.wd Working directory. Default: process.cwd() | 
						|
 * @param Function fn callback function. | 
						|
 */ | 
						|
 | 
						|
function setPathAsync(options, fn) { | 
						|
  // options is optional | 
						|
  if (typeof options === 'function') { | 
						|
    fn = options; | 
						|
    options = {}; | 
						|
  } | 
						|
 | 
						|
  // if no fn, execute as sync | 
						|
  if (typeof fn !== 'function') return setPathSync(options); | 
						|
 | 
						|
  getPathAsync(options, function (err, newPath) { | 
						|
    if (err) return fn(err); | 
						|
    fn(null, options.env[PATH] = newPath); | 
						|
  }); | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Sync version of `setPathAsync` | 
						|
 */ | 
						|
function setPathSync(options) { | 
						|
  options = options || {}; | 
						|
  var newPath = getPathSync(options); | 
						|
  options.env[PATH] = newPath; | 
						|
  return newPath; | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Generate simple parts of the npm path. Basically everything that doesn't | 
						|
 * depend on potentially async operations. | 
						|
 * | 
						|
 * @return Array | 
						|
 */ | 
						|
function getPathArr(options) { | 
						|
  var wd = options.cwd; | 
						|
  var pathArr = []; | 
						|
  var p = wd.split(path.sep + 'node_modules' + path.sep); | 
						|
  var acc = path.resolve(p.shift()); | 
						|
 | 
						|
  // first add the directory containing the `node` executable currently | 
						|
  // running, so that any lifecycle script that invoke 'node' will execute | 
						|
  // this same one. | 
						|
  pathArr.unshift(path.dirname(process.execPath)); | 
						|
 | 
						|
  p.forEach(function (pp) { | 
						|
    pathArr.unshift(path.join(acc, 'node_modules', '.bin')); | 
						|
    acc = path.join(acc, 'node_modules', pp); | 
						|
  }); | 
						|
  pathArr.unshift(path.join(acc, 'node_modules', '.bin')); | 
						|
  return pathArr; | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Use callback-style signature but toggle sync execution if `isSync` is true. | 
						|
 * If options.npm is supplied, this will simply provide npm/bin/npm-cli. | 
						|
 */ | 
						|
function whichNpm(options, fn) { | 
						|
  var npmCli = options.npm && path.join(options.npm, 'bin', 'npm-cli.js'); | 
						|
 | 
						|
  if (options.isSync) { | 
						|
    var npmPath = null; | 
						|
 | 
						|
    try { | 
						|
      npmPath = fs.realpathSync(npmCli || which.sync('npm')); | 
						|
    } catch (err) { | 
						|
      return fn(err); | 
						|
    } | 
						|
 | 
						|
    fn(null, npmPath); | 
						|
    return; | 
						|
  } | 
						|
 | 
						|
  if (options.npm) { | 
						|
    fs.realpath(npmCli, fn); | 
						|
    return; | 
						|
  } | 
						|
 | 
						|
  which('npm', function (err, npmPath) { | 
						|
    if (err) return fn(err); | 
						|
    fs.realpath(npmPath, fn); | 
						|
  }); | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Get key to use as $PATH in environment | 
						|
 */ | 
						|
 | 
						|
function getPATHKey() { | 
						|
  var PATH = 'PATH'; | 
						|
 | 
						|
  // windows calls it's path 'Path' usually, but this is not guaranteed. | 
						|
  if (process.platform === 'win32') { | 
						|
    PATH = 'Path'; | 
						|
    Object.keys(process.env).forEach(function (e) { | 
						|
      if (e.match(/^PATH$/i)) { | 
						|
        PATH = e; | 
						|
      } | 
						|
    }); | 
						|
  } | 
						|
  return PATH; | 
						|
} | 
						|
 | 
						|
/** | 
						|
 * Get $PATH separator based on environment | 
						|
 */ | 
						|
function getPATHSeparator() { | 
						|
  return process.platform === 'win32' ? ';' : ':'; | 
						|
} | 
						|
 | 
						|
module.exports = setPathAsync; | 
						|
module.exports.get = getPathAsync; | 
						|
module.exports.get.sync = getPathSync; | 
						|
module.exports.getSync = getPathSync; | 
						|
 | 
						|
module.exports.set = setPathAsync; | 
						|
module.exports.set.sync = setPathSync; | 
						|
module.exports.setSync = setPathSync; | 
						|
 | 
						|
module.exports.PATH = PATH; | 
						|
module.exports.SEPARATOR = SEPARATOR; |