Package conary :: Package build :: Module macros
[hide private]
[frames] | no frames]

Source Code for Module conary.build.macros

  1  # 
  2  # Copyright (c) 2004-2008 rPath, Inc. 
  3  # 
  4  # This program is distributed under the terms of the Common Public License, 
  5  # version 1.0. A copy of this license should have been distributed with this 
  6  # source file in a file called LICENSE. If it is not present, the license 
  7  # is always available at http://www.rpath.com/permanent/licenses/CPL-1.0. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, but 
 10  # without any warranty; without even the implied warranty of merchantability 
 11  # or fitness for a particular purpose. See the Common Public License for 
 12  # full details. 
 13  # 
 14   
 15  """ 
 16  Module implementing the "macro" dictionary class 
 17  """ 
 18   
 19  import re 
 20   
 21  from conary.build.errors import MacroKeyError 
 22   
23 -class Macros(dict):
24 - def __init__(self, macros={}, shadow=False, ignoreUnknown=False):
25 self.__tracked = {} 26 self.__track = False 27 self.__overrides = {} 28 self.__callbacks = {} 29 self.__ignoreUnknown = ignoreUnknown 30 if shadow: 31 self.__macros = macros 32 else: 33 self.__macros = {} 34 self.update(macros)
35
36 - def _get(self, key):
37 return dict.__getitem__(self, key)
38
39 - def update(self, other):
40 if isinstance(other, dict): 41 for key, item in other.iteritems(): 42 self[key] = item 43 else: 44 for key, item in other: 45 self[key] = item
46
47 - def setCallback(self, name, callback):
48 """ Add a callback to a particular macros. When that macro is 49 accessed, the callback function will be called with that macro's 50 name as an argument 51 """ 52 self.__callbacks[name] = callback
53
54 - def unsetCallback(self, name):
55 del self.__callbacks[name]
56
57 - def __setitem__(self, name, value):
58 if name.startswith('_Macros'): 59 dict.__setitem__(self, name, value) 60 return 61 # '.' in name reserved for getting alternative representations 62 if '.' in name: 63 raise MacroError, 'name "%s" contains illegal character: "."' % name 64 if self.__track: 65 self.__tracked[name] = 1 66 # only expand references to ourself 67 d = {name: self.get(name)} 68 # escape any macros in the new value 69 value = value.replace('%', '%%') 70 # unescape references to ourself 71 value = value.replace('%%%%(%s)s' %name, '%%(%s)s'%name) 72 # expand our old value when defining the new value 73 dict.__setitem__(self, name, value % d)
74 75 # overrides allow you to set a macro value at the command line 76 # or in a config file and use it despite the value being 77 # set subsequently within the recipe 78
79 - def _override(self, key, value):
80 self.__overrides[key] = value 81 self[key] = value
82
83 - def __setattr__(self, name, value):
84 self.__setitem__(name, value)
85
86 - def __getitem__(self, name):
87 if name.startswith('_Macros'): 88 return dict.__getitem__(self, name) 89 repmethod = None 90 parts = name.split('.', 1) 91 if len(parts) > 1: 92 repmethod = parts[1] 93 name = parts[0] 94 if name in self.__callbacks: 95 self.__callbacks[name](name) 96 if name in self.__overrides: 97 return self.__repmethod(self.__overrides[name], repmethod) 98 if not name in self: 99 # update on access 100 try: 101 value = self.__macros[name] 102 except KeyError: 103 # let's make this error message more helpful 104 # so our users will have a chance of debugging. 105 if self.__ignoreUnknown: 106 return '' 107 raise MacroKeyError(name) 108 109 value = self.__macros[name] 110 self[name] = value 111 return self.__repmethod(value, repmethod) 112 else: 113 return self.__repmethod(dict.__getitem__(self, name) % self, repmethod)
114
115 - def __repmethod(self, name, repmethod):
116 if repmethod is None: 117 return name 118 if repmethod == 'literalRegex': 119 return re.escape(name) 120 # should not be reached 121 raise MacroError, 'unknown representation method %s for %s' %(repmethod, name)
122
123 - def __getattr__(self, name):
124 return self.__getitem__(name)
125
126 - def trackChanges(self, flag=True):
127 self.__track = flag
128
129 - def getTrackedChanges(self):
130 return self.__tracked.keys()
131
132 - def copy(self, shadow=True):
133 # shadow saves initial copying cost for a higher search cost 134 if not shadow: 135 return Macros([(x, self._get(x)) for x in dict.__iter__(self)]) 136 return Macros(self, shadow)
137 138 # occasionally it may be desirable to switch from shadowing 139 # to a flattened representation
140 - def _flatten(self):
141 if self.__macros: 142 # just accessing the element will copy it to this 143 # macro 144 for key in self.__macros.keys(): 145 dummy = self[key] 146 self.__macros = {}
147
148 - def __iter__(self):
149 # since we are accessing every element in the parent anyway 150 # just flatten hierarchy first, which greatly simplifies iterating 151 self._flatten() 152 # iter over self and parents 153 for key in dict.__iter__(self): 154 if not key.startswith('_Macros'): 155 yield key
156
157 - def iterkeys(self):
158 for key in self.__iter__(): 159 yield key
160
161 - def iteritems(self):
162 for key in self.__iter__(): 163 yield (key, self[key])
164
165 - def itermacros(self):
166 for key in self.__iter__(): 167 yield (key, self._get(key))
168
169 - def keys(self):
170 return [ x for x in self.__iter__() ]
171 172
173 -class MacroError(Exception):
174 - def __init__(self, msg):
175 self.msg = msg
176
177 - def __repr__(self):
178 return self.msg
179
180 - def __str__(self):
181 return repr(self)
182