aboutsummaryrefslogtreecommitdiff
path: root/lib/git.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/git.js')
-rw-r--r--lib/git.js132
1 files changed, 131 insertions, 1 deletions
diff --git a/lib/git.js b/lib/git.js
index d4a071e..fa889ef 100644
--- a/lib/git.js
+++ b/lib/git.js
@@ -8,6 +8,8 @@ var Reader = require('pull-reader')
var toPull = require('stream-to-pull-stream')
var zlib = require('zlib')
var looper = require('looper')
+var multicb = require('multicb')
+var kvdiff = require('pull-kvdiff')
var ObjectNotFoundError = u.customError('ObjectNotFoundError')
@@ -16,6 +18,7 @@ var types = {
commit: true,
tree: true,
}
+var emptyBlobHash = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391'
module.exports = Git
@@ -82,6 +85,7 @@ Git.prototype.openObject = function (opts, cb) {
}
Git.prototype.readObject = function (obj) {
+ if (obj.offset === obj.next) return pull.empty()
return pull(
this.app.readBlobSlice(obj.packLink, {start: obj.offset, end: obj.next}),
this.decodeObject({
@@ -100,6 +104,19 @@ Git.prototype._findObject = function (opts, cb) {
if (!opts.obj) return cb(new TypeError('missing object id'))
var self = this
var objId = opts.obj
+ if (objId === emptyBlobHash) {
+ // special case: the empty blob may be found anywhere
+ self.app.getMsgDecrypted(opts.headMsgId, function (err, msg) {
+ if (err) return cb(err)
+ return cb(null, {
+ offset: 0,
+ next: 0,
+ packLink: null,
+ idx: null,
+ msg: msg,
+ })
+ })
+ }
self.findObjectMsgs(opts, function (err, msgs) {
if (err) return cb(err)
if (msgs.length === 0)
@@ -515,6 +532,7 @@ function readCString(reader, cb) {
}
Git.prototype.readTree = function (obj) {
+ var self = this
var reader = Reader()
reader(this.readObject(obj))
return function (abort, cb) {
@@ -529,9 +547,121 @@ Git.prototype.readTree = function (obj) {
cb(null, {
name: name,
mode: mode,
- hash: hash.toString('hex')
+ hash: hash.toString('hex'),
+ type: mode === 0040000 ? 'tree' :
+ mode === 0160000 ? 'commit' : 'blob',
})
})
})
}
}
+
+Git.prototype.readCommitChanges = function (commit) {
+ var self = this
+ return u.readNext(function (cb) {
+ var done = multicb({pluck: 1})
+ commit.parents.forEach(function (rev) {
+ var cb = done()
+ self.getObjectMsg({
+ obj: rev,
+ headMsgId: commit.msg.key,
+ type: 'commit',
+ }, function (err, msg) {
+ if (err) return cb(err)
+ self.openObject({
+ obj: rev,
+ msg: msg.key,
+ }, function (err, obj) {
+ if (err) return cb(err)
+ self.getCommit(obj, cb)
+ })
+ })
+ })
+ done()(null, commit)
+ done(function (err, commits) {
+ if (err) return cb(err)
+ var done = multicb({pluck: 1})
+ commits.forEach(function (commit) {
+ var cb = done()
+ if (!commit.tree) return cb(null, pull.empty())
+ self.getObjectMsg({
+ obj: commit.tree,
+ headMsgId: commit.msg.key,
+ type: 'tree',
+ }, function (err, msg) {
+ if (err) return cb(err)
+ self.openObject({
+ obj: commit.tree,
+ msg: commit.msg.key,
+ }, cb)
+ })
+ })
+ done(function (err, trees) {
+ if (err) return cb(err)
+ cb(null, self.diffTreesRecursive(trees))
+ })
+ })
+ })
+}
+
+Git.prototype.diffTrees = function (objs) {
+ var self = this
+ return pull(
+ kvdiff(objs.map(function (obj) {
+ return self.readTree(obj)
+ }), 'name'),
+ pull.map(function (item) {
+ var diff = item.diff || {}
+ var head = item.values[item.values.length-1]
+ var created = true
+ for (var k = 0; k < item.values.length-1; k++)
+ if (item.values[k]) created = false
+ return {
+ name: item.key,
+ hash: diff.hash,
+ mode: diff.mode,
+ type: item.values.map(function (val) { return val.type }),
+ deleted: !head,
+ created: created
+ }
+ })
+ )
+}
+
+Git.prototype.diffTreesRecursive = function (objs) {
+ var self = this
+ return pull(
+ self.diffTrees(objs),
+ paramap(function (item, cb) {
+ if (!item.type.some(function (t) { return t === 'tree' }))
+ return cb(null, [item])
+ var done = multicb({pluck: 1})
+ item.type.forEach(function (type, i) {
+ var cb = done()
+ if (type !== 'tree') return cb(null, pull.once(item))
+ var hash = item.hash[i]
+ self.getObjectMsg({
+ obj: hash,
+ headMsgId: objs[i].msg.key,
+ }, function (err, msg) {
+ if (err) return cb(err)
+ self.openObject({
+ obj: hash,
+ msg: msg.key,
+ }, cb)
+ })
+ })
+ done(function (err, objs) {
+ if (err) return cb(err)
+ cb(null, pull(
+ self.diffTreesRecursive(objs),
+ pull.map(function (f) {
+ f.name = item.name + '/' + f.name
+ return f
+ })
+ ))
+ })
+ }, 4),
+ pull.flatten()
+ )
+}