diff --git a/read-json.js b/read-json.js index 969bcc0..b8968b2 100644 --- a/read-json.js +++ b/read-json.js @@ -339,10 +339,26 @@ function githead_ (file, data, dir, head, cb) { data.gitHead = head.trim() return cb(null, data) } - var headFile = head.replace(/^ref: /, '').trim() - headFile = path.resolve(dir, '.git', headFile) + var headRef = head.replace(/^ref: /, '').trim() + var headFile = path.resolve(dir, '.git', headRef) fs.readFile(headFile, 'utf8', function (er, head) { - if (er || !head) return cb(null, data) + if (er || !head) { + var packFile = path.resolve(dir, '.git/packed-refs') + return fs.readFile(packFile, 'utf8', function (er, refs) { + if (er || !refs) { + return cb(null, data) + } + refs = refs.split('\n') + for (var i = 0; i < refs.length; i++) { + var match = refs[i].match(/^([0-9a-f]{40}) (.+)$/) + if (match && match[2].trim() === headRef) { + data.gitHead = match[1] + break + } + } + return cb(null, data) + }) + } head = head.replace(/^ref: /, '').trim() data.gitHead = head return cb(null, data) diff --git a/test/gitHead.js b/test/gitHead.js new file mode 100644 index 0000000..395101d --- /dev/null +++ b/test/gitHead.js @@ -0,0 +1,64 @@ +var childProcess = require('child_process') +var fs = require('fs') +var path = require('path') + +var tap = require('tap') + +var readJson = require('../') + +var isGit +try { + fs.readFileSync(path.resolve(__dirname, '../.git/HEAD')) + isGit = true +} catch (e) { + isGit = false +} + +if (isGit) { + tap.test('gitHead tests', function (t) { + t.plan(3) + + const repoProjectName = 'read-package-json' + const repo = 'https://github.com/npm/' + repoProjectName + '.git' + var repoDirs = [] + + t.test('detached case', function (tt) { + var p = path.resolve(__dirname, '..', 'package.json') + readJson(p, function (er, data) { + if (er) throw er + tt.ok(data) + tt.similar(data.gitHead, /^[a-f0-9]{40}$/) + tt.end() + }) + }) + + function testGitRepo (kind, extraRepoCommand, t) { + var repoDirName = repoProjectName + '-' + kind + var cmd = `cd ${__dirname} && git clone ${repo} ${repoDirName} && cd ${repoDirName}` + if (extraRepoCommand) cmd += ` && ${extraRepoCommand}` + childProcess.execSync(cmd) + repoDirs.push(repoDirName) + var p = path.resolve(__dirname, repoDirName, 'package.json') + readJson(p, function (er, data) { + if (er) throw er + t.ok(data) + t.similar(data.gitHead, /^[a-f0-9]{40}$/) + t.end() + }) + } + + t.test('basic case', function (tt) { + testGitRepo('basic', '', tt) + }) + + t.test('git-pack-refs vs gitHead', function (tt) { + testGitRepo('git-pack-refs', 'git pack-refs --all', tt) + }) + + t.tearDown(function () { + repoDirs.forEach(function (d) { + childProcess.execSync(`rm -rf ${path.resolve(__dirname, d)}`) + }) + }) + }) +}