aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519>2017-06-03 11:53:21 -1000
committercel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519>2017-06-03 12:37:01 -1000
commit4d96b6e0f7b726a5d96742e51fcb6c05b1d3f85f (patch)
tree21b82ee95357c8f232a2a5fa486b16e26b845b07
parent81e06ce58a3a4a09b7c6c2837e8076ecec6e38e3 (diff)
downloadpatchfoo-4d96b6e0f7b726a5d96742e51fcb6c05b1d3f85f.tar.gz
patchfoo-4d96b6e0f7b726a5d96742e51fcb6c05b1d3f85f.zip
Show commit files changed
-rw-r--r--lib/git.js132
-rw-r--r--lib/render.js1
-rw-r--r--lib/serve.js26
-rw-r--r--lib/util.js1
-rw-r--r--package.json1
5 files changed, 154 insertions, 7 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()
+ )
+}
diff --git a/lib/render.js b/lib/render.js
index d28f4b4..880470a 100644
--- a/lib/render.js
+++ b/lib/render.js
@@ -104,6 +104,7 @@ Render.prototype.emoji = function (emoji) {
src: this.opts.emoji_base + emoji + '.png',
alt: name,
height: 17,
+ align: 'absmiddle',
title: name,
})
}
diff --git a/lib/serve.js b/lib/serve.js
index d2510e1..59a09d5 100644
--- a/lib/serve.js
+++ b/lib/serve.js
@@ -1440,6 +1440,21 @@ Serve.prototype.gitCommit = function (rev) {
)]) : '',
h('blockquote',
self.app.render.gitCommitBody(commit.body)).outerHTML,
+ ph('h4', 'files'),
+ ph('table', pull(
+ self.app.git.readCommitChanges(commit),
+ pull.map(function (file) {
+ return ph('tr', [
+ ph('td', ph('code', u.escapeHTML(file.name))),
+ // ph('td', ph('code', u.escapeHTML(JSON.stringify(file.msg)))),
+ ph('td', file.deleted ? 'deleted'
+ : file.created ? 'created'
+ : file.hash ? 'changed'
+ : file.mode ? 'mode changed'
+ : JSON.stringify(file))
+ ])
+ })
+ ))
]
]),
self.wrapPage('git commit ' + rev),
@@ -1572,20 +1587,19 @@ Serve.prototype.gitTree = function (rev) {
})
}, 8),
pull.map(function (item) {
- var type = item.mode === 0040000 ? 'tree' :
- item.mode === 0160000 ? 'commit' : 'blob'
if (!item.msg) return ph('tr', [
ph('td',
- u.escapeHTML(item.name) + (type === 'tree' ? '/' : '')),
+ u.escapeHTML(item.name) + (item.type === 'tree' ? '/' : '')),
+ ph('td', u.escapeHTML(item.hash)),
ph('td', 'missing')
])
- var path = '/git/' + type + '/' + item.hash
+ var path = '/git/' + item.type + '/' + item.hash
+ '?msg=' + encodeURIComponent(item.msg.key)
var fileDate = new Date(item.msg.value.timestamp)
return ph('tr', [
ph('td',
ph('a', {href: self.app.render.toUrl(path)},
- u.escapeHTML(item.name) + (type === 'tree' ? '/' : ''))),
+ u.escapeHTML(item.name) + (item.type === 'tree' ? '/' : ''))),
ph('td',
self.phIdLink(item.msg.value.author)),
ph('td',
@@ -1748,7 +1762,7 @@ Serve.prototype.askWantBlobsForm = function (links) {
if (!u.isRef(link.link)) return
return ph('tr', [
ph('td', ph('code', link.link)),
- ph('td', self.app.render.formatSize(link.size)),
+ !isNaN(link.size) ? ph('td', self.app.render.formatSize(link.size)) : '',
])
})),
ph('input', {type: 'hidden', name: 'action', value: 'want-blobs'}),
diff --git a/lib/util.js b/lib/util.js
index a5f14f5..e4cf415 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -153,6 +153,7 @@ u.customError = function (name) {
}
u.escapeHTML = function (html) {
+ if (!html) return ''
return html.toString('utf8')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
diff --git a/package.json b/package.json
index 42311a4..816c115 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"pull-hash": "^1.0.0",
"pull-hyperscript": "^0.2.2",
"pull-identify-filetype": "^1.1.0",
+ "pull-kvdiff": "^0.0.1",
"pull-paginate": "^1.0.0",
"pull-paramap": "^1.2.1",
"pull-reader": "^1.2.9",