diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | legacy/example.rb (renamed from example.rb) | 0 | ||||
-rw-r--r-- | legacy/state.rb (renamed from state.rb) | 0 | ||||
-rw-r--r-- | legacy/test.rb (renamed from test.rb) | 0 | ||||
-rw-r--r-- | legacy/test2.rb (renamed from test2.rb) | 0 | ||||
-rw-r--r-- | state.py | 154 |
6 files changed, 155 insertions, 0 deletions
@@ -1,2 +1,3 @@ .*.swp +*.pyc coverage/ diff --git a/example.rb b/legacy/example.rb index 182ae1d..182ae1d 100644 --- a/example.rb +++ b/legacy/example.rb diff --git a/state.rb b/legacy/state.rb index 02c1bf3..02c1bf3 100644 --- a/state.rb +++ b/legacy/state.rb diff --git a/test2.rb b/legacy/test2.rb index 0a43d58..0a43d58 100644 --- a/test2.rb +++ b/legacy/test2.rb diff --git a/state.py b/state.py new file mode 100644 index 0000000..594b32a --- /dev/null +++ b/state.py @@ -0,0 +1,154 @@ +# +class Category: + def __init__(self, name, **args): + self.args = args + self.name = name + + def equiv(self, other): + if self.name != other.name: return False + for key, value in self.args.iteritems(): + if not other.args.has_key(key): return False + if value == None: continue + if other.args[key] == None: continue + if not other.args[key] == value: return False + return True + + def intersect(self, other): + if self.name != other.name: return None + args = {} + for key in list(set(self.args.keys() + other.args.keys())): + if not self.args.has_key(key): + args[key] = other.args[key] + elif not other.args.has_key(key): + args[key] = self.args[key] + elif self.args[key] == None: + args[key] = other.args[key] + elif other.args[key] == None: + args[key] = self.args[key] + elif self.args[key] != other.args[key]: + return None + else: # self.args[key] == other.args[key] + args[key] = self.args[key] + return Category(self.name, **args) + + def __str__(self): + string = self.name + "(" + had = False + for key, val in self.args.iteritems(): + if had: + string += ", " + had = True + if val == None: + string += "%%%s" % key + else: + string += "%s: %s" % (key, val) + return string + ")" + + def __repr__(self): + return self.__str__() + + def __hash__(self): + return hash((self.argstup(), self.name)) + + def __eq__(self, other): + return self.name == other.name and self.argstup() == other.argstup() + + def argstup(self): + retval = [] + keys = self.args.keys() + keys.sort() + for key in keys: + retval.append((key, self.args[key])) + return tuple(retval) + + def filter(self, other): + if not other.name == self.name: + raise TypeError, "States must be the same class" + args = {} + for key, value in other.args.iteritems(): + if value != None or not self.args.has_key(key): + args[key] = value + else: + args[key] = self.args[key] + return Category(self.name, **args) + + def fill(self, info): + args = {} + for key, value in self.args.iteritems(): + if value != None or not info.has_key(key): + args[key] = value + else: + args[key] = info[key] + return Category(self.name, **args) + + def is_finite(self): + return not None in self.args.values() + +class StateMachine: + def __init__(self): + self.holds = {} + self.deps = [] + + def assert_state(self, cat): + 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): + 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): + 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): + 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): + retval = [] + for (x, y) in self.deps: + if x.equiv(cat): + retval.append(y.fill(cat.filter(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 |