1'use strict' 2 3const BB = require('bluebird') 4 5const Fetcher = require('../fetch') 6const glob = BB.promisify(require('glob')) 7const packDir = require('../util/pack-dir') 8const readJson = require('../util/read-json') 9const path = require('path') 10const pipe = BB.promisify(require('mississippi').pipe) 11const through = require('mississippi').through 12const normalizePackageBin = require('npm-normalize-package-bin') 13 14const readFileAsync = BB.promisify(require('fs').readFile) 15 16const fetchDirectory = module.exports = Object.create(null) 17 18Fetcher.impl(fetchDirectory, { 19 packument (spec, opts) { 20 return this.manifest(spec, opts).then(manifest => { 21 return Object.assign({}, manifest, { 22 'dist-tags': { 23 'latest': manifest.version 24 }, 25 time: { 26 [manifest.version]: (new Date()).toISOString() 27 }, 28 versions: { 29 [manifest.version]: manifest 30 } 31 }) 32 }) 33 }, 34 // `directory` manifests come from the actual manifest/lockfile data. 35 manifest (spec, opts) { 36 const pkgPath = path.join(spec.fetchSpec, 'package.json') 37 const srPath = path.join(spec.fetchSpec, 'npm-shrinkwrap.json') 38 return BB.join( 39 readFileAsync(pkgPath).then(readJson).catch({ code: 'ENOENT' }, err => { 40 err.code = 'ENOPACKAGEJSON' 41 throw err 42 }), 43 readFileAsync(srPath).then(readJson).catch({ code: 'ENOENT' }, () => null), 44 (pkg, sr) => { 45 pkg._shrinkwrap = sr 46 pkg._hasShrinkwrap = !!sr 47 pkg._resolved = spec.fetchSpec 48 pkg._integrity = false // Don't auto-calculate integrity 49 pkg._shasum = false // Don't auto-calculate shasum either 50 return pkg 51 } 52 ).then(pkg => { 53 if (!pkg.bin && pkg.directories && pkg.directories.bin) { 54 const dirBin = pkg.directories.bin 55 return glob(path.join(spec.fetchSpec, dirBin, '/**'), { nodir: true }).then(matches => { 56 matches.forEach(filePath => { 57 const relative = path.relative(spec.fetchSpec, filePath) 58 if (relative && relative[0] !== '.') { 59 if (!pkg.bin) { pkg.bin = {} } 60 pkg.bin[path.basename(relative)] = relative 61 } 62 }) 63 }).then(() => pkg) 64 } else { 65 return pkg 66 } 67 }).then(pkg => normalizePackageBin(pkg)) 68 }, 69 70 // As of npm@5, the npm installer doesn't pack + install directories: it just 71 // creates symlinks. This code is here because `npm pack` still needs the 72 // ability to create a tarball from a local directory. 73 tarball (spec, opts) { 74 const stream = through() 75 this.manifest(spec, opts).then(mani => { 76 return pipe(this.fromManifest(mani, spec, opts), stream) 77 }).catch(err => stream.emit('error', err)) 78 return stream 79 }, 80 81 // `directory` tarballs are generated in a very similar way to git tarballs. 82 fromManifest (manifest, spec, opts) { 83 const stream = through() 84 packDir(manifest, manifest._resolved, manifest._resolved, stream, opts).catch(err => { 85 stream.emit('error', err) 86 }) 87 return stream 88 } 89}) 90