• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2
3const deprCheck = require('./utils/depr-check')
4const path = require('path')
5const log = require('npmlog')
6const pacote = require('pacote')
7const readPackageTree = require('read-package-tree')
8const rimraf = require('rimraf')
9const validate = require('aproba')
10const npa = require('npm-package-arg')
11const npm = require('./npm')
12let npmConfig
13const npmlog = require('npmlog')
14const limit = require('call-limit')
15const tempFilename = require('./utils/temp-filename.js')
16const replaceInfo = require('./utils/replace-info.js')
17const isWindows = require('./utils/is-windows.js')
18
19function andLogAndFinish (spec, tracker, done) {
20  validate('SOF|SZF|OOF|OZF', [spec, tracker, done])
21  return (er, pkg) => {
22    if (er) {
23      er.message = replaceInfo(er.message)
24      var spc = replaceInfo(String(spec))
25      log.silly('fetchPackageMetaData', 'error for ' + spc, er.message)
26      if (tracker) tracker.finish()
27    }
28    return done(er, pkg)
29  }
30}
31
32const LRUCache = require('lru-cache')
33const CACHE = new LRUCache({
34  max: 300 * 1024 * 1024,
35  length: (p) => p._contentLength
36})
37
38module.exports = limit(fetchPackageMetadata, npm.limit.fetch)
39function fetchPackageMetadata (spec, where, opts, done) {
40  validate('SSOF|SSFZ|OSOF|OSFZ', [spec, where, opts, done])
41
42  if (!done) {
43    done = opts
44    opts = {}
45  }
46  var tracker = opts.tracker
47  const logAndFinish = andLogAndFinish(spec, tracker, done)
48
49  if (typeof spec === 'object') {
50    var dep = spec
51  } else {
52    dep = npa(spec)
53  }
54  if (!isWindows && dep.type === 'directory' && /^[a-zA-Z]:/.test(dep.fetchSpec)) {
55    var err = new Error(`Can't install from windows path on a non-windows system: ${dep.fetchSpec.replace(/[/]/g, '\\')}`)
56    err.code = 'EWINDOWSPATH'
57    return logAndFinish(err)
58  }
59  if (!npmConfig) {
60    npmConfig = require('./config/figgy-config.js')
61  }
62  pacote.manifest(dep, npmConfig({
63    annotate: true,
64    fullMetadata: opts.fullMetadata,
65    log: tracker || npmlog,
66    memoize: CACHE,
67    where: where
68  })).then(
69    (pkg) => logAndFinish(null, deprCheck(pkg)),
70    (err) => {
71      if (dep.type !== 'directory') return logAndFinish(err)
72      if (err.code === 'ENOTDIR') {
73        var enolocal = new Error(`Could not install "${path.relative(process.cwd(), dep.fetchSpec)}" as it is not a directory and is not a file with a name ending in .tgz, .tar.gz or .tar`)
74        enolocal.code = 'ENOLOCAL'
75        if (err.stack) enolocal.stack = err.stack
76        return logAndFinish(enolocal)
77      } else if (err.code === 'ENOPACKAGEJSON') {
78        var enopackage = new Error(`Could not install from "${path.relative(process.cwd(), dep.fetchSpec)}" as it does not contain a package.json file.`)
79        enopackage.code = 'ENOLOCAL'
80        if (err.stack) enopackage.stack = err.stack
81        return logAndFinish(enopackage)
82      } else {
83        return logAndFinish(err)
84      }
85    }
86  )
87}
88
89module.exports.addBundled = addBundled
90function addBundled (pkg, next) {
91  validate('OF', arguments)
92  if (pkg._bundled !== undefined) return next(null, pkg)
93
94  if (!pkg.bundleDependencies && pkg._requested.type !== 'directory') return next(null, pkg)
95  const requested = pkg._requested || npa(pkg._from)
96  if (requested.type === 'directory') {
97    pkg._bundled = null
98    return readPackageTree(pkg._requested.fetchSpec, function (er, tree) {
99      if (tree) pkg._bundled = tree.children
100      return next(null, pkg)
101    })
102  }
103  pkg._bundled = null
104  const target = tempFilename('unpack')
105  if (!npmConfig) {
106    npmConfig = require('./config/figgy-config.js')
107  }
108  const opts = npmConfig({integrity: pkg._integrity})
109  pacote.extract(pkg._resolved || pkg._requested || npa.resolve(pkg.name, pkg.version), target, opts).then(() => {
110    log.silly('addBundled', 'read tarball')
111    readPackageTree(target, (err, tree) => {
112      if (err) { return next(err) }
113      log.silly('cleanup', 'remove extracted module')
114      rimraf(target, function () {
115        if (tree) {
116          pkg._bundled = tree.children
117        }
118        next(null, pkg)
119      })
120    })
121  }, next)
122}
123