]> scripts.mit.edu Git - wizard.git/blob - wizard/app/__init__.py
Implement 'wizard restore'.
[wizard.git] / wizard / app / __init__.py
1 import os.path
2 import re
3
4 import wizard
5
6 def expand_re(val):
7     if isinstance(val, str):
8         return re.escape(val)
9     else:
10         return '(?:' + '|'.join(map(expand_re, val)) + ')'
11
12 def filename_regex_extractor(f):
13     """
14     This is a decorator to apply to functions that take a name and return
15     (filename, RegexObject) tuples.  It converts it into a function
16     that takes a name and returns another function (the actual extractor)
17     which takes a deployment and returns the value of the extracted variable.
18
19     The regular expression requires a very specific form, essentially ()()()
20     (with the second subgroup being the value we care about), so that we can
21     reuse the regex for other things.
22
23     Its Haskell-style type signature would be::
24
25         (String -> (Filename, Regex)) -> (String -> (Deployment -> String))
26
27     For convenience purposes, we also accept [Filename], in which case
28     we use the first entry (index 0).  Passing an empty list is invalid.
29     """
30     def g(var):
31         file, regex = f(var)
32         if not isinstance(file, str):
33             file = file[0]
34         def h(deployment):
35             try:
36                 contents = deployment.read(file) # cached
37             except IOError:
38                 return None
39             match = regex.search(contents)
40             if not match: return None
41             # assumes that the second match is the one we want.
42             return match.group(2)
43         return h
44     return g
45
46 def filename_regex_substitution(f):
47     """
48     This is a decorator to apply to functions that take a name and return
49     (filename, RegexObject) tuples.  It converts it into a function
50     that takes a name and returns another function (that does substitution)
51     which takes a deployment and modifies its files to replace explicit
52     values with their generic WIZARD_* equivalents.  The final function returns
53     the number of replacements made.
54
55     The regular expression requires a very specific form, essentially ()()()
56     (with the second subgroup being the value to be replaced).
57
58     Its Haskell-style type signature would be::
59
60         (String -> ([Filename], Regex)) -> (String -> (Deployment -> IO Int))
61
62     For convenience purposes, we also accept Filename, in which case it is treated
63     as a single item list.
64     """
65     def g(key, var):
66         files, regex = f(var)
67         if isinstance(files, str):
68             files = (files,)
69         def h(deployment):
70             base = deployment.location
71             subs = 0
72             for file in files:
73                 file = os.path.join(base, file)
74                 try:
75                     contents = open(file, "r").read()
76                     contents, n = regex.subn("\\1" + key + "\\3", contents)
77                     subs += n
78                     open(file, "w").write(contents)
79                 except IOError:
80                     pass
81             return subs
82         return h
83     return g
84
85 class Error(wizard.Error):
86     """Generic error class for this module."""
87     pass
88
89 class UpgradeFailure(Error):
90     """Upgrade script failed."""
91     #: String details of failure (possibly stdout or stderr output)
92     details = None
93     def __init__(self, details):
94         self.details = details
95     def __str__(self):
96         return """
97
98 ERROR: Upgrade script failed, details:
99
100 %s""" % self.details
101
102 class BackupFailure(Error):
103     """Backup script failed."""
104     #: String details of failure
105     details = None
106     def __init__(self, details):
107         self.details = details
108     def __str__(self):
109         return """
110
111 ERROR: Backup script failed, details:
112
113 %s""" % self.details
114
115 class RestoreFailure(Error):
116     """Restore script failed."""
117     #: String details of failure
118     details = None
119     def __init__(self, details):
120         self.details = details
121     def __str__(self):
122         return """
123
124 ERROR: Restore script failed, details:
125
126 %s""" % self.details