]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/app/__init__.py
Make logging not retarded. Fix tests.
[wizard.git] / wizard / app / __init__.py
index a4a6ca21f04980b3e5176d284d9aa2f52fea31a6..90657630c2cb59fb2c9d946da2b514c3d86bc39d 100644 (file)
@@ -1,23 +1,76 @@
 import os.path
+import re
+
+def expand_re(val):
+    if isinstance(val, str):
+        return re.escape(val)
+    else:
+        return '(?:' + '|'.join(map(expand_re, val)) + ')'
 
 def filename_regex_extractor(f):
-    """This is a decorator to apply to functions that take a name and return
+    """
+    This is a decorator to apply to functions that take a name and return
     (filename, RegexObject) tuples.  It converts it into a function
     that takes a name and returns another function (the actual extractor)
     which takes a deployment and returns the value of the extracted variable.
 
-    Its Haskell-style type signature would be:
+    The regular expression requires a very specific form, essentially ()()()
+    (with the second subgroup being the value we care about), so that we can
+    reuse the regex for other things.
+
+    Its Haskell-style type signature would be::
+
         (String -> (Filename, Regex)) -> (String -> (Deployment -> String))
 
-    It's a little bit like a transformer."""
+    For convenience purposes, we also accept [Filename], in which case
+    we use the first entry (index 0).  Passing an empty list is invalid.
+    """
     def g(var):
         file, regex = f(var)
+        if not isinstance(file, str):
+            file = file[0]
         def h(deployment):
             contents = deployment.read(file) # cached
             match = regex.search(contents)
             if not match: return None
-            # assumes that the first match is the one we want. Hopefully
-            # our regexes can be clever enough to make this work
-            return match.group(1)
+            # assumes that the second match is the one we want.
+            return match.group(2)
         return h
     return g
+
+def filename_regex_substitution(f):
+    """
+    This is a decorator to apply to functions that take a name and return
+    (filename, RegexObject) tuples.  It converts it into a function
+    that takes a name and returns another function (that does substitution)
+    which takes a deployment and modifies its files to replace explicit
+    values with their generic WIZARD_* equivalents.  The final function returns
+    the number of replacements made.
+
+    The regular expression requires a very specific form, essentially ()()()
+    (with the second subgroup being the value to be replaced).
+
+    Its Haskell-style type signature would be::
+
+        (String -> ([Filename], Regex)) -> (String -> (Deployment -> IO Int))
+
+    For convenience purposes, we also accept Filename, in which case it is treated
+    as a single item list.
+    """
+    def g(key, var):
+        files, regex = f(var)
+        if isinstance(files, str):
+            files = (files,)
+        def h(deployment):
+            base = deployment.location
+            subs = 0
+            for file in files:
+                file = os.path.join(base, file)
+                contents = open(file, "r").read()
+                contents, n = regex.subn("\\1" + key + "\\3", contents)
+                subs += n
+                open(file, "w").write(contents)
+            return subs
+        return h
+    return g
+