summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/npm-registry-fetch/node_modules/cacache/lib/content/write.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/npm-registry-fetch/node_modules/cacache/lib/content/write.js')
-rw-r--r--deps/npm/node_modules/npm-registry-fetch/node_modules/cacache/lib/content/write.js162
1 files changed, 162 insertions, 0 deletions
diff --git a/deps/npm/node_modules/npm-registry-fetch/node_modules/cacache/lib/content/write.js b/deps/npm/node_modules/npm-registry-fetch/node_modules/cacache/lib/content/write.js
new file mode 100644
index 0000000000..a79ae92902
--- /dev/null
+++ b/deps/npm/node_modules/npm-registry-fetch/node_modules/cacache/lib/content/write.js
@@ -0,0 +1,162 @@
+'use strict'
+
+const BB = require('bluebird')
+
+const contentPath = require('./path')
+const fixOwner = require('../util/fix-owner')
+const fs = require('graceful-fs')
+const moveFile = require('../util/move-file')
+const PassThrough = require('stream').PassThrough
+const path = require('path')
+const pipe = BB.promisify(require('mississippi').pipe)
+const rimraf = BB.promisify(require('rimraf'))
+const ssri = require('ssri')
+const to = require('mississippi').to
+const uniqueFilename = require('unique-filename')
+const Y = require('../util/y.js')
+
+const writeFileAsync = BB.promisify(fs.writeFile)
+
+module.exports = write
+function write (cache, data, opts) {
+ opts = opts || {}
+ if (opts.algorithms && opts.algorithms.length > 1) {
+ throw new Error(
+ Y`opts.algorithms only supports a single algorithm for now`
+ )
+ }
+ if (typeof opts.size === 'number' && data.length !== opts.size) {
+ return BB.reject(sizeError(opts.size, data.length))
+ }
+ const sri = ssri.fromData(data, opts)
+ if (opts.integrity && !ssri.checkData(data, opts.integrity, opts)) {
+ return BB.reject(checksumError(opts.integrity, sri))
+ }
+ return BB.using(makeTmp(cache, opts), tmp => (
+ writeFileAsync(
+ tmp.target, data, {flag: 'wx'}
+ ).then(() => (
+ moveToDestination(tmp, cache, sri, opts)
+ ))
+ )).then(() => ({integrity: sri, size: data.length}))
+}
+
+module.exports.stream = writeStream
+function writeStream (cache, opts) {
+ opts = opts || {}
+ const inputStream = new PassThrough()
+ let inputErr = false
+ function errCheck () {
+ if (inputErr) { throw inputErr }
+ }
+
+ let allDone
+ const ret = to((c, n, cb) => {
+ if (!allDone) {
+ allDone = handleContent(inputStream, cache, opts, errCheck)
+ }
+ inputStream.write(c, n, cb)
+ }, cb => {
+ inputStream.end(() => {
+ if (!allDone) {
+ const e = new Error(Y`Cache input stream was empty`)
+ e.code = 'ENODATA'
+ return ret.emit('error', e)
+ }
+ allDone.then(res => {
+ res.integrity && ret.emit('integrity', res.integrity)
+ res.size !== null && ret.emit('size', res.size)
+ cb()
+ }, e => {
+ ret.emit('error', e)
+ })
+ })
+ })
+ ret.once('error', e => {
+ inputErr = e
+ })
+ return ret
+}
+
+function handleContent (inputStream, cache, opts, errCheck) {
+ return BB.using(makeTmp(cache, opts), tmp => {
+ errCheck()
+ return pipeToTmp(
+ inputStream, cache, tmp.target, opts, errCheck
+ ).then(res => {
+ return moveToDestination(
+ tmp, cache, res.integrity, opts, errCheck
+ ).then(() => res)
+ })
+ })
+}
+
+function pipeToTmp (inputStream, cache, tmpTarget, opts, errCheck) {
+ return BB.resolve().then(() => {
+ let integrity
+ let size
+ const hashStream = ssri.integrityStream({
+ integrity: opts.integrity,
+ algorithms: opts.algorithms,
+ size: opts.size
+ }).on('integrity', s => {
+ integrity = s
+ }).on('size', s => {
+ size = s
+ })
+ const outStream = fs.createWriteStream(tmpTarget, {
+ flags: 'wx'
+ })
+ errCheck()
+ return pipe(inputStream, hashStream, outStream).then(() => {
+ return {integrity, size}
+ }, err => {
+ return rimraf(tmpTarget).then(() => { throw err })
+ })
+ })
+}
+
+function makeTmp (cache, opts) {
+ const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix)
+ return fixOwner.mkdirfix(
+ path.dirname(tmpTarget), opts.uid, opts.gid
+ ).then(() => ({
+ target: tmpTarget,
+ moved: false
+ })).disposer(tmp => (!tmp.moved && rimraf(tmp.target)))
+}
+
+function moveToDestination (tmp, cache, sri, opts, errCheck) {
+ errCheck && errCheck()
+ const destination = contentPath(cache, sri)
+ const destDir = path.dirname(destination)
+
+ return fixOwner.mkdirfix(
+ destDir, opts.uid, opts.gid
+ ).then(() => {
+ errCheck && errCheck()
+ return moveFile(tmp.target, destination)
+ }).then(() => {
+ errCheck && errCheck()
+ tmp.moved = true
+ return fixOwner.chownr(destination, opts.uid, opts.gid)
+ })
+}
+
+function sizeError (expected, found) {
+ var err = new Error(Y`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
+ err.expected = expected
+ err.found = found
+ err.code = 'EBADSIZE'
+ return err
+}
+
+function checksumError (expected, found) {
+ var err = new Error(Y`Integrity check failed:
+ Wanted: ${expected}
+ Found: ${found}`)
+ err.code = 'EINTEGRITY'
+ err.expected = expected
+ err.found = found
+ return err
+}