Package backend :: Package server :: Package config_common :: Module base_templated_document
[hide private]
[frames] | no frames]

Source Code for Module backend.server.config_common.base_templated_document

  1  # 
  2  # Copyright (c) 2008--2016 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15  # 
 16  # Templating code for the configuration management project 
 17  # 
 18   
 19  import re 
 20  import sys 
 21  import string 
 22   
 23  from spacewalk.common.rhnLog import log_error 
 24   
 25   
26 -class BaseTemplatedDocument:
27 compiled_regexes = {} 28
29 - def __init__(self, start_delim=None, end_delim=None):
30 self.start_delim = None 31 self.end_delim = None 32 self.set_delims(start_delim, end_delim) 33 self.functions = {} 34 # To be overridden in a child class 35 self.set_functions()
36
37 - def set_functions(self):
38 pass
39
40 - def set_delims(self, start_delim=None, end_delim=None):
41 if '%' in (start_delim, end_delim): 42 raise ValueError("Cannot use `%' as a delimiter") 43 if self.start_delim is None and start_delim is None: 44 start_delim = '{{' 45 if self.start_delim is None or start_delim is not None: 46 self.start_delim = start_delim 47 # if start_delim is None and self.start_denim is set, don't overwrite 48 49 if self.end_delim is None and end_delim is None: 50 end_delim = '{{' 51 if self.end_delim is None or end_delim is not None: 52 self.end_delim = end_delim 53 54 # delims might have special characters that are regexp-relevant, 55 # need to escape those 56 escaped_start_delim = re.escape(self.start_delim) 57 escaped_end_delim = re.escape(self.end_delim) 58 59 regex_key = (self.start_delim, self.end_delim) 60 61 # At this point, self.start_delim and self.end_delim are non-null 62 if regex_key in self.compiled_regexes: 63 # We already have the regex compiled 64 self.regex = self.compiled_regexes[regex_key] 65 return 66 67 # We have to convince .* to match as few repetitions as possible, 68 # otherwise it's possible to match end_delims too; using .*? then 69 self.regex = re.compile(escaped_start_delim + r"(.*?)" + escaped_end_delim) 70 self.compiled_regexes[regex_key] = self.regex 71 72 self.compiled_regexes[self.start_delim] = re.compile("(%s)" % escaped_start_delim) 73 self.compiled_regexes[self.end_delim] = re.compile("(%s)" % escaped_end_delim)
74
75 - def repl_func(self, match_object):
76 try: 77 return self._repl_func(match_object) 78 except ValueError: 79 e = sys.exc_info()[1] 80 log_error("cfg variable interpolation error", e) 81 return match_object.group()
82
83 - def _repl_func(self, match_object):
84 return ""
85
86 - def interpolate(self, data):
87 return self.regex.sub(self.repl_func, data)
88 89
90 -class TemplatedDocument(BaseTemplatedDocument):
91 func_regex = re.compile("^(?P<fname>[^=]+)(=(?P<defval>.*))?$") 92 funcname_regex = re.compile("^[A-Za-z][\w._]*$") 93
94 - def _repl_func(self, match_object):
95 funcname = match_object.groups()[0] 96 funcname = string.strip(funcname) 97 fname, params, defval = self.parse_func_name(funcname) 98 return self.call(fname, params, defval)
99
100 - def parse_func_name(self, fstr):
101 mo = self.func_regex.match(fstr) 102 if not mo: 103 # XXX raise exceptions 104 return (None, None, None) 105 dict = mo.groupdict() 106 fname = dict.get('fname') 107 defval = dict.get('defval') 108 109 fname = self.strip(fname) 110 defval = self.unquote(defval) 111 params = None 112 113 if fname[-1] == ')': 114 # Params are present 115 i = string.rfind(fname, '(') 116 if i < 0: 117 raise ValueError("Missing (") 118 119 params = fname[i + 1:-1] 120 fname = string.strip(fname[:i]) 121 122 # Parse the params 123 params = list(map(self.unquote, [_f for _f in string.split(params, ',') if _f])) 124 125 # Validate the function name 126 if not self.funcname_regex.match(fname): 127 raise ValueError("Invalid function name %s" % fname) 128 129 return fname, params, defval
130
131 - def null_call(self, fname, params, defval):
132 val = fname 133 if params: 134 val = "%s(%s)" % (val, string.join(params, ', ')) 135 if defval is not None: 136 val = "%s = %s" % (val, defval) 137 return "%s %s %s" % (self.start_delim, val, self.end_delim)
138
139 - def lookup_function(self, fname):
140 return self.functions.get(fname)
141
142 - def call(self, fname, params, defval):
143 f = self.lookup_function(fname) 144 if f is None: 145 return str(self.fallback_call(fname, params, defval)) 146 if params is None: 147 params = () 148 149 result = f(*params) 150 151 if result is None: 152 if defval: 153 return defval 154 return '' 155 156 return str(result)
157 158 # What to do when the function was not found? 159 # To be overridden in subclasses
160 - def fallback_call(self, fname, params, defval):
161 raise InvalidFunctionError(fname)
162
163 - def test(self):
164 escaped = self.regex.sub(self.repl_func, 'abc @@ aa @@ def') 165 print(escaped)
166
167 - def strip(self, s):
168 if s is None: 169 return None 170 return string.strip(s)
171
172 - def unquote(self, s):
173 if s is None: 174 return None 175 s = string.strip(s) 176 if len(s) <= 1: 177 # Nothing to unquote 178 return s 179 180 if s[0] == s[-1] and s[0] in ['"', "'"]: 181 # Strip quotes 182 return s[1:-1] 183 184 return s
185 186
187 -class InvalidFunctionError(Exception):
188 pass
189