s4-param: Use a unique header name
[Samba.git] / buildtools / wafadmin / Environment.py
blob52c83b4f3e45b543563e5777b0d3c38a706ffe98
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Thomas Nagy, 2005 (ita)
5 """Environment representation
7 There is one gotcha: getitem returns [] if the contents evals to False
8 This means env['foo'] = {}; print env['foo'] will print [] not {}
9 """
11 import os, copy, re
12 import Logs, Options, Utils
13 from Constants import *
14 re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M)
16 class Environment(object):
17 """A safe-to-use dictionary, but do not attach functions to it please (break cPickle)
18 An environment instance can be stored into a file and loaded easily
19 """
20 __slots__ = ("table", "parent")
21 def __init__(self, filename=None):
22 self.table = {}
23 #self.parent = None
25 if filename:
26 self.load(filename)
28 def __contains__(self, key):
29 if key in self.table: return True
30 try: return self.parent.__contains__(key)
31 except AttributeError: return False # parent may not exist
33 def __str__(self):
34 keys = set()
35 cur = self
36 while cur:
37 keys.update(cur.table.keys())
38 cur = getattr(cur, 'parent', None)
39 keys = list(keys)
40 keys.sort()
41 return "\n".join(["%r %r" % (x, self.__getitem__(x)) for x in keys])
43 def __getitem__(self, key):
44 try:
45 while 1:
46 x = self.table.get(key, None)
47 if not x is None:
48 return x
49 self = self.parent
50 except AttributeError:
51 return []
53 def __setitem__(self, key, value):
54 self.table[key] = value
56 def __delitem__(self, key):
57 del self.table[key]
59 def pop(self, key, *args):
60 if len(args):
61 return self.table.pop(key, *args)
62 return self.table.pop(key)
64 def set_variant(self, name):
65 self.table[VARIANT] = name
67 def variant(self):
68 try:
69 while 1:
70 x = self.table.get(VARIANT, None)
71 if not x is None:
72 return x
73 self = self.parent
74 except AttributeError:
75 return DEFAULT
77 def copy(self):
78 # TODO waf 1.6 rename this method derive, #368
79 newenv = Environment()
80 newenv.parent = self
81 return newenv
83 def detach(self):
84 """TODO try it
85 modifying the original env will not change the copy"""
86 tbl = self.get_merged_dict()
87 try:
88 delattr(self, 'parent')
89 except AttributeError:
90 pass
91 else:
92 keys = tbl.keys()
93 for x in keys:
94 tbl[x] = copy.deepcopy(tbl[x])
95 self.table = tbl
97 def get_flat(self, key):
98 s = self[key]
99 if isinstance(s, str): return s
100 return ' '.join(s)
102 def _get_list_value_for_modification(self, key):
103 """Gets a value that must be a list for further modification. The
104 list may be modified inplace and there is no need to
105 "self.table[var] = value" afterwards.
107 try:
108 value = self.table[key]
109 except KeyError:
110 try: value = self.parent[key]
111 except AttributeError: value = []
112 if isinstance(value, list):
113 value = value[:]
114 else:
115 value = [value]
116 else:
117 if not isinstance(value, list):
118 value = [value]
119 self.table[key] = value
120 return value
122 def append_value(self, var, value):
123 current_value = self._get_list_value_for_modification(var)
125 if isinstance(value, list):
126 current_value.extend(value)
127 else:
128 current_value.append(value)
130 def prepend_value(self, var, value):
131 current_value = self._get_list_value_for_modification(var)
133 if isinstance(value, list):
134 current_value = value + current_value
135 # a new list: update the dictionary entry
136 self.table[var] = current_value
137 else:
138 current_value.insert(0, value)
140 # prepend unique would be ambiguous
141 def append_unique(self, var, value):
142 current_value = self._get_list_value_for_modification(var)
144 if isinstance(value, list):
145 for value_item in value:
146 if value_item not in current_value:
147 current_value.append(value_item)
148 else:
149 if value not in current_value:
150 current_value.append(value)
152 def get_merged_dict(self):
153 """compute a merged table"""
154 table_list = []
155 env = self
156 while 1:
157 table_list.insert(0, env.table)
158 try: env = env.parent
159 except AttributeError: break
160 merged_table = {}
161 for table in table_list:
162 merged_table.update(table)
163 return merged_table
165 def store(self, filename):
166 "Write the variables into a file"
167 file = open(filename, 'w')
168 merged_table = self.get_merged_dict()
169 keys = list(merged_table.keys())
170 keys.sort()
171 for k in keys: file.write('%s = %r\n' % (k, merged_table[k]))
172 file.close()
174 def load(self, filename):
175 "Retrieve the variables from a file"
176 tbl = self.table
177 code = Utils.readf(filename)
178 for m in re_imp.finditer(code):
179 g = m.group
180 tbl[g(2)] = eval(g(3))
181 Logs.debug('env: %s', self.table)
183 def get_destdir(self):
184 "return the destdir, useful for installing"
185 if self.__getitem__('NOINSTALL'): return ''
186 return Options.options.destdir
188 def update(self, d):
189 for k, v in d.iteritems():
190 self[k] = v
193 def __getattr__(self, name):
194 if name in self.__slots__:
195 return object.__getattr__(self, name)
196 else:
197 return self[name]
199 def __setattr__(self, name, value):
200 if name in self.__slots__:
201 object.__setattr__(self, name, value)
202 else:
203 self[name] = value
205 def __delattr__(self, name):
206 if name in self.__slots__:
207 object.__delattr__(self, name)
208 else:
209 del self[name]