# Path: groundstation/gref.py
# class Gref(object):
#     def __init__(self, store, channel, identifier):
#         self.store = store
#         self.channel = channel.replace("/", "_")
#         assert valid_path(self.channel), "Invalid channel"
#         self.identifier = identifier
#         assert valid_path(self.identifier), "Invalid identifier"
#         self._node_path = os.path.join(self.store.gref_path(),
#                                  self.channel,
#                                  self.identifier)
# 
#     def __str__(self):
#         return "%s/%s" % (self.channel, self.identifier)
# 
#     def exists(self):
#         return os.path.exists(self._node_path)
# 
#     def tips(self):
#         return os.listdir(self._node_path)
# 
#     def node_path(self):
#         if not self.exists():
#             os.makedirs(self._node_path)
# 
#         return self._node_path
# 
#     def write_tip(self, tip, signature):
#         if signature:
#             signature = str(signature[0])
#         tip_path = self.tip_path(tip)
#         open(tip_path, 'a').close()
#         fh = open(tip_path, 'r+')
#         fh.seek(0)
#         fh.write(signature)
#         fh.truncate()
#         fh.close()
# 
#     def tip_path(self, tip):
#         return os.path.join(self.node_path(), tip)
# 
#     def __iter__(self):
#         return os.listdir(self.node_path()).__iter__()
# 
#     def get_signature(self, tip):
#         try:
#             with open(self.tip_path(tip), 'r') as fh:
#                 data = fh.read()
#                 if not data:
#                     return ""
#                 return (int(data),)
#         except IOError:
#             return ""
# 
#     def remove_tip(self, tip, silent=False):
#         try:
#             os.unlink(os.path.join(self.tip_path(tip)))
#         except:
#             if not silent:
#                 raise
# 
#     def direct_parents(self, tip):
#         """Return all parents of `tip` in the order they're written into the
#         object"""
#         obj = object_factory.hydrate_object(self.store[tip].data)
#         if isinstance(obj, RootObject):
#             # Roots can't have parents
#             return []
#         elif isinstance(obj, UpdateObject):
#             return obj.parents
#         else:
#             raise "Unknown object hydrated %s" % (str(type(obj)))
# 
#     def parents(self, tips=None):
#         """Return all ancestors of `tip`, in an undefined order"""
#         # XXX This will asplode the stack at some point
#         parents = set()
#         this_iter = (tips or self.tips())
#         while this_iter:
#             tip = this_iter.pop()
#             tips_parents = self.direct_parents(tip)
#             parents = parents.union(set(tips_parents))
#             this_iter.extend(tips_parents)
#         return parents
# 
#     def marshall(self, crypto_adaptor=None):
#         """Marshalls the gref into something renderable:
#         {
#             "thread": An ordered thread of UpdateObjects. Ordering is
#                       arbitraryish.
#             "roots": The root nodes of this gref.
#             "tips": The string names of the tips used to marshall
#         }
#         """
#         thread = []
#         root_nodes = []
#         visited_nodes = set()
#         tips = []
#         signatures = {}
# 
#         # TODO Big issues will smash the stack
#         def _process(node):
#             if node in visited_nodes:
#                 log.debug("Bailing on visited node: %s" % (node))
#                 return
#             visited_nodes.add(node)
# 
#             if crypto_adaptor:
#                 signature = self.get_signature(node)
#                 if signature:
#                     signatures[node] = crypto_adaptor.verify(node, signature)
# 
#             obj = object_factory.hydrate_object(self.store[node].data)
#             if isinstance(obj, RootObject):  # We've found a root
#                 root_nodes.append(obj)
#                 return
#             for tip in obj.parents:
#                 _process(tip)
#             thread.insert(0, obj)
# 
#         for tip in self:
#             tips.append(tip)
#             log.debug("Descending into %s" % (tip))
#             _process(tip)
#         return {
#                 "thread": thread,
#                 "roots": root_nodes,
#                 "tips": tips,
#                 "signatures": signatures
#                 }
# 
#     def as_dict(self):
#         return {
#                 "channel": self.channel,
#                 "identifier": self.identifier,
#                 "node_path": self._node_path,
#                 "tips": self.tips()
#                 }
# 
# def valid_path(path):
#     test_path = os.path.join("/", path)
#     return os.path.realpath(test_path) == test_path


from support import store_fixture
from groundstation.gref import Gref, valid_path
import groundstation.store

    def test_get_signature(self):
        gref = Gref(self.repo, "testchannel", "test_get_signature")
        root = self.create_root_object(gref)
        oid = self.repo.create_blob(root.as_object())

        signature = (17**23,)
        gref.write_tip(oid, signature)
        self.assertEqual(signature, gref.get_signature(oid))

    def test_direct_parents(self):
        gref = Gref(self.repo, "testchannel", "test_write_tip")
        root = self.create_root_object(gref)
        root_oid = self.repo.create_blob(root.as_object())

        first_tier = []
        for i in xrange(5):
            obj = self.create_update_object([root_oid], "test_%i")
            oid = self.repo.create_blob(obj.as_object())
            first_tier.append(oid)

        final = self.create_update_object(first_tier, "final object")
        final_oid = self.repo.create_blob(final.as_object())

        gref.write_tip(final_oid, "")
        self.assertEqual(gref.direct_parents(final_oid), first_tier)

    def test_valid_path_works(self):
        self.assertTrue(valid_path("asdf"))
        self.assertTrue(valid_path("asdf/foo"))

# Path: groundstation/gref.py
# class Gref(object):
#     def __init__(self, store, channel, identifier):
#         self.store = store
#         self.channel = channel.replace("/", "_")
#         assert valid_path(self.channel), "Invalid channel"
#         self.identifier = identifier
#         assert valid_path(self.identifier), "Invalid identifier"
#         self._node_path = os.path.join(self.store.gref_path(),
#                                  self.channel,
#                                  self.identifier)
# 
#     def __str__(self):
#         return "%s/%s" % (self.channel, self.identifier)
# 
#     def exists(self):
#         return os.path.exists(self._node_path)
# 
#     def tips(self):
#         return os.listdir(self._node_path)
# 
#     def node_path(self):
#         if not self.exists():
#             os.makedirs(self._node_path)
# 
#         return self._node_path
# 
#     def write_tip(self, tip, signature):
#         if signature:
#             signature = str(signature[0])
#         tip_path = self.tip_path(tip)
#         open(tip_path, 'a').close()
#         fh = open(tip_path, 'r+')
#         fh.seek(0)
#         fh.write(signature)
#         fh.truncate()
#         fh.close()
# 
#     def tip_path(self, tip):
#         return os.path.join(self.node_path(), tip)
# 
#     def __iter__(self):
#         return os.listdir(self.node_path()).__iter__()
# 
#     def get_signature(self, tip):
#         try:
#             with open(self.tip_path(tip), 'r') as fh:
#                 data = fh.read()
#                 if not data:
#                     return ""
#                 return (int(data),)
#         except IOError:
#             return ""
# 
#     def remove_tip(self, tip, silent=False):
#         try:
#             os.unlink(os.path.join(self.tip_path(tip)))
#         except:
#             if not silent:
#                 raise
# 
#     def direct_parents(self, tip):
#         """Return all parents of `tip` in the order they're written into the
#         object"""
#         obj = object_factory.hydrate_object(self.store[tip].data)
#         if isinstance(obj, RootObject):
#             # Roots can't have parents
#             return []
#         elif isinstance(obj, UpdateObject):
#             return obj.parents
#         else:
#             raise "Unknown object hydrated %s" % (str(type(obj)))
# 
#     def parents(self, tips=None):
#         """Return all ancestors of `tip`, in an undefined order"""
#         # XXX This will asplode the stack at some point
#         parents = set()
#         this_iter = (tips or self.tips())
#         while this_iter:
#             tip = this_iter.pop()
#             tips_parents = self.direct_parents(tip)
#             parents = parents.union(set(tips_parents))
#             this_iter.extend(tips_parents)
#         return parents
# 
#     def marshall(self, crypto_adaptor=None):
#         """Marshalls the gref into something renderable:
#         {
#             "thread": An ordered thread of UpdateObjects. Ordering is
#                       arbitraryish.
#             "roots": The root nodes of this gref.
#             "tips": The string names of the tips used to marshall
#         }
#         """
#         thread = []
#         root_nodes = []
#         visited_nodes = set()
#         tips = []
#         signatures = {}
# 
#         # TODO Big issues will smash the stack
#         def _process(node):
#             if node in visited_nodes:
#                 log.debug("Bailing on visited node: %s" % (node))
#                 return
#             visited_nodes.add(node)
# 
#             if crypto_adaptor:
#                 signature = self.get_signature(node)
#                 if signature:
#                     signatures[node] = crypto_adaptor.verify(node, signature)
# 
#             obj = object_factory.hydrate_object(self.store[node].data)
#             if isinstance(obj, RootObject):  # We've found a root
#                 root_nodes.append(obj)
#                 return
#             for tip in obj.parents:
#                 _process(tip)
#             thread.insert(0, obj)
# 
#         for tip in self:
#             tips.append(tip)
#             log.debug("Descending into %s" % (tip))
#             _process(tip)
#         return {
#                 "thread": thread,
#                 "roots": root_nodes,
#                 "tips": tips,
#                 "signatures": signatures
#                 }
# 
#     def as_dict(self):
#         return {
#                 "channel": self.channel,
#                 "identifier": self.identifier,
#                 "node_path": self._node_path,
#                 "tips": self.tips()
#                 }
# 
# def valid_path(path):
#     test_path = os.path.join("/", path)
#     return os.path.realpath(test_path) == test_path


# Path: test/test_gref.py
from support import store_fixture
from groundstation.gref import Gref, valid_path
import groundstation.store


    def test_get_signature(self):
        gref = Gref(self.repo, "testchannel", "test_get_signature")
        root = self.create_root_object(gref)
        oid = self.repo.create_blob(root.as_object())

        signature = (17**23,)
        gref.write_tip(oid, signature)
        self.assertEqual(signature, gref.get_signature(oid))

    def test_direct_parents(self):
        gref = Gref(self.repo, "testchannel", "test_write_tip")
        root = self.create_root_object(gref)
        root_oid = self.repo.create_blob(root.as_object())

        first_tier = []
        for i in xrange(5):
            obj = self.create_update_object([root_oid], "test_%i")
            oid = self.repo.create_blob(obj.as_object())
            first_tier.append(oid)

        final = self.create_update_object(first_tier, "final object")
        final_oid = self.repo.create_blob(final.as_object())

        gref.write_tip(final_oid, "")
        self.assertEqual(gref.direct_parents(final_oid), first_tier)

    def test_valid_path_works(self):
        self.assertTrue(valid_path("asdf"))
        self.assertTrue(valid_path("asdf/foo"))

        self.assertFalse(valid_path("../asdf/asdfasdf"))