summaryrefslogtreecommitdiff
path: root/morphlib/morphset.py
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2013-09-19 09:48:06 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2013-09-24 10:26:03 +0000
commitf58e5f85d135d00f92116a97bb8bce82d46f0d36 (patch)
treee38502022e3ac8fe2aa349b55dbe9d0c9cea37a5 /morphlib/morphset.py
parent63dccb712d7d741d5a138f7be0647e9befc80094 (diff)
downloadmorph-f58e5f85d135d00f92116a97bb8bce82d46f0d36.tar.gz
MorphSet: Factor traversal logic out of change_ref
Tweaking all the morphology specs in a MorphologySet is a common operation. - Edit does it to rewrite refs - petrify does it to fix refs to their state at the current point in time - unpetrify does this to reverse the petrify operation - branch-from-image works similarly to petrify After the refs inside morphologies are tweaked, any morphologies in the MorphSet that are referred to by the changed ref are also updated. This was previously an operation of change_ref, but it will be useful for the other use cases. Changes other than refs are not handled, since there are currently no use cases for it.
Diffstat (limited to 'morphlib/morphset.py')
-rw-r--r--morphlib/morphset.py87
1 files changed, 66 insertions, 21 deletions
diff --git a/morphlib/morphset.py b/morphlib/morphset.py
index c256760e..468bcbe9 100644
--- a/morphlib/morphset.py
+++ b/morphlib/morphset.py
@@ -122,6 +122,66 @@ class MorphologySet(object):
raise ChunkNotInStratumError(stratum_morph['name'], chunk_name)
return repo_url, ref, morph
+ def _traverse_specs(self, cb_process, cb_filter=lambda s: True):
+ '''Higher-order function for processing every spec.
+
+ This traverses every spec in all the morphologies, so all chunk,
+ stratum and stratum-build-depend specs are visited.
+
+ It is to be passed one or two callbacks. `cb_process` is given
+ a spec, which it may alter, but if it does, it must return True.
+
+ `cb_filter` is given the morphology, the kind of spec it is
+ working on in addition to the spec itself.
+
+ `cb_filter` is expected to decide whether to run `cb_process`
+ on the spec.
+
+ Arguably this could be checked in `cb_process`, but it can be less
+ logic over all since `cb_process` need not conditionally return.
+
+ If any specs have been altered, at the end of iteration, any
+ morphologies in the MorphologySet that are referred to by an
+ altered spec are also changed.
+
+ This requires a full iteration of the MorphologySet, so it is not a
+ cheap operation.
+
+ A coroutine was attempted, but it required the same amount of
+ code at the call site as doing it by hand.
+
+ '''
+
+ altered_references = {}
+
+ def process_spec_list(m, kind):
+ specs = m[kind]
+ for spec in specs:
+ if cb_filter(m, kind, spec):
+ orig_spec = (spec['repo'], spec['ref'], spec['morph'])
+ dirtied = cb_process(m, kind, spec)
+ if dirtied:
+ m.dirty = True
+ altered_references[orig_spec] = spec
+
+ for m in self.morphologies:
+ if m['kind'] == 'system':
+ process_spec_list(m, 'strata')
+ elif m['kind'] == 'stratum':
+ process_spec_list(m, 'build-depends')
+ process_spec_list(m, 'chunks')
+
+ for m in self.morphologies:
+ tup = (m.repo_url, m.ref, m.filename[:-len('.morph')])
+ if tup in altered_references:
+ spec = altered_references[tup]
+ if m.ref != spec['ref']:
+ m.ref = spec['ref']
+ m.dirty = True
+ assert (m.filename == spec['morph'] + '.morph'
+ or m.repo_url == spec['repo']), \
+ 'Moving morphologies is not supported.'
+
def change_ref(self, repo_url, orig_ref, morph_filename, new_ref):
'''Change a triplet's ref to a new one in all morphologies in a ref.
@@ -130,30 +190,15 @@ class MorphologySet(object):
'''
- def wanted_spec(spec):
+ def wanted_spec(m, kind, spec):
return (spec['repo'] == repo_url and
spec['ref'] == orig_ref and
spec['morph'] + '.morph' == morph_filename)
- def change_specs(specs, m):
- for spec in specs:
- if wanted_spec(spec):
- spec['unpetrify-ref'] = spec['ref']
- spec['ref'] = new_ref
- m.dirty = True
-
- def change(m):
- if m['kind'] == 'system':
- change_specs(m['strata'], m)
- elif m['kind'] == 'stratum':
- change_specs(m['chunks'], m)
- change_specs(m['build-depends'], m)
-
- for m in self.morphologies:
- change(m)
+ def process_spec(m, kind, spec):
+ spec['unpetrify-ref'] = spec['ref']
+ spec['ref'] = new_ref
+ return True
- m = self._get_morphology(repo_url, orig_ref, morph_filename)
- if m and m.ref != new_ref:
- m.ref = new_ref
- m.dirty = True
+ self._traverse_specs(process_spec, wanted_spec)