import os.path import re import wizard 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 (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. 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)) 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): try: contents = deployment.read(file) # cached except IOError: return None match = regex.search(contents) if not match: return None # 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) try: contents = open(file, "r").read() contents, n = regex.subn("\\1" + key + "\\3", contents) subs += n open(file, "w").write(contents) except IOError: pass return subs return h return g class Error(wizard.Error): """Generic error class for this module.""" pass class UpgradeFailure(Error): """Upgrade script failed.""" #: String details of failure (possibly stdout or stderr output) details = None def __init__(self, details): self.details = details def __str__(self): return """ ERROR: Upgrade script failed, details: %s""" % self.details class BackupFailure(Error): """Backup script failed.""" #: String details of failure details = None def __init__(self, details): self.details = details def __str__(self): return """ ERROR: Backup script failed, details: %s""" % self.details class RestoreFailure(Error): """Restore script failed.""" #: String details of failure details = None def __init__(self, details): self.details = details def __str__(self): return """ ERROR: Restore script failed, details: %s""" % self.details