wallet-core/node_modules/package-hash/index.js

171 lines
4.2 KiB
JavaScript
Raw Normal View History

2017-05-28 00:38:50 +02:00
'use strict'
const cp = require('child_process')
const fs = require('fs')
const path = require('path')
const gfs = require('graceful-fs')
const flattenDeep = require('lodash.flattendeep')
const md5hex = require('md5-hex')
const releaseZalgo = require('release-zalgo')
const PACKAGE_FILE = require.resolve('./package.json')
const TEN_MEBIBYTE = 1024 * 1024 * 10
const readFile = {
async (file) {
return new Promise((resolve, reject) => {
gfs.readFile(file, (err, contents) => {
err ? reject(err) : resolve(contents)
})
})
},
sync (file) {
return fs.readFileSync(file)
}
}
const tryReadFile = {
async (file) {
return new Promise(resolve => {
gfs.readFile(file, (err, contents) => {
resolve(err ? null : contents)
})
})
},
sync (file) {
try {
return fs.readFileSync(file)
} catch (err) {
return null
}
}
}
const tryExecFile = {
async (file, args, options) {
return new Promise(resolve => {
cp.execFile(file, args, options, (err, stdout) => {
resolve(err ? null : stdout)
})
})
},
sync (file, args, options) {
try {
return cp.execFileSync(file, args, options)
} catch (err) {
return null
}
}
}
const git = {
tryGetRef (zalgo, dir, head) {
const m = /^ref: (.+)$/.exec(head.toString('utf8').trim())
if (!m) return null
return zalgo.run(tryReadFile, path.join(dir, '.git', m[1]))
},
tryGetDiff (zalgo, dir) {
return zalgo.run(tryExecFile,
'git',
// Attempt to get consistent output no matter the platform. Diff both
// staged and unstaged changes.
['--no-pager', 'diff', 'HEAD', '--no-color', '--no-ext-diff'],
{
cwd: dir,
maxBuffer: TEN_MEBIBYTE,
env: Object.assign({}, process.env, {
// Force the GIT_DIR to prevent git from diffing a parent repository
// in case the directory isn't actually a repository.
GIT_DIR: path.join(dir, '.git')
}),
// Ignore stderr.
stdio: ['ignore', 'pipe', 'ignore']
})
}
}
function addPackageData (zalgo, pkgPath) {
const dir = path.dirname(pkgPath)
return zalgo.all([
dir,
zalgo.run(readFile, pkgPath),
zalgo.run(tryReadFile, path.join(dir, '.git', 'HEAD'))
.then(head => {
if (!head) return []
return zalgo.all([
zalgo.run(tryReadFile, path.join(dir, '.git', 'packed-refs')),
git.tryGetRef(zalgo, dir, head),
git.tryGetDiff(zalgo, dir)
])
.then(results => {
return [head].concat(results.filter(Boolean))
})
})
])
}
function computeHash (zalgo, paths, pepper, salt) {
const inputs = []
if (pepper) inputs.push(pepper)
if (typeof salt !== 'undefined') {
if (Buffer.isBuffer(salt) || typeof salt === 'string') {
inputs.push(salt)
} else if (typeof salt === 'object' && salt !== null) {
inputs.push(JSON.stringify(salt))
} else {
throw new TypeError('Salt must be an Array, Buffer, Object or string')
}
}
return zalgo.all(paths.map(pkgPath => addPackageData(zalgo, pkgPath)))
.then(furtherInputs => md5hex(flattenDeep([inputs, furtherInputs])))
}
let ownHash = null
let ownHashPromise = null
function run (zalgo, paths, salt) {
if (!ownHash) {
return zalgo.run({
async () {
if (!ownHashPromise) {
ownHashPromise = computeHash(zalgo, [PACKAGE_FILE])
}
return ownHashPromise
},
sync () {
return computeHash(zalgo, [PACKAGE_FILE])
}
})
.then(hash => {
ownHash = new Buffer(hash, 'hex')
ownHashPromise = null
return run(zalgo, paths, salt)
})
}
if (paths === PACKAGE_FILE && typeof salt === 'undefined') {
// Special case that allow the pepper value to be obtained. Mainly here for
// testing purposes.
return zalgo.returns(ownHash.toString('hex'))
}
paths = Array.isArray(paths) ? paths : [paths]
return computeHash(zalgo, paths, ownHash, salt)
}
module.exports = (paths, salt) => {
return run(releaseZalgo.async(), paths, salt)
}
module.exports.sync = (paths, salt) => {
const result = run(releaseZalgo.sync(), paths, salt)
return releaseZalgo.unwrapSync(result)
}