diff options
Diffstat (limited to 'node_modules/package-hash/index.js')
-rw-r--r-- | node_modules/package-hash/index.js | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/node_modules/package-hash/index.js b/node_modules/package-hash/index.js new file mode 100644 index 000000000..8947a02d9 --- /dev/null +++ b/node_modules/package-hash/index.js @@ -0,0 +1,170 @@ +'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) +} |