src/git-info.js
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const GIT_DIR = '.git'
function findRepo(startingPath) {
let gitPath, lastPath
let currentPath = startingPath
if (!currentPath) { currentPath = process.cwd() }
do {
gitPath = path.join(currentPath, GIT_DIR)
if (fs.existsSync(gitPath)) {
return gitPath
}
lastPath = currentPath
currentPath = path.resolve(currentPath, '..')
} while (lastPath !== currentPath)
return null
}
function findPackedTag(gitPath, sha) {
const packedRefsFilePath = path.join(gitPath, 'packed-refs')
if (fs.existsSync(packedRefsFilePath)) {
const packedRefsFile = fs.readFileSync(packedRefsFilePath, {encoding: 'utf8'})
const tagLine = packedRefsFile.split('\n').filter(function(line) {
return line.indexOf('refs/tags') > -1 && line.indexOf(sha) > -1
})[0]
if (tagLine) {
return tagLine.split('tags/')[1]
}
}
}
function commitForTag(gitPath, tag) {
const tagPath = path.join(gitPath, 'refs', 'tags', tag)
const taggedObject = fs.readFileSync(tagPath, { encoding: 'utf8' }).trim()
const objectPath = path.join(gitPath, 'objects', taggedObject.slice(0, 2), taggedObject.slice(2))
if (!zlib.inflateSync || !fs.existsSync(objectPath)) {
// we cannot support annotated tags on node v0.10 because
// zlib does not allow sync access
return taggedObject
}
const objectContents = zlib.inflateSync(fs.readFileSync(objectPath)).toString()
// 'tag 172\u0000object c1ee41c325d54f410b133e0018c7a6b1316f6cda\ntype commit\ntag awesome-tag\ntagger Robert Jackson <robert.w.jackson@me.com> 1429100021 -0400\n\nI am making an annotated tag.\n'
if (objectContents.slice(0,3) === 'tag') {
const sections = objectContents.split(/\0|\n/)
const sha = sections[1].slice(7)
return sha
} else {
// this will return the tag for lightweight tags
return taggedObject
}
}
function findTag(gitPath, sha) {
let tag = findPackedTag(gitPath, sha)
if (tag) { return tag }
const tagsPath = path.join(gitPath, 'refs', 'tags')
if (!fs.existsSync(tagsPath)) { return false }
const tags = fs.readdirSync(tagsPath)
for (let i = 0, l = tags.length; i < l; i++) {
tag = tags[i]
const commitAtTag = commitForTag(gitPath, tags[i])
if (commitAtTag === sha) {
return tag
}
}
}
module.exports = function(gitPath) {
gitPath = findRepo(gitPath)
const result = {
sha: null,
abbreviatedSha: null,
branch: null,
tag: null,
root: path.resolve(gitPath, '..')
}
try {
const headFilePath = path.join(gitPath, 'HEAD')
if (fs.existsSync(headFilePath)) {
const headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'})
let branchName = headFile.split('/').slice(2).join('/').trim()
if (!branchName) {
branchName = headFile.split('/').slice(-1)[0].trim()
}
const refPath = headFile.split(' ')[1]
// Find branch and SHA
if (refPath) {
const branchPath = path.join(gitPath, refPath.trim())
result.branch = branchName
result.sha = fs.readFileSync(branchPath, {encoding: 'utf8' }).trim()
} else {
result.sha = branchName
}
result.abbreviatedSha = result.sha.slice(0,10)
// Find tag
let tag = findTag(gitPath, result.sha)
if (tag) {
result.tag = tag
}
}
} catch (e) {
if (!module.exports._suppressErrors) {
throw e // helps with testing and scenarios where we do not expect errors
} else {
// eat the error
}
}
return result
}
module.exports._suppressErrors = true
module.exports._findRepo = findRepo