├── README.md ├── package.json ├── test └── abstract.js └── index.js /README.md: -------------------------------------------------------------------------------- 1 | # hyperdb-git-repo 2 | 3 | > p2p git repo primitive for building p2p open source communities & escaping the 4 | > corporate web 5 | 6 | Implements [abstract-pull-git-repo][1]. 7 | 8 | ## Usage 9 | 10 | ```js 11 | #!/usr/bin/env node 12 | 13 | var toPull = require('stream-to-pull-stream') 14 | var pull = require('pull-stream') 15 | var hyperdb = require('hyperdb') 16 | var Repo = require('hyperdb-git-repo') 17 | var gitRemoteHelper = require('pull-git-remote-helper') 18 | 19 | var name = process.argv[3].replace('foo://', '') 20 | 21 | var db = hyperdb('../' + name) 22 | 23 | db.ready(function () { 24 | pull( 25 | toPull(process.stdin), 26 | gitRemoteHelper(Repo(db)), 27 | toPull(process.stdout) 28 | ) 29 | }) 30 | ``` 31 | 32 | ## API 33 | 34 | Implements the [abstract-pull-git-repo API][1]. 35 | 36 | ## License 37 | 38 | non-commercial 39 | 40 | [1]: https://github.com/clehner/abstract-pull-git-repo 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperdb-git-repo", 3 | "description": "git repo over a hyperdb", 4 | "author": "Stephen Whitmore ", 5 | "version": "1.0.4", 6 | "repository": { 7 | "url": "git://github.com/noffle/hyperdb-git-repo.git" 8 | }, 9 | "homepage": "https://github.com/noffle/hyperdb-git-repo", 10 | "bugs": "https://github.com/noffle/hyperdb-git-repo/issues", 11 | "main": "index.js", 12 | "scripts": { 13 | "test": "tape test/*.js", 14 | "lint": "standard" 15 | }, 16 | "keywords": [], 17 | "dependencies": { 18 | "debug": "^3.1.0", 19 | "hyperdb": "^3.1.1", 20 | "pull-git-remote-helper": "^2.0.0", 21 | "pull-hash": "^1.0.0", 22 | "pull-stream": "^3.6.8", 23 | "stream-to-pull-stream": "^1.7.2" 24 | }, 25 | "devDependencies": { 26 | "abstract-pull-git-repo": "^0.4.1", 27 | "standard": "~10.0.0", 28 | "tape": "~4.6.2" 29 | }, 30 | "license": "non-commercial" 31 | } 32 | -------------------------------------------------------------------------------- /test/abstract.js: -------------------------------------------------------------------------------- 1 | var test = require('tape') 2 | var suite = require('abstract-pull-git-repo/tests') 3 | var Repo = require('..') 4 | var tmp = require('os').tmpdir 5 | var path = require('path') 6 | var hyperdb = require('hyperdb') 7 | 8 | function makeRepo (key, cb) { 9 | if (!cb && typeof key === 'function') { 10 | cb = key 11 | key = null 12 | } 13 | 14 | var dir = path.join(tmp(), 'tmp-' + String(Math.random()).slice(2)) 15 | var db = hyperdb(dir, key) 16 | db.ready(function () { 17 | var repo = Repo(db) 18 | cb(null, repo, db) 19 | }) 20 | } 21 | 22 | // repo tests 23 | //test('repo', function (t) { 24 | // makeRepo(function (_, repo) { 25 | // suite.repo(t.test, repo) 26 | // }) 27 | //}) 28 | 29 | // repos tests 30 | test('repos', function (t) { 31 | var repo2 32 | var db2 33 | function get (key, cb) { 34 | if (repo2) return process.nextTick(cb, null, repo2, db2) 35 | makeRepo(key, function (_, repo, db) { 36 | repo2 = repo 37 | db2 = db 38 | cb(null, repo, db) 39 | }) 40 | } 41 | 42 | makeRepo(function (_, repo, db) { 43 | get(db.key, function (_, repo2, db2) { 44 | var r1 = db.replicate({live:true}) 45 | var r2 = db2.replicate({live:true}) 46 | r1.pipe(r2).pipe(r1) 47 | 48 | suite.repos(t.test, repo, function (cb) { 49 | get(db.key, cb) 50 | }) 51 | }) 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var toPull = require('stream-to-pull-stream') 2 | var pull = require('pull-stream') 3 | var createGitHash = require('pull-hash/ext/git') 4 | var debug = require('debug')('hyperdb-git-repo') 5 | 6 | module.exports = function (db) { 7 | return { 8 | refs: function () { 9 | debug('want refs') 10 | return pull( 11 | toPull(db.createReadStream('git/refs', {recursive:true})), 12 | pull.filter(function (nodes) { 13 | if (!nodes || !nodes.length) return false 14 | if (!nodes[0].value) return false 15 | return true 16 | }), 17 | pull.map(function (nodes) { 18 | var node = nodes[0] 19 | debug('refs', node.key, node.value.toString()) 20 | return { 21 | name: node.key.replace('git/', ''), 22 | hash: node.value.toString() 23 | } 24 | }) 25 | ) 26 | }, 27 | symrefs: function () { 28 | return pull.once({ name: 'HEAD', ref: 'refs/heads/master'}) 29 | }, 30 | hasObject: function (hash, cb) { 31 | debug('has', hash) 32 | db.get('git/objects/' + hash + '/info', function (err, nodes) { 33 | cb(err, !!nodes.length) 34 | }) 35 | }, 36 | getObject: function (hash, cb) { 37 | debug('get', hash) 38 | db.get('git/objects/' + hash + '/info', function (err, nodes) { 39 | if (err) return cb(err) 40 | if (!nodes.length) return cb(new Error({notFound:true})) 41 | var info = JSON.parse(nodes[0].value.toString()) 42 | db.get('git/objects/' + hash + '/data', function (err, nodes) { 43 | if (err) return cb(err) 44 | info.read = pull.once(nodes[0].value) 45 | cb(null, info) 46 | }) 47 | }) 48 | }, 49 | update: function (refs, objects, cb) { 50 | var refsDone = false 51 | var objsDone = false 52 | var error 53 | 54 | pull( 55 | refs, 56 | pull.asyncMap(function (update, done) { 57 | if (update.old && !update.new) { 58 | db.del('git/' + update.name, function () { 59 | debug('delete ref', update) 60 | done() 61 | }) 62 | } else { 63 | // don't let tags be double-pushed 64 | if (/tags/.test(update.name)) { 65 | db.get('git/' + update.name, function (err, nodes) { 66 | if (err || nodes.length > 0) return done(err || {}) 67 | db.put('git/' + update.name, update.new, function () { 68 | debug('update ref', update) 69 | done() 70 | }) 71 | }) 72 | } else { 73 | db.put('git/' + update.name, update.new, function () { 74 | debug('update ref', update) 75 | done() 76 | }) 77 | } 78 | } 79 | }), 80 | pull.collect(function (err) { 81 | error = err || error 82 | refsDone = true 83 | debug('refs done', err) 84 | if (refsDone && objsDone) cb(error) 85 | }) 86 | ) 87 | 88 | if (!objects) { 89 | objsDone = true 90 | debug('objs done') 91 | if (refsDone && objsDone) cb(error) 92 | return 93 | } 94 | 95 | objects(null, function next(end, object) { 96 | if (end === true) { 97 | objsDone = true 98 | if (refsDone && objsDone) cb(error) 99 | return 100 | } 101 | if (end) throw end 102 | var pending = 2 103 | var buf, hash 104 | pull( 105 | object.read, 106 | createGitHash(object, done), 107 | pull.collect(function (err, bufs) { 108 | if (err) return done(err) 109 | buf = Buffer.concat(bufs, object.length) 110 | done() 111 | }) 112 | ) 113 | function done (err, theHash) { 114 | if (theHash) hash = theHash 115 | if (--pending) return 116 | // debug('updating object', hash, object, buf.length) 117 | var info = new Buffer(JSON.stringify({ 118 | type: object.type, 119 | length: object.length 120 | })) 121 | db.put('git/objects/' + hash + '/info', info, function () { 122 | db.put('git/objects/' + hash + '/data', buf, function () { 123 | debug('wrote', hash, 'to hyperdb') 124 | objects(null, next) 125 | }) 126 | }) 127 | } 128 | }) 129 | } 130 | } 131 | } 132 | 133 | --------------------------------------------------------------------------------