summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCasey Dahlin <cdahlin@redhat.com>2008-12-22 02:58:28 -0500
committerCasey Dahlin <cdahlin@redhat.com>2008-12-22 02:58:28 -0500
commitb746901eb0eaf46e163ec1a52211f86fdfbc45f1 (patch)
treed79fc342170074aad852f5455a7b31fcd232a609
parent456d0c14697cf19128a58b40053fa56d1daf21f5 (diff)
downloadupstate-b746901eb0eaf46e163ec1a52211f86fdfbc45f1.tar.gz
upstate-b746901eb0eaf46e163ec1a52211f86fdfbc45f1.tar.xz
upstate-b746901eb0eaf46e163ec1a52211f86fdfbc45f1.zip
Modify system to use proper patterns rather than just strings and blanks
-rw-r--r--category.py67
-rw-r--r--statemachine.py38
2 files changed, 58 insertions, 47 deletions
diff --git a/category.py b/category.py
index 51a36b8..61458dc 100644
--- a/category.py
+++ b/category.py
@@ -1,5 +1,7 @@
__docformat__ = 'restructuredtext'
+from pattern import Pattern
+
class Category:
"""
A Category is a "set" of states. The category specifies a name, certain
@@ -13,26 +15,38 @@ class Category:
Categories are constructed with a `name` and a series of keyword
arguments. `name` is a string. Each keyword argument that is specified
is the name of a state argument a state must posess to be considered to
- be a member of the category. If the value of the keyword argument is
- `None` then the state argument can have any value, otherwise the value is a string
- and specifies a mandatory value for the state argument.
+ be a member of the category. The value of the keyword arguments are
+ patterns that must match the value of the state argument.
"""
self.args = args
self.name = name
def equiv(self, other):
"""
- Returns True if any state in the Category `other` is in this Category. Note that
- this is *intransitive*; ``a.equiv(b)`` is not the same as ``b.equiv(a)``.
+ A Category is equivalent to another Category if:
+ - The other category mandates the same or more arguments
+ - The intersection of the two is nonempty
+ Its an odd relationship, brought about to match expected user behavior
"""
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
+ if not other.args[key].intersect(value).nonempty(): return False
return True
-
+
+ def subtract(self, other):
+ """
+ returns a set of categories that, when combined, include all states
+ that are in `self` but *not* in `other`
+ """
+ retval = set()
+ for key, value in other.args.iteritems():
+ args = {}
+ for k, v in self.args.iteritems(): args[k] = v
+ args[key].intersect(value.complement())
+ if args[key].nonempty():
+ retval.add(Category(self.name, **args))
+
def intersect(self, other):
"""
Returns a new category consisting only of states that are in this
@@ -45,28 +59,19 @@ class Category:
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]
+ else:
+ val = self.args[key].intersect(other.args[key])
+ if not val.nonempty():
+ return None
+ args[key] = val
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 + ")"
+ return "%s(%s)" % (
+ self.name,
+ ", ".join(["%s: %s" % (key, val) \
+ for key, val in self.args.iteritems()])
+ )
def __repr__(self):
return self.__str__()
@@ -95,8 +100,10 @@ class Category:
"""
args = {}
for key, value in self.args.iteritems():
- if value != None or not info.has_key(key):
+ if not info.has_key(key):
args[key] = value
- else:
+ elif not value.singular():
args[key] = info[key]
+ else:
+ args[key] = value
return Category(self.name, **args)
diff --git a/statemachine.py b/statemachine.py
index 5c396eb..cc90793 100644
--- a/statemachine.py
+++ b/statemachine.py
@@ -1,6 +1,7 @@
__docformat__ = 'restructuredtext'
from category import Category
+from pattern import Pattern
class StateMachine:
"""
@@ -20,10 +21,11 @@ class StateMachine:
Move states in the given Category `cat` from down to up.
"""
found = None
- for dependency in self.get_applicable_deps(cat):
+ for (match, dependency) in self.get_applicable_deps(cat):
res = self.get_satisfied_states(cat, dependency)
+ print dependency, res
if len(res) == 0:
- return False
+ res = cat.subtract(match)
if found == None:
found = res
else:
@@ -44,18 +46,12 @@ class StateMachine:
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))
+ return retval
def add_hold(self, cat):
"""
@@ -85,15 +81,23 @@ class StateMachine:
retval = []
for (x, y) in self.deps:
if x.equiv(cat):
- retval.append(y.fill(cat.intersect(x).args))
+ retval.append((x, y.fill(cat.intersect(x).args)))
return retval
+ def __str__(self):
+ return "\n".join(["%s: %s" % (v, k) for k, v in self.holds.iteritems()])
+
+ def __repr__(self):
+ return str(self)
+
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
+ sm.deps.append((Category("mounted", type=Pattern(True, "nfs")), Category("network_up")))
+ sm.deps.append((Category("mounted", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False), type=Pattern(False, "nfs")), Category("found_disk", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False))))
+ sm.deps.append((Category("mounted", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False)), Category("vol_conf", uuid=Pattern(False), devname=Pattern(False), label=Pattern(False))))
+ sm.assert_state(Category("network_up"))
+ sm.assert_state(Category("vol_conf", uuid=Pattern(False), devname=Pattern(False), label=Pattern(True, "myroot"), type=Pattern(True, "ext3"), mountpoint=Pattern(True, "/")))
+ sm.assert_state(Category("vol_conf", uuid=Pattern(False), devname=Pattern(True, "foosrv.com:/vol/home"), label=Pattern(False), type=Pattern(True, "nfs"), mountpoint=Pattern(True, "/home")))
+ sm.assert_state(Category("found_disk", uuid=Pattern(True, "d3adb3ef"), devname=Pattern(True, "/dev/sda"), label=Pattern(True, "myroot")))
+ sm.assert_state(Category("mounted", uuid=Pattern(False), type=Pattern(False), devname=Pattern(False), label=Pattern(False), mountpoint=Pattern(False)))
+ print sm