git ssb

16+

cel / patchfoo



Commit 2eb748d24d3ee0d13f990d2b7eab167a1b41b930

Render npm package readmes

cel committed on 9/20/2017, 8:44:17 PM
Parent: a9feab3b1f5335b14fc0feba4da2b9fe40aa1224

Files changed

lib/app.jschanged
lib/render.jschanged
lib/serve.jschanged
lib/app.jsView
@@ -11,8 +11,10 @@
1111 var Serve = require('./serve')
1212 var Render = require('./render')
1313 var Git = require('./git')
1414 var cat = require('pull-cat')
15 +var proc = require('child_process')
16 +var toPull = require('stream-to-pull-stream')
1517
1618 module.exports = App
1719
1820 function App(sbot, config) {
@@ -39,13 +41,17 @@
3941 this._getAbout.bind(this))
4042 this.unboxContent = memo({cache: lru(100)}, sbot.private.unbox)
4143 this.reverseNameCache = lru(500)
4244 this.reverseEmojiNameCache = lru(500)
45 + this.getBlobSize = memo({cache: this.blobSizeCache = lru(100)},
46 + sbot.blobs.size.bind(sbot.blobs))
4347
4448 this.unboxMsg = this.unboxMsg.bind(this)
4549
4650 this.render = new Render(this, this.opts)
4751 this.git = new Git(this)
52 +
53 + this.monitorBlobWants()
4854 }
4955
5056 App.prototype.go = function () {
5157 var self = this
@@ -178,11 +184,14 @@
178184 tryPublish(2)
179185 }
180186
181187 App.prototype.wantSizeBlob = function (id, cb) {
188 + // only want() the blob if we don't already have it
189 + var self = this
182190 var blobs = this.sbot.blobs
183191 blobs.size(id, function (err, size) {
184192 if (size != null) return cb(null, size)
193 + self.blobWants[id] = true
185194 blobs.want(id, function (err) {
186195 if (err) return cb(err)
187196 blobs.size(id, cb)
188197 })
@@ -564,4 +573,51 @@
564573 }}
565574 ]
566575 })
567576 }
577 +
578 +App.prototype.monitorBlobWants = function () {
579 + var self = this
580 + self.blobWants = {}
581 + pull(
582 + this.sbot.blobs.createWants(),
583 + pull.drain(function (wants) {
584 + for (var id in wants) {
585 + if (wants[id] < 0) self.blobWants[id] = true
586 + else delete self.blobWants[id]
587 + self.blobSizeCache.remove(id)
588 + }
589 + }, function (err) {
590 + if (err) console.trace(err)
591 + })
592 + )
593 +}
594 +
595 +App.prototype.getBlobState = function (id, cb) {
596 + var self = this
597 + if (self.blobWants[id]) return cb(null, 'wanted')
598 + self.getBlobSize(id, function (err, size) {
599 + if (err) return cb(err)
600 + cb(null, size != null)
601 + })
602 +}
603 +
604 +App.prototype.getNpmReadme = function (tarballId, cb) {
605 + var self = this
606 + // TODO: make this portable, and handle plaintext readmes
607 + var tar = proc.spawn('tar', ['--ignore-case', '-Oxz',
608 + 'package/README.md', 'package/readme.markdown', 'package/readme.mkd'])
609 + var done = multicb({pluck: 1, spread: true})
610 + pull(
611 + self.sbot.blobs.get(tarballId),
612 + toPull.sink(tar.stdin, done())
613 + )
614 + pull(
615 + toPull.source(tar.stdout),
616 + pull.collect(done())
617 + )
618 + done(function (err, _, bufs) {
619 + if (err) return cb(err)
620 + var text = Buffer.concat(bufs).toString('utf8')
621 + cb(null, text, true)
622 + })
623 +}
lib/render.jsView
@@ -421,14 +421,16 @@
421421 var distTag = parts[3]
422422 var self = this
423423 var done = multicb({pluck: 1, spread: true})
424424 var base = '/npm/' + (opts.author ? u.escapeId(link.author) + '/' : '')
425- var pathWithAuthor = '/npm/' +
425 + var pathWithAuthor = opts.withAuthor ? '/npm/' +
426426 u.escapeId(link.author) + '/' +
427427 (opts.name ? opts.name + '/' +
428428 (opts.version ? opts.version + '/' +
429- (opts.distTag ? opts.distTag + '/' : '') : '') : '')
430- self.app.getAbout(link.author, function (err, about) {
429 + (opts.distTag ? opts.distTag + '/' : '') : '') : '') : ''
430 + self.app.getAbout(link.author, done())
431 + self.app.getBlobState(link.link, done())
432 + done(function (err, about, blobState) {
431433 if (err) return cb(err)
432434 cb(null, h('tr', [
433435 opts.withAuthor ? h('td', h('a', {
434436 href: self.toUrl(pathWithAuthor),
@@ -451,8 +453,21 @@
451453 }, self.formatSize(link.size)), ' '] : ''),
452454 h('td', typeof link.link === 'string' ? h('code', h('a', {
453455 href: self.toUrl('/links/' + link.link),
454456 title: 'package tarball'
455- }, link.link.substr(0, 8) + '…')) : '')
457 + }, link.link.substr(0, 8) + '…')) : ''),
458 + h('td',
459 + blobState === 'wanted' ?
460 + 'fetching...'
461 + : blobState ? h('a', {
462 + href: self.toUrl('/npm-readme/' + encodeURIComponent(link.link)),
463 + title: 'package contents'
464 + }, 'readme')
465 + : h('form', {action: '', method: 'post'},
466 + h('input', {type: 'hidden', name: 'action', value: 'want-blobs'}),
467 + h('input', {type: 'hidden', name: 'async_want', value: '1'}),
468 + h('input', {type: 'hidden', name: 'blob_ids', value: link.link}),
469 + h('input', {type: 'submit', value: 'fetch'})
470 + ))
456471 ]))
457472 })
458473 }
lib/serve.jsView
@@ -200,10 +200,11 @@
200200 var ids = self.data.blob_ids.split(',')
201201 if (!ids.every(u.isRef)) return cb(new Error('bad blob ids ' + ids.join(',')))
202202 var done = multicb({pluck: 1})
203203 ids.forEach(function (id) {
204- self.app.sbot.blobs.want(id, done())
204 + self.app.wantSizeBlob(id, done())
205205 })
206 + if (self.data.async_want) return cb()
206207 done(function (err) {
207208 if (err) return cb(err)
208209 // self.note = h('div', 'wanted blobs: ' + ids.join(', ') + '.')
209210 cb()
@@ -302,8 +303,9 @@
302303 case '/about': return this.about(m[2])
303304 case '/git': return this.git(m[2])
304305 case '/image': return this.image(m[2])
305306 case '/npm': return this.npm(m[2])
307 + case '/npm-readme': return this.npmReadme(m[2])
306308 }
307309 return this.respond(404, 'Not found')
308310 }
309311
@@ -1910,9 +1912,10 @@
19101912 ph('td', 'package'),
19111913 ph('td', 'version'),
19121914 ph('td', 'tag'),
19131915 ph('td', 'size'),
1914- ph('td', 'tarball')
1916 + ph('td', 'tarball'),
1917 + ph('td', 'readme')
19151918 ])),
19161919 ph('tbody', pull(
19171920 self.app.blobMentions({
19181921 name: {$prefix: prefix},
@@ -1933,13 +1936,36 @@
19331936 pull.map(u.toHTML)
19341937 ))
19351938 ])
19361939 ]),
1937- self.wrapPage('npm:'),
1940 + self.wrapPage(prefix),
19381941 self.respondSink(200)
19391942 )
19401943 }
19411944
1945 +Serve.prototype.npmReadme = function (url) {
1946 + var self = this
1947 + var id = decodeURIComponent(url.substr(1))
1948 + return pull(
1949 + ph('section', {}, [
1950 + ph('h3', [
1951 + 'npm readme for ',
1952 + ph('a', {href: '/links/' + id}, id.substr(0, 8) + '…')
1953 + ]),
1954 + ph('blockquote', u.readNext(function (cb) {
1955 + self.app.getNpmReadme(id, function (err, readme, isMarkdown) {
1956 + if (err) return cb(null, ph('div', u.renderError(err).outerHTML))
1957 + cb(null, isMarkdown
1958 + ? ph('div', self.app.render.markdown(readme))
1959 + : ph('pre', readme))
1960 + })
1961 + }))
1962 + ]),
1963 + self.wrapPage('npm readme'),
1964 + self.respondSink(200)
1965 + )
1966 +}
1967 +
19421968 // wrap a binary source and render it or turn into an embed
19431969 Serve.prototype.wrapBinary = function (opts) {
19441970 var self = this
19451971 var ext = opts.ext

Built with git-ssb-web