1'use strict' 2 3const BB = require('bluebird') 4 5const cacache = require('cacache') 6const Fetcher = require('../fetch') 7const fs = require('fs') 8const pipe = BB.promisify(require('mississippi').pipe) 9const through = require('mississippi').through 10 11const readFileAsync = BB.promisify(fs.readFile) 12const statAsync = BB.promisify(fs.stat) 13 14const MAX_BULK_SIZE = 2 * 1024 * 1024 // 2MB 15 16// `file` packages refer to local tarball files. 17const fetchFile = module.exports = Object.create(null) 18 19Fetcher.impl(fetchFile, { 20 packument (spec, opts) { 21 return BB.reject(new Error('Not implemented yet')) 22 }, 23 24 manifest (spec, opts) { 25 // We can't do much here. `finalizeManifest` will take care of 26 // calling `tarball` to fill out all the necessary details. 27 return BB.resolve(null) 28 }, 29 30 // All the heavy lifting for `file` packages is done here. 31 // They're never cached. We just read straight out of the file. 32 // TODO - maybe they *should* be cached? 33 tarball (spec, opts) { 34 const src = spec._resolved || spec.fetchSpec 35 const stream = through() 36 statAsync(src).then(stat => { 37 if (spec._resolved) { stream.emit('manifest', spec) } 38 if (stat.size <= MAX_BULK_SIZE) { 39 // YAY LET'S DO THING IN BULK 40 return readFileAsync(src).then(data => { 41 if (opts.cache) { 42 return cacache.put( 43 opts.cache, `pacote:tarball:file:${src}`, data, { 44 integrity: opts.integrity 45 } 46 ).then(integrity => ({ data, integrity })) 47 } else { 48 return { data } 49 } 50 }).then(info => { 51 if (info.integrity) { stream.emit('integrity', info.integrity) } 52 stream.write(info.data, () => { 53 stream.end() 54 }) 55 }) 56 } else { 57 let integrity 58 const cacheWriter = !opts.cache 59 ? BB.resolve(null) 60 : (pipe( 61 fs.createReadStream(src), 62 cacache.put.stream(opts.cache, `pacote:tarball:${src}`, { 63 integrity: opts.integrity 64 }).on('integrity', d => { integrity = d }) 65 )) 66 return cacheWriter.then(() => { 67 if (integrity) { stream.emit('integrity', integrity) } 68 return pipe(fs.createReadStream(src), stream) 69 }) 70 } 71 }).catch(err => stream.emit('error', err)) 72 return stream 73 }, 74 75 fromManifest (manifest, spec, opts) { 76 return this.tarball(manifest || spec, opts) 77 } 78}) 79