ssb-git-repo
Advanced tools
Comparing version 1.10.1 to 2.0.0-collab
@@ -29,3 +29,3 @@ var ref = require('ssb-ref') | ||
if (err) return cb(err) | ||
var repo = new Repo(sbot, msg.key, msg.value, upstream) | ||
var repo = new Repo(sbot, msg.key, msg.value, upstream, options) | ||
repo._sync(options.live) | ||
@@ -61,3 +61,3 @@ cb(null, repo) | ||
if (err) return cb(err) | ||
var repo = new Repo(sbot, id, msg, upstream) | ||
var repo = new Repo(sbot, id, msg, upstream, options) | ||
repo._sync(options.live) | ||
@@ -76,5 +76,5 @@ if (upstream) upstream._sync(options.live) | ||
pull.map(function (msg) { | ||
return new Repo(sbot, msg.key, msg.value) | ||
return new Repo(sbot, msg.key, msg.value, null, options) | ||
}) | ||
) | ||
} |
239
lib/repo.js
@@ -15,3 +15,17 @@ var pull = require('pull-stream') | ||
var PullRequests = require('ssb-pull-requests') | ||
var KVGraph = require('kvgraph') | ||
var mergeUpdates = require('ssb-git/merge') | ||
function readNext(fn) { | ||
var next, self = this | ||
return function (end, cb) { | ||
if (next) return next(end, cb) | ||
fn.call(self, function (err, _next) { | ||
if (err) return cb(err) | ||
next = _next | ||
next(null, cb) | ||
}) | ||
} | ||
} | ||
module.exports = Repo | ||
@@ -80,5 +94,7 @@ | ||
var w = 0 | ||
function getBlobWithTimeout(blobs, timeout, key, cb) { | ||
function getBlobWithTimeout(timeout, key, cb) { | ||
if (process.env.DEBUG_BLOBS) | ||
console.error(++w + '+', 'blob req', key) | ||
if (this.output) | ||
this.output.write('Fetching blob: ' + key + '\r') | ||
if (!key) return cb(new Error('Missing blob key')) | ||
@@ -89,3 +105,3 @@ var timer = setTimeout(function () { | ||
}, timeout) | ||
blobs.want(key, function (err, got) { | ||
this.sbot.blobs.want(key, function (err, got) { | ||
if (process.env.DEBUG_BLOBS) | ||
@@ -97,4 +113,4 @@ console.error(--w + '-', 'blob got', key) | ||
else if (!got) cb(new Error('Unable to get blob ' + key)) | ||
else cb(null, blobs.get(key)) | ||
}) | ||
else cb(null, this.sbot.blobs.get(key)) | ||
}.bind(this)) | ||
} | ||
@@ -115,15 +131,17 @@ | ||
function Repo(sbot, id, msg, upstream) { | ||
function Repo(sbot, id, value, upstream, options) { | ||
this.sbot = sbot | ||
this.id = id | ||
this.feed = msg.author | ||
this.creator = value.author | ||
this.upstream = upstream | ||
this._refs = {/* ref: sha1 */} | ||
this.output = options.output | ||
this._objects = {/* sha1: {type, length, key} */} | ||
this._blobs = {/* sha1: [Buffer] */} | ||
this.updates = new KVGraph('key') | ||
this.updates.add({key: id, value: value}) | ||
// queued operations while syncing of old messages | ||
this._oldRefPushables = [] | ||
this._hashLookups = {/* sha1: [cb(err, object)] */} | ||
this._headCbs = [] | ||
this._syncCbs = [] | ||
@@ -152,31 +170,12 @@ this._newPacksPushable = pushable() | ||
Repo.prototype.getHead = function (cb) { | ||
if (this.head) | ||
cb(null, this.head) | ||
else | ||
this._headCbs.push(cb) | ||
this.getState(function (err, state) { | ||
cb(null, state.head) | ||
}) | ||
} | ||
Repo.prototype._setHead = function (head) { | ||
this.head = head | ||
while (this._headCbs.length) | ||
this._headCbs.shift()(null, head) | ||
} | ||
Repo.prototype._processOldMsg = function (msg) { | ||
var c = msg.value.content | ||
if (c.type !== 'git-update' || c.repo != this.id) return | ||
this.updates.add(msg) | ||
Repo.prototype._processOldMsg = function (c) { | ||
if (c.head && !this.head) | ||
this._setHead(c.head) | ||
for (var ref in c.refs || {}) { | ||
if (!(ref in this._refs)) { | ||
var hash = c.refs[ref] | ||
this._refs[ref] = hash | ||
if (hash) { | ||
var refObj = {name: ref, hash: hash} | ||
this._oldRefPushables.forEach(function (pushable) { | ||
pushable.push(refObj) | ||
}) | ||
} | ||
} | ||
} | ||
if (Array.isArray(c.objects)) { | ||
@@ -219,11 +218,8 @@ for (var i = 0; i < c.objects.length; i++) { | ||
Repo.prototype._processNewMsg = function (c) { | ||
if (c.head) | ||
this._setHead(c.head) | ||
Repo.prototype._processNewMsg = function (msg) { | ||
var c = msg.value.content | ||
this.updates.add(msg) | ||
for (var name in c.refs || {}) | ||
if (c.refs[name]) | ||
this._refs[name] = c.refs[name] | ||
else | ||
delete this._refs[name] | ||
// expire cached state object | ||
delete this._state | ||
@@ -260,4 +256,8 @@ if (Array.isArray(c.objects)) { | ||
Repo.prototype.getRepoBranches = function () { | ||
return Object.keys(this.updates.getHeads()) | ||
} | ||
Repo.prototype._getBlob = function (key, cb) { | ||
getBlobWithTimeout(this.sbot.blobs, 30e3, key, cb) | ||
getBlobWithTimeout.call(this, 30e3, key, cb) | ||
} | ||
@@ -305,51 +305,26 @@ | ||
var inherited = options.inherited !== false | ||
return pull( | ||
cat([ | ||
this._currentRefs(), | ||
!this.syncedRefs && this._oldRefs(), | ||
inherited && this.upstream && this.upstream.refs(), | ||
]), | ||
pull.unique('name') | ||
) | ||
return readNext.call(this, function (cb) { | ||
this.getState(function (err, state) { | ||
if (err) cb(err) | ||
else cb(null, pull( | ||
cat([ | ||
pull.values(state.refs), | ||
inherited && this.upstream && this.upstream.refs() | ||
]), | ||
pull.unique('name') | ||
)) | ||
}) | ||
}) | ||
} | ||
Repo.prototype.symrefs = function () { | ||
var ended | ||
if (this.head) | ||
return pull.once({name: 'HEAD', ref: this.head}) | ||
else if (!this.synced) | ||
return function (end, cb) { | ||
if (ended || end) return cb(ended || end) | ||
this.getHead(function (err, ref) { | ||
ended = err || true | ||
cb(err, {name: 'HEAD', ref: ref}) | ||
}) | ||
}.bind(this) | ||
else | ||
return pull.empty() | ||
} | ||
Repo.prototype._currentRefs = function () { | ||
var refs = this._refs | ||
return pull( | ||
pull.values(Object.keys(refs)), | ||
pull.map(function (name) { | ||
return { | ||
name: name, | ||
hash: refs[name] | ||
} | ||
}), | ||
pull.filter(function (ref) { | ||
return ref.hash | ||
return readNext.call(this, function (cb) { | ||
this.getHead(function (err, head) { | ||
if (err) return cb(err) | ||
cb(null, pull.once({name: 'HEAD', ref: head})) | ||
}) | ||
) | ||
}) | ||
} | ||
// get refs that are being read from history | ||
Repo.prototype._oldRefs = function () { | ||
var read = pushable() | ||
this._oldRefPushables.push(read) | ||
return read | ||
} | ||
Repo.prototype._addObject = function (sha1, object) { | ||
@@ -380,3 +355,2 @@ this._objects[sha1] = object | ||
this.sbot.links({ | ||
type: 'git-update', | ||
dest: this.id, | ||
@@ -386,8 +360,4 @@ source: this.feed, | ||
values: true, | ||
keys: false, | ||
reverse: true | ||
}), | ||
pull.map(function (msg) { | ||
return msg.value.content | ||
}), | ||
pull.drain(this._processOldMsg.bind(this), function (err) { | ||
@@ -397,25 +367,3 @@ this._oldPacksPushable.end(err) | ||
this.syncedRefs = true | ||
this._oldRefPushables.forEach(function (pushable) { | ||
pushable.end(err) | ||
}) | ||
delete this._oldRefPushables | ||
// pick a head from the current branches if head was not set | ||
var head = this.head | ||
var defaultHead = 'refs/heads/master' | ||
if (!head) { | ||
if (defaultHead in this._refs) | ||
head = defaultHead | ||
else | ||
for (head in this._refs) break | ||
} | ||
if (!head && this.upstream) { | ||
// set head from upstream's head | ||
this.upstream.getHead(function (err, head) { | ||
this._setHead(head || defaultHead) | ||
}.bind(this)) | ||
} else { | ||
this._setHead(head || defaultHead) | ||
} | ||
// complete waiting requests for lookups | ||
@@ -426,4 +374,7 @@ this.synced = true | ||
while (this._syncCbs.length) | ||
this._syncCbs.pop().call(this) | ||
if (live) | ||
this._syncNew(now) | ||
this._syncNew() | ||
}.bind(this)) | ||
@@ -433,17 +384,34 @@ ) | ||
Repo.prototype._syncNew = function (since) { | ||
function getLog(sbot, meta) { | ||
return meta.id | ||
? sbot.createHistoryStream(meta) | ||
: sbot.createLogStream(meta) | ||
} | ||
Repo.prototype.awaitSync = function (cb) { | ||
if (this.synced) cb.call(this) | ||
else this._syncCbs.push(cb) | ||
} | ||
Repo.prototype.getState = function (cb) { | ||
if (this._state) return cb(null, this._state) | ||
this.awaitSync(function () { | ||
cb.call(this, null, this._state = this.updates.reduceRight(mergeUpdates)) | ||
}) | ||
} | ||
Repo.prototype._syncNew = function () { | ||
if (this.closed) return | ||
var id = this.id | ||
pull( | ||
this._readNew = this.sbot.createHistoryStream({ | ||
this._readNew = getLog(this.sbot, { | ||
id: this.feed, | ||
values: true, | ||
live: true, | ||
gt: since | ||
old: false | ||
}), | ||
pull.map(function (msg) { | ||
return msg.value.content | ||
pull.filter(function (msg) { | ||
var c = msg.value.content | ||
return c && c.type == 'git-update' && c.repo == id | ||
}), | ||
pull.filter(function (c) { | ||
return (c.type == 'git-update' && c.repo == id) | ||
}), | ||
pull.drain(this._processNewMsg.bind(this), function (err) { | ||
@@ -498,9 +466,2 @@ if (err) throw err | ||
function Repo_resolveRefSync(repo, name) { | ||
for (; repo; repo = repo.upstream) { | ||
if (name in repo._refs) | ||
return repo._refs[name] | ||
} | ||
} | ||
function Repo_readRefUpdates(updates, cb) { | ||
@@ -512,10 +473,2 @@ var self = this | ||
if (ended = end) return cb(end === true ? null : end, refs) | ||
var oldRef = Repo_resolveRefSync(self, update.name) | ||
if (update.old != oldRef) | ||
console.error('Warning: ' + | ||
'Ref update old value is incorrect. ' + | ||
'ref: ' + update.name + ', ' + | ||
'old in update: ' + update.old + ', ' + | ||
'old in repo: ' + oldRef | ||
) | ||
;(refs || (refs = {}))[update.name] = update.new | ||
@@ -528,3 +481,3 @@ if (!ended) | ||
Repo.prototype.update = function (readRefUpdates, readObjects, cb) { | ||
if (this.sbot.id && this.sbot.id != this.feed) | ||
if (this.sbot.id && this.feed && this.sbot.id != this.feed) | ||
return cb(new Error('You do not have permission to push to this repo')) | ||
@@ -538,2 +491,3 @@ var done = multicb({ pluck: 1, spread: true }) | ||
type: 'git-update', | ||
repoBranch: this.getRepoBranches(), | ||
repo: this.id | ||
@@ -594,3 +548,3 @@ } | ||
} else { | ||
self._processNewMsg(msgPublished.value.content) | ||
self._processNewMsg(msgPublished) | ||
pushLinks(sbot, msg.objects, cb) | ||
@@ -603,3 +557,3 @@ } | ||
Repo.prototype.uploadPack = function (readRefUpdates, readPacks, cb) { | ||
if (this.sbot.id && this.sbot.id != this.feed) | ||
if (this.sbot.id && this.feed && this.sbot.id != this.feed) | ||
return cb(new Error('You do not have permission to push to this repo')) | ||
@@ -791,2 +745,3 @@ var self = this | ||
repo: self.id, | ||
repoBranch: self.getRepoBranches(), | ||
packs: packs, | ||
@@ -841,3 +796,3 @@ indexes: indexes, | ||
console.error('Published ' + msg.key) | ||
self._processNewMsg(msg.value.content) | ||
self._processNewMsg(msg) | ||
var links = [].concat(value.packs || [], value.indexes || []) | ||
@@ -844,0 +799,0 @@ pushLinks(self.sbot, links, cb) |
{ | ||
"name": "ssb-git-repo", | ||
"version": "1.10.1", | ||
"version": "2.0.0-collab", | ||
"description": "git repos in secure-scuttlebutt", | ||
@@ -24,2 +24,3 @@ "main": "index.js", | ||
"dependencies": { | ||
"kvgraph": "^0.1.0", | ||
"multicb": "^1.2.1", | ||
@@ -36,2 +37,3 @@ "pull-cache": "^0.0.0", | ||
"ssb-pull-requests": "^0.2.0", | ||
"ssb-git": "^0.2.0", | ||
"ssb-ref": "^2.3.0" | ||
@@ -38,0 +40,0 @@ }, |
@@ -29,2 +29,3 @@ # ssb-git-repo | ||
- `options.live`: keep the repo updated as changes are pushed to it | ||
- `options.output`: stream for logging stuff to | ||
- `cb`: function called when the repo is created | ||
@@ -41,2 +42,3 @@ - `err`: error creating the repo, if any | ||
- `options.live`: keep the repo updated as changes are pushed to it | ||
- `options.output`: stream for logging stuff to | ||
- `cb`: function called when the repo is retrieved | ||
@@ -93,2 +95,3 @@ - `err`: error retrieving the repo, if any | ||
repo: MsgId, | ||
repoBranch: [ MsgId ]?, | ||
refs: { <ref>: String? }?, | ||
@@ -107,2 +110,4 @@ objects: [ { type: String, length: Number, sha1: String, link: BlobId } ]?, | ||
- `repo`: id of a message (expected of type `git-repo`) identifying the repo | ||
- `repoBranch`: ids of latest concurrent previous git-update messages. | ||
Use to indicate causal order. | ||
- `refs`: updates to the repo's refs. a map of ref names to git sha1 hashes. | ||
@@ -109,0 +114,0 @@ e.g. `{ 'refs/heads/master': commitId }` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
0
137
36812
14
1023
2
+ Addedkvgraph@^0.1.0
+ Addedssb-git@^0.2.0
+ Addedkvgraph@0.1.0(transitive)
+ Addedssb-git@0.2.1(transitive)