Files
pnpm/lib/fetch.js

68 lines
1.8 KiB
JavaScript

'use strict'
const debug = require('debug')('pnpm:fetch')
const crypto = require('crypto')
const gunzip = require('gunzip-maybe')
const tar = require('tar-fs')
const fs = require('fs')
/*
* Fetches a tarball `tarball` and extracts it into `dir`
*/
module.exports = function fetch (dir, dist, opts) {
if (!dist.local) {
return opts.got.getStream(dist.tarball)
.then(stream => fetchStream(dir, dist.tarball, dist.shasum, opts.log, stream))
}
return unpackStream(fs.createReadStream(dist.tarball), dir)
}
function fetchStream (dir, tarball, shasum, log, stream) {
return new Promise((resolve, reject) => {
const actualShasum = crypto.createHash('sha1')
let size
let downloaded = 0
unpackStream(
stream
.on('response', start)
.on('data', _ => { actualShasum.update(_) })
.on('error', reject), dir
).then(finish)
function start (res) {
if (res.statusCode !== 200) {
return reject(new Error('' + tarball + ': invalid response ' + res.statusCode))
}
log('download-start')
if ('content-length' in res.headers) {
size = +res.headers['content-length']
res.on('data', chunk => {
downloaded += chunk.length
log('downloading', { done: downloaded, total: size })
})
}
}
function finish () {
const digest = actualShasum.digest('hex')
debug('finish %s %s', shasum, tarball)
if (shasum && digest !== shasum) {
return reject(new Error('' + tarball + ': incorrect shasum (expected ' + shasum + ', got ' + digest + ')'))
}
return resolve(dir)
}
})
}
function unpackStream (stream, dir) {
return new Promise((resolve, reject) => {
stream
.pipe(gunzip()).on('error', reject)
.pipe(tar.extract(dir, { strip: 1 })).on('error', reject)
.on('finish', resolve)
})
}