diff options
Diffstat (limited to 'lib/serve.js')
-rw-r--r-- | lib/serve.js | 262 |
1 files changed, 261 insertions, 1 deletions
diff --git a/lib/serve.js b/lib/serve.js index f1ec351..64aa82b 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -1282,7 +1282,9 @@ Serve.prototype.git = function (url) { var m = /^\/?([^\/]*)\/?(.*)?$/.exec(url) switch (m[1]) { case 'commit': return this.gitCommit(m[2]) - case 'tag': return this.gitCommit(m[2]) + case 'tag': return this.gitTag(m[2]) + case 'tree': return this.gitTree(m[2]) + case 'blob': return this.gitBlob(m[2]) case 'raw': return this.gitRaw(m[2]) default: return this.respond(404, 'Not found') } @@ -1442,6 +1444,264 @@ Serve.prototype.gitCommit = function (rev) { }) } +Serve.prototype.gitTag = function (rev) { + var self = this + if (!/[0-9a-f]{24}/.test(rev)) { + return pull( + ph('div.error', 'rev is not a git object id'), + self.wrapPage('git'), + self.respondSink(400) + ) + } + if (!u.isRef(self.query.msg)) return pull( + ph('div.error', 'missing message id'), + self.wrapPage('git tag ' + 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(u.renderError(err).outerHTML), + self.wrapPage('git tag ' + rev), + self.respondSink(400) + ) + var msgDate = new Date(obj.msg.value.timestamp) + self.app.git.getTag(obj, function (err, tag) { + 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 tag ' + 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(tag.tagger), + ' tagged ', + ph('span', {title: tag.tagger.date.toLocaleString()}, + htime(tag.tagger.date)), + ' in ', tag.tagger.tz + ]), + tag.type, ' ', + pull( + pull.once(tag.object), + pull.asyncMap(function (id, cb) { + self.app.git.getObjectMsg({ + obj: id, + type: tag.type, + headMsgId: obj.msg.key, + }, function (err, msg) { + var path = '/git/' + tag.type + '/' + id + + '?msg=' + encodeURIComponent(msg.key) + cb(null, [ph('code', ph('a', { + href: self.app.render.toUrl(path) + }, id.substr(0, 8))), ' ']) + }) + }) + ), ' ', + ph('code', u.escapeHTML(tag.tag)), + h('pre', self.app.render.linkify(tag.body)).outerHTML, + ] + ]), + self.wrapPage('git tag ' + rev), + self.respondSink(missingBlobs ? 409 : 200) + ) + }) + }) +} + +Serve.prototype.gitTree = function (rev) { + var self = this + if (!/[0-9a-f]{24}/.test(rev)) { + return pull( + ph('div.error', 'rev is not a git object id'), + self.wrapPage('git'), + self.respondSink(400) + ) + } + 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) { + 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 tree ' + rev), + self.respondSink(400) + ) + var msgDate = new Date(obj.msg.value.timestamp) + pull( + ph('section', [ + ph('h3', ph('a', {href: ''}, rev)), + ph('div', [ + self.phIdLink(obj.msg.value.author), ' ', + ph('a', { + href: self.app.render.toUrl(obj.msg.key), + title: msgDate.toLocaleString(), + }, htime(msgDate)) + ]), + missingBlobs ? self.askWantBlobsForm(missingBlobs) : ph('table', [ + pull( + self.app.git.readTree(obj), + paramap(function (file, cb) { + self.app.git.getObjectMsg({ + obj: file.hash, + headMsgId: obj.msg.key, + }, function (err, msg) { + if (err && err.name === 'ObjectNotFoundError') return cb(null, file) + if (err) return cb(err) + file.msg = msg + cb(null, file) + }) + }, 8), + pull.map(function (item) { + var type = item.mode === 0040000 ? 'tree' : + item.mode === 0160000 ? 'commit' : 'blob' + var path = '/git/' + 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)}, + item.name + (type === 'tree' ? '/' : ''))), + item.msg ? ph('td', + self.phIdLink(item.msg.value.author)) : '', + item.msg ? ph('td', + ph('a', { + href: self.app.render.toUrl(item.msg.key), + title: fileDate.toLocaleString(), + }, htime(fileDate)) + ) : '', + ]) + }) + ) + ]), + ]), + self.wrapPage('git tree ' + rev), + self.respondSink(missingBlobs ? 409 : 200) + ) + }) +} + +Serve.prototype.gitBlob = function (rev) { + var self = this + if (!/[0-9a-f]{24}/.test(rev)) { + return pull( + ph('div.error', 'rev is not a git object id'), + self.wrapPage('git'), + self.respondSink(400) + ) + } + if (!u.isRef(self.query.msg)) return pull( + ph('div.error', 'missing message id'), + self.wrapPage('git object ' + rev), + self.respondSink(400) + ) + + self.app.getMsgDecrypted(self.query.msg, function (err, msg) { + if (err) return pull( + pull.once(u.renderError(err).outerHTML), + self.wrapPage('git object ' + rev), + self.respondSink(400) + ) + var msgDate = new Date(msg.value.timestamp) + self.app.git.openObject({ + obj: rev, + msg: msg.key, + }, function (err, obj) { + 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 object ' + rev), + self.respondSink(400) + ) + pull( + ph('section', [ + ph('h3', ph('a', {href: ''}, rev)), + ph('div', [ + self.phIdLink(msg.value.author), ' ', + ph('a', { + href: self.app.render.toUrl(msg.key), + title: msgDate.toLocaleString(), + }, htime(msgDate)) + ]), + missingBlobs ? self.askWantBlobsForm(missingBlobs) : pull( + self.app.git.readObject(obj), + self.wrapBinary({ + rawUrl: self.app.render.toUrl('/git/raw/' + rev + + '?msg=' + encodeURIComponent(msg.key)) + }) + ), + ]), + self.wrapPage('git blob ' + rev), + self.respondSink(200) + ) + }) + }) +} + +// wrap a binary source and render it or turn into an embed +Serve.prototype.wrapBinary = function (opts) { + var self = this + return function (read) { + var readRendered, type + read = ident(function (ext) { + type = ext && mime.lookup(ext) || 'text/plain' + })(read) + return function (abort, cb) { + if (readRendered) return readRendered(abort, cb) + if (abort) return read(abort, cb) + if (!type) read(null, function (end, buf) { + if (end) return cb(end) + if (!type) return cb(new Error('unable to get type')) + readRendered = pickSource(type, cat([pull.once(buf), read])) + readRendered(null, cb) + }) + } + } + function pickSource(type, read) { + if (/^image\//.test(type)) { + read(true, function (err) { + if (err && err !== true) console.trace(err) + }) + return ph('img', { + src: opts.rawUrl + }) + } + return ph('pre', pull.map(function (buf) { + return h('div', + self.app.render.linkify(buf.toString('utf8')) + ).innerHTML + })(read)) + } +} + Serve.prototype.wrapPublic = function (opts) { var self = this return u.hyperwrap(function (thread, cb) { |