From 8e1ee8d111b0ec5d7bf6b9e8f1dda833e35d30f2 Mon Sep 17 00:00:00 2001 From: Casey Dahlin Date: Sun, 21 Dec 2008 22:19:24 -0500 Subject: Reorganize code into separate files --- statemachine.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 statemachine.py (limited to 'statemachine.py') diff --git a/statemachine.py b/statemachine.py new file mode 100644 index 0000000..5c396eb --- /dev/null +++ b/statemachine.py @@ -0,0 +1,99 @@ +__docformat__ = 'restructuredtext' + +from category import Category + +class StateMachine: + """ + The state machine contains a list of dependencies between states, and a list + of states which are "up." + """ + + def __init__(self): + """ + Create a new state machine + """ + self.holds = {} + self.deps = [] + + def assert_state(self, cat): + """ + Move states in the given Category `cat` from down to up. + """ + found = None + for dependency in self.get_applicable_deps(cat): + res = self.get_satisfied_states(cat, dependency) + if len(res) == 0: + return False + if found == None: + found = res + else: + found = self.intersect_list(found, res) + if found == None: + self.add_hold(cat) + return True + if len(found) == 0: + return False + for x in found: + self.add_hold(x) + return True + + def intersect_list(self, cats1, cats2): + """ + Given two lists of categories, return a list of categories such that a + state appearing in at least one category in each list will appear in at + least one category in the returned list. + """ + retval = set() + found = set() + for x in cats1: + for y in cats2: + if x == y: continue + inter = x.intersect(y) + if inter != None: + retval.add(inter) + found.add(x) + found.add(y) + if len(found) == 0: + return cats1 & cats2 + return (retval | ((cats1 & cats2) - found)) + + def add_hold(self, cat): + """ + Add a hold to a state. Does not check dependencies. + """ + if self.holds.has_key(cat): + self.holds[cat] = self.holds[cat] + 1 + else: + self.holds[cat] = 1 + + def get_satisfied_states(self, dependents, dependencies): + """ + Given that states in `dependents` depend on states in `dependencies`, + return a new Category that contains only the states in `dependents` that + could match states in `dependencies`. + """ + retval = [] + for key, val in self.holds.iteritems(): + if dependencies.equiv(key) and val > 0: + retval.append(dependents.fill(key.args)) + return set(retval) + + def get_applicable_deps(self, cat): + """ + Find dependencies that might apply to members of `cat` + """ + retval = [] + for (x, y) in self.deps: + if x.equiv(cat): + retval.append(y.fill(cat.intersect(x).args)) + return retval + +if __name__ == "__main__": + sm = StateMachine() + sm.deps.append((Category("mounted", type="nfs"), Category("network_up"))) + sm.deps.append((Category("mounted", uuid=None, devname=None, label=None), Category("found_disk", uuid=None, devname=None, label=None))) + sm.deps.append((Category("mounted", uuid=None, devname=None, label=None), Category("vol_conf", uuid=None, devname=None, label=None))) + sm.assert_state(Category("vol_conf", uuid=None, devname=None, label="myroot", type="ext3", mountpoint="/")) + sm.assert_state(Category("found_disk", uuid="d3adb3ef", devname="/dev/sda", label="myroot")) + sm.assert_state(Category("mounted", uuid=None, type="ext3", devname=None, label=None, mountpoint=None)) + print sm.holds -- cgit