1'use strict' 2 3const path = require('path') 4const nopt = require('nopt') 5const log = require('npmlog') 6const childProcess = require('child_process') 7const EE = require('events').EventEmitter 8const inherits = require('util').inherits 9const commands = [ 10 // Module build commands 11 'build', 12 'clean', 13 'configure', 14 'rebuild', 15 // Development Header File management commands 16 'install', 17 'list', 18 'remove' 19] 20const aliases = { 21 ls: 'list', 22 rm: 'remove' 23} 24 25// differentiate node-gyp's logs from npm's 26log.heading = 'gyp' 27 28function gyp () { 29 return new Gyp() 30} 31 32function Gyp () { 33 var self = this 34 35 this.devDir = '' 36 this.commands = {} 37 38 commands.forEach(function (command) { 39 self.commands[command] = function (argv, callback) { 40 log.verbose('command', command, argv) 41 return require('./' + command)(self, argv, callback) 42 } 43 }) 44} 45inherits(Gyp, EE) 46exports.Gyp = Gyp 47var proto = Gyp.prototype 48 49/** 50 * Export the contents of the package.json. 51 */ 52 53proto.package = require('../package.json') 54 55/** 56 * nopt configuration definitions 57 */ 58 59proto.configDefs = { 60 help: Boolean, // everywhere 61 arch: String, // 'configure' 62 cafile: String, // 'install' 63 debug: Boolean, // 'build' 64 directory: String, // bin 65 make: String, // 'build' 66 msvs_version: String, // 'configure' 67 ensure: Boolean, // 'install' 68 solution: String, // 'build' (windows only) 69 proxy: String, // 'install' 70 noproxy: String, // 'install' 71 devdir: String, // everywhere 72 nodedir: String, // 'configure' 73 loglevel: String, // everywhere 74 python: String, // 'configure' 75 'dist-url': String, // 'install' 76 tarball: String, // 'install' 77 jobs: String, // 'build' 78 thin: String // 'configure' 79} 80 81/** 82 * nopt shorthands 83 */ 84 85proto.shorthands = { 86 release: '--no-debug', 87 C: '--directory', 88 debug: '--debug', 89 j: '--jobs', 90 silly: '--loglevel=silly', 91 verbose: '--loglevel=verbose', 92 silent: '--loglevel=silent' 93} 94 95/** 96 * expose the command aliases for the bin file to use. 97 */ 98 99proto.aliases = aliases 100 101/** 102 * Parses the given argv array and sets the 'opts', 103 * 'argv' and 'command' properties. 104 */ 105 106proto.parseArgv = function parseOpts (argv) { 107 this.opts = nopt(this.configDefs, this.shorthands, argv) 108 this.argv = this.opts.argv.remain.slice() 109 110 var commands = this.todo = [] 111 112 // create a copy of the argv array with aliases mapped 113 argv = this.argv.map(function (arg) { 114 // is this an alias? 115 if (arg in this.aliases) { 116 arg = this.aliases[arg] 117 } 118 return arg 119 }, this) 120 121 // process the mapped args into "command" objects ("name" and "args" props) 122 argv.slice().forEach(function (arg) { 123 if (arg in this.commands) { 124 var args = argv.splice(0, argv.indexOf(arg)) 125 argv.shift() 126 if (commands.length > 0) { 127 commands[commands.length - 1].args = args 128 } 129 commands.push({ name: arg, args: [] }) 130 } 131 }, this) 132 if (commands.length > 0) { 133 commands[commands.length - 1].args = argv.splice(0) 134 } 135 136 // support for inheriting config env variables from npm 137 var npmConfigPrefix = 'npm_config_' 138 Object.keys(process.env).forEach(function (name) { 139 if (name.indexOf(npmConfigPrefix) !== 0) { 140 return 141 } 142 var val = process.env[name] 143 if (name === npmConfigPrefix + 'loglevel') { 144 log.level = val 145 } else { 146 // add the user-defined options to the config 147 name = name.substring(npmConfigPrefix.length) 148 // gyp@741b7f1 enters an infinite loop when it encounters 149 // zero-length options so ensure those don't get through. 150 if (name) { 151 this.opts[name] = val 152 } 153 } 154 }, this) 155 156 if (this.opts.loglevel) { 157 log.level = this.opts.loglevel 158 } 159 log.resume() 160} 161 162/** 163 * Spawns a child process and emits a 'spawn' event. 164 */ 165 166proto.spawn = function spawn (command, args, opts) { 167 if (!opts) { 168 opts = {} 169 } 170 if (!opts.silent && !opts.stdio) { 171 opts.stdio = [0, 1, 2] 172 } 173 var cp = childProcess.spawn(command, args, opts) 174 log.info('spawn', command) 175 log.info('spawn args', args) 176 return cp 177} 178 179/** 180 * Returns the usage instructions for node-gyp. 181 */ 182 183proto.usage = function usage () { 184 var str = [ 185 '', 186 ' Usage: node-gyp <command> [options]', 187 '', 188 ' where <command> is one of:', 189 commands.map(function (c) { 190 return ' - ' + c + ' - ' + require('./' + c).usage 191 }).join('\n'), 192 '', 193 'node-gyp@' + this.version + ' ' + path.resolve(__dirname, '..'), 194 'node@' + process.versions.node 195 ].join('\n') 196 return str 197} 198 199/** 200 * Version number getter. 201 */ 202 203Object.defineProperty(proto, 'version', { 204 get: function () { 205 return this.package.version 206 }, 207 enumerable: true 208}) 209 210module.exports = exports = gyp 211