diff options
Diffstat (limited to 'lib/serve.js')
-rw-r--r-- | lib/serve.js | 182 |
1 files changed, 146 insertions, 36 deletions
diff --git a/lib/serve.js b/lib/serve.js index 4e8c15d..f1ec351 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -1296,16 +1296,49 @@ Serve.prototype.gitRaw = function (rev) { self.respondSink(400, {'Content-Type': 'text/plain'}) ) } - - var headMsgId = self.query.head - pull( - self.app.git.readObject({ - id: rev, - headMsgId: headMsgId, - }), - catchTextError(), - self.respondSink(200, {'Content-type': 'text/plain'}) + if (!u.isRef(self.query.msg)) return pull( + ph('div.error', 'missing message id'), + self.wrapPage('git tree ' + rev), + self.respondSink(400) ) + + self.app.git.openObject({ + obj: rev, + msg: self.query.msg, + }, function (err, obj) { + if (err && err.name === 'BlobNotFoundError') + return self.askWantBlobs(err.links) + if (err) return pull( + pull.once(err.stack), + self.respondSink(400, {'Content-Type': 'text/plain'}) + ) + pull( + self.app.git.readObject(obj), + catchTextError(), + ident(function (type) { + type = type && mime.lookup(type) + if (type) self.res.setHeader('Content-Type', type) + self.res.setHeader('Cache-Control', 'public, max-age=315360000') + self.res.setHeader('etag', rev) + self.res.writeHead(200) + }), + self.respondSink() + ) + }) +} + +Serve.prototype.gitAuthorLink = function (author) { + if (author.feed) { + var myName = this.app.getNameSync(author.feed) + var sigil = author.name === author.localpart ? '@' : '' + return ph('a', { + href: this.app.render.toUrl(author.feed), + title: author.localpart + (myName ? ' (' + myName + ')' : '') + }, u.escapeHTML(sigil + author.name)) + } else { + return ph('a', {href: this.app.render.toUrl('mailto:' + author.email)}, + u.escapeHTML(author.name)) + } } Serve.prototype.gitCommit = function (rev) { @@ -1317,23 +1350,95 @@ Serve.prototype.gitCommit = function (rev) { self.respondSink(400) ) } + if (!u.isRef(self.query.msg)) return pull( + ph('div.error', 'missing message id'), + self.wrapPage('git commit ' + rev), + self.respondSink(400) + ) - self.app.git.getCommit({ - id: rev, - headMsgId: self.query.head, - }, function (err, commit) { + self.app.git.openObject({ + obj: rev, + msg: self.query.msg, + }, function (err, obj) { if (err && err.name === 'BlobNotFoundError') return self.askWantBlobs(err.links) if (err) return pull( pull.once(u.renderError(err).outerHTML), - self.wrapPage('git object ' + rev), + self.wrapPage('git commit ' + rev), self.respondSink(400) ) - pull( - pull.once(h('pre', self.app.render.linkify(commit.body)).outerHTML), - self.wrapPage('git object ' + rev), - self.respondSink(200) - ) + var msgDate = new Date(obj.msg.value.timestamp) + self.app.git.getCommit(obj, function (err, commit) { + var missingBlobs + if (err && err.name === 'BlobNotFoundError') + missingBlobs = err.links, err = null + if (err) return pull( + pull.once(u.renderError(err).outerHTML), + self.wrapPage('git commit ' + rev), + self.respondSink(400) + ) + pull( + ph('section', [ + ph('h3', ph('a', {href: ''}, rev)), + ph('div', [ + self.phIdLink(obj.msg.value.author), ' pushed ', + ph('a', { + href: self.app.render.toUrl(obj.msg.key), + title: msgDate.toLocaleString(), + }, htime(msgDate)) + ]), + missingBlobs ? self.askWantBlobsForm(missingBlobs) : [ + ph('div', [ + self.gitAuthorLink(commit.committer), + ' committed ', + ph('span', {title: commit.committer.date.toLocaleString()}, + htime(commit.committer.date)), + ' in ', commit.committer.tz + ]), + commit.author ? ph('div', [ + self.gitAuthorLink(commit.author), + ' authored ', + ph('span', {title: commit.author.date.toLocaleString()}, + htime(commit.author.date)), + ' in ', commit.author.tz + ]) : '', + commit.parents.length ? ph('div', ['parents: ', pull( + pull.values(commit.parents), + paramap(function (id, cb) { + self.app.git.getObjectMsg({ + obj: id, + headMsgId: obj.msg.key, + }, function (err, msg) { + var path = '/git/commit/' + id + + '?msg=' + encodeURIComponent(msg.key) + cb(null, [ph('code', ph('a', { + href: self.app.render.toUrl(path) + }, id.substr(0, 8))), ' ']) + }) + }, 4) + )]) : '', + commit.tree ? ph('div', ['tree: ', pull( + pull.once(commit.tree), + pull.asyncMap(function (id, cb) { + self.app.git.getObjectMsg({ + obj: id, + headMsgId: obj.msg.key, + }, function (err, msg) { + var path = '/git/tree/' + id + + '?msg=' + encodeURIComponent(msg.key) + cb(null, [ph('code', ph('a', { + href: self.app.render.toUrl(path) + }, id.substr(0, 8))), ' ']) + }) + }) + )]) : '', + h('pre', self.app.render.linkify(commit.body)).outerHTML, + ] + ]), + self.wrapPage('git commit ' + rev), + self.respondSink(missingBlobs ? 409 : 200) + ) + }) }) } @@ -1352,26 +1457,31 @@ Serve.prototype.wrapPublic = function (opts) { }) } +Serve.prototype.askWantBlobsForm = function (links) { + var self = this + return ph('form', {action: '', method: 'post'}, [ + ph('section', [ + ph('h3', 'Missing blobs'), + ph('p', 'The application needs these blobs to continue:'), + ph('table', links.map(u.toLink).map(function (link) { + if (!u.isRef(link.link)) return + return ph('tr', [ + ph('td', ph('code', link.link)), + ph('td', self.app.render.formatSize(link.size)), + ]) + })), + ph('input', {type: 'hidden', name: 'action', value: 'want-blobs'}), + ph('input', {type: 'hidden', name: 'blob_ids', + value: links.map(u.linkDest).join(',')}), + ph('p', ph('input', {type: 'submit', value: 'Want Blobs'})) + ]) + ]) +} + Serve.prototype.askWantBlobs = function (links) { var self = this pull( - ph('form', {action: '', method: 'post'}, [ - ph('section', [ - ph('h3', 'Missing blobs'), - ph('p', 'The application needs these blobs to continue:'), - ph('table', links.map(u.toLink).map(function (link) { - if (!u.isRef(link.link)) return - return ph('tr', [ - ph('td', ph('code', link.link)), - ph('td', self.app.render.formatSize(link.size)), - ]) - })), - ph('input', {type: 'hidden', name: 'action', value: 'want-blobs'}), - ph('input', {type: 'hidden', name: 'blob_ids', - value: links.map(u.linkDest).join(',')}), - ph('p', ph('input', {type: 'submit', value: 'Want Blobs'})) - ]) - ]), + self.askWantBlobsForm(links), self.wrapPage('missing blobs'), self.respondSink(409) ) |