diff options
author | Lars Wirzenius <liw@liw.fi> | 2016-06-12 17:08:54 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2016-06-12 17:08:54 +0300 |
commit | 0773cfd15ff6583d3d900555dfa7a6d01417ac3a (patch) | |
tree | 45c97c6c545059bc42e66e98efeb9272916d7915 | |
parent | dce6ebac72e97b38a416ba07eef1dd19d7e73cdc (diff) | |
download | obnam-0773cfd15ff6583d3d900555dfa7a6d01417ac3a.tar.gz |
Handle cyclic closures
-rw-r--r-- | meliaereader/reader.py | 42 |
1 files changed, 19 insertions, 23 deletions
diff --git a/meliaereader/reader.py b/meliaereader/reader.py index a6961cda..a955b226 100644 --- a/meliaereader/reader.py +++ b/meliaereader/reader.py @@ -65,33 +65,29 @@ class MeliaeReader(object): return [o for o in self if o['type'] == typename] def compute_closures(self): - while True: - refs = self.find_trivial_closures() - if not refs: - break - for ref in refs: - assert ref not in self._closures - self._closures[ref] = self.get_trivial_closure(ref) - - def find_trivial_closures(self): - refs = [] for ref in self._objs: - if ref not in self._closures: - obj = self.get_object(ref) - if all((child_ref in self._closures) for child_ref in obj['refs']): - refs.append(ref) - return refs - - def get_trivial_closure(self, ref): - obj = self.get_object(ref) - refs = set([ref]) - for child_ref in obj['refs']: - refs = refs.union(self._closures.get(child_ref, set())) - return refs + self._closures[ref] = self._simple_get_closure(ref) + assert set(self._objs.keys()) == set(self._closures.keys()) + + def _simple_get_closure(self, ref): # pragma: no cover + closure = set() + todo = [ref] + done = set() + while todo: + ref = todo.pop(0) + done.add(ref) + closure.add(ref) + + obj = self.get_object(ref) + for child_ref in obj['refs']: + if child_ref not in done and child_ref in self: + todo.append(child_ref) + + return closure def get_closure(self, obj, indent=0): ref = obj['address'] - assert ref in self._closures + assert ref in self._closures, 'ref {} not in _closures'.format(ref) return [self.get_object(r) for r in self._closures[ref]] def get_object(self, ref): |