UNPKG

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