• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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