Browse files

Merge branch 'master' into features/airship/grefs_api

  • Loading branch information...
2 parents dfce3ef + b1e4dee commit 8a6382facc6f10b5ff2e9c495fc8a586a926c37e @richo committed Feb 16, 2013
@@ -75,6 +75,13 @@ Once the rindex is resolved, a search for `f` will return `g`, which in turn
includes `d` and `e` which have nothing to do with `f`. Notation for branching
and resolution will need to be created.
+### Writing data out
+Updates to refs that are recieved from a peer should be accompanied by a valid
+signature. All objects should be accepted (unless the signature is actually
+invalid, not just untrusted), but only objects that are signed by a trusted
+party should be included into the rindex for consideration for rendering.
### Traversing
To find the forward ancestors of a given object, simply grep over
@@ -110,6 +117,49 @@ of all divergent branches from a root object.
Tie resolution is currently undefined.
+updating refs
+Unlike in git, a ref doesn't point ot a single commit, instead it points to all
+the valid tips of a commit.
+As such, the process for updating a ref should be:
+1. Create a directory for the ref in `grefs/$refname`, respecting slashes as
+though they were native to the fs.
+2. Inside this ref directory, create a file for each tip that now exists on the
+ref. This file should contain the signature for the update to that ref (this is
+a TODO)
+3. Any previously existing files should be unlinked, AFTER each child ref is
+Therefore, a state transformation for an update might look like:
+grefs/ ::
+ \
+ e
+Currently, the `grefs` directory contains two files, `d` and `e`, each
+theoretically with a valid signature.
+grefs/ ::
+ \ /
+ e
+After this, `f` is written out with a new signature, and then `d` and `e` are
### Misc
@@ -1,8 +1,10 @@
-This is the root object of a thread. It contains:
+NB: See [protocol](/groundstation/objects/root_object.proto) and [implementation](/groundstation/objects/
+This is the root object of a thread. It contains:
+- SHA1: This is the hash of the object as stored in the objdb, as used for checksumming.
- ID: This should be reproducable if it's from upstream
- github:richo/groundstation/issues/15 for example
- They will be identifiable by the sha1 of the id
@@ -17,6 +19,9 @@ This is the root object of a thread. It contains:
+NB: See [protocol](/groundstation/objects/update_object.proto) and [implementation](/groundstation/objects/
These represent the updates to an object. The format of the payload member is dependent on the value of Protocol on the root object, but should include:
+- parent: This shall be an array of ID's of parents. Note that this is the SHA hashes and not the stringified ID.
+- data: An a protocol (as specified on the rootObject) specific payload used by the adaptor to render the content.
@@ -1,12 +1,17 @@
import os
import logging
+import binascii
if "GROUNDSTATION_DEBUG" in os.environ:
LEVEL = getattr(logging, os.getenv("GROUNDSTATION_DEBUG"))
LEVEL = logging.DEBUG
+def fix_oid(oid):
+ return binascii.hexlify(oid)
def _get_formatter():
return logging.Formatter('%(name)s - %(levelname)s - %(message)s')
@@ -3,12 +3,10 @@
from groundstation import logger
log = logger.getLogger(__name__)
-import binascii
def handle_transfer(self):
git_pb = GitObject()
git_pb.ParseFromString(self.payload)"Handling TRANSFER of %s" % (git_pb.type))
ret =,
-"Wrote object %s into local db" % (binascii.hexlify(ret)))
+"Wrote object %s into local db" % logger.fix_oid(ret))
@@ -0,0 +1,19 @@
+import os
+def is_dir(path):
+ return (040000 & (os.stat(path).st_mode)) > 0
+def find_leaf_dirs(d):
+ leafs = []
+ def _find_leafs(d):
+ for i in os.listdir(d):
+ this_path = os.path.join(d, i)
+ if sum(1 if is_dir(os.path.join(this_path, n)) else 0 for n in os.listdir(this_path)) > 0:
+ _find_leafs(this_path)
+ else:
+ leafs.append(this_path)
+ _find_leafs(d)
+ return leafs
@@ -0,0 +1,27 @@
+import os
+import shutil
+import unittest
+import tempfile
+from groundstation import utils
+class TestUtilsLeafDirs(unittest.TestCase):
+ def setUp(self):
+ self.tmpdir = tempfile.mkdtemp()
+ os.makedirs(os.path.join(self.tmpdir, "foo", "bar", "baz"))
+ os.makedirs(os.path.join(self.tmpdir, "foo", "borp"))
+ os.makedirs(os.path.join(self.tmpdir, "foo", "test", "test", "test"))
+ def tearDown(self):
+ shutil.rmtree(self.tmpdir)
+ def test_find_leaf_dirs(self):
+ leaves = utils.find_leaf_dirs(self.tmpdir)
+ self.assertIn(os.path.join(self.tmpdir, "foo", "bar", "baz"), leaves)
+ self.assertIn(os.path.join(self.tmpdir, "foo", "borp"), leaves)
+ self.assertIn(os.path.join(self.tmpdir, "foo", "test", "test", "test"), leaves)
+ self.assertNotIn(os.path.join(self.tmpdir, "foo", "bar"), leaves)
+ self.assertNotIn(os.path.join(self.tmpdir, "foo"), leaves)
+ self.assertNotIn(os.path.join(self.tmpdir, "foo", "test", "test"), leaves)

0 comments on commit 8a6382f

Please sign in to comment.