ggit
Version:
Local promise-returning git command wrappers
146 lines (126 loc) • 4.01 kB
JavaScript
var check = require('check-more-types')
var moment = require('moment')
var spawn = require('child_process').spawn
var path = require('path')
var getGitRootFolder = require('./repo-root')
var debug = require('debug')('ggit')
// returns commits in reverse chronological order
function gitLog (filename, commits, cb, err, rootFolder) {
debug('gitLog, err?', err)
if (err) {
throw err
}
check.maybe.string(filename, 'missing filename')
check.verify.positiveNumber(commits, 'invalid number of commits', commits)
check.verify.fn(cb, 'callback should be a function')
// use -n <number> to limit history
// oe --since <date>
// var args = ['log', '--no-decorate', '-n ' + commits];
var args = ['log', '--name-status', '-n ' + commits]
debug('gitLog args', args)
if (filename) {
debug('gitLog uses filename', filename)
check.verify.string(rootFolder, 'could not find git root folder')
rootFolder = rootFolder.trim()
rootFolder = rootFolder.replace(/\//g, '\\')
console.log('filename', filename)
console.log('repo root folder', rootFolder)
var workingFolder = process.cwd()
console.log('working folder', workingFolder)
var relativePath = path.relative(workingFolder, filename)
// var repoPath = path.relative(rootFolder, filename);
args.push(relativePath)
}
debug('git log command', args)
var git = spawn('git', args)
commits = []
git.stdout.setEncoding('utf-8')
git.stdout.on('data', function (data) {
data.trim()
// console.log('git data\n', data);
var separatedData = data.split('\ncommit ')
separatedData = separatedData.filter(function (str) {
str.trim()
return str && str !== '\n'
})
var info = separatedData.map(parseCommit)
commits = commits.concat(info)
})
git.stderr.setEncoding('utf-8')
git.stderr.on('data', function (data) {
if (filename) {
throw new Error('Could not get git log for\n' + filename + '\n' + data)
} else {
throw new Error('Could not get git log\n' + data)
}
})
git.on('exit', function () {
debug('returning', commits.length, 'commits')
cb(commits)
})
}
function parseCommit (data) {
check.verify.string(data, 'null commit data')
data = data.trim()
// console.log('parsing commit\n', data);
var lines = data.split('\n')
console.assert(lines.length > 3, 'invalid commit\n', data)
// console.log('commit lines\n', lines);
var commitLine = lines[0].trim()
if (commitLine.indexOf('commit ') === 0) {
commitLine = commitLine.substr('commit '.length)
}
var authorLine = lines[1].split(':')[1].trim()
var dateLine = lines[2]
dateLine = dateLine.substr(dateLine.indexOf(':') + 1)
dateLine = dateLine.trim()
// console.log(dateLine);
lines.splice(0, 3)
lines = lines.filter(function (str) {
return str
})
lines = lines.map(function (str) {
str = str.trim()
return str
})
var files = []
lines = lines.filter(function (str) {
// console.log('checking line', str);
if (
str.indexOf('M') === 0 ||
str.indexOf('A') === 0 ||
str.indexOf('D') === 0
) {
files.push({
name: str.substr(1).trim(),
status: str[0]
})
return false
} else {
return true
}
})
var description = lines.join('\n')
return {
commit: '' + commitLine.trim(),
author: authorLine.trim(),
date: moment(new Date(dateLine)),
description: description.trim(),
files: files
}
}
function getGitLog (filename, commits, cb) {
if (filename) {
check.verify.string(filename, 'expected filename')
filename = path.resolve(filename)
console.log('fetching', commits, 'history for', filename)
}
commits = commits || 30
check.verify.positiveNumber(commits, 'invalid max number of commits', commits)
check.verify.fn(cb, 'expect callback function, not', cb)
getGitRootFolder(gitLog.bind(null, filename, commits, cb))
}
module.exports = {
getGitLog: getGitLog,
parseCommit: parseCommit
}