Include waf as an extracted source directory, rather than as a one-in-a-file script.
[ira/wip.git] / buildtools / wafadmin / Environment.py
diff --git a/buildtools/wafadmin/Environment.py b/buildtools/wafadmin/Environment.py
new file mode 100644 (file)
index 0000000..52c83b4
--- /dev/null
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005 (ita)
+
+"""Environment representation
+
+There is one gotcha: getitem returns [] if the contents evals to False
+This means env['foo'] = {}; print env['foo'] will print [] not {}
+"""
+
+import os, copy, re
+import Logs, Options, Utils
+from Constants import *
+re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M)
+
+class Environment(object):
+       """A safe-to-use dictionary, but do not attach functions to it please (break cPickle)
+       An environment instance can be stored into a file and loaded easily
+       """
+       __slots__ = ("table", "parent")
+       def __init__(self, filename=None):
+               self.table = {}
+               #self.parent = None
+
+               if filename:
+                       self.load(filename)
+
+       def __contains__(self, key):
+               if key in self.table: return True
+               try: return self.parent.__contains__(key)
+               except AttributeError: return False # parent may not exist
+
+       def __str__(self):
+               keys = set()
+               cur = self
+               while cur:
+                       keys.update(cur.table.keys())
+                       cur = getattr(cur, 'parent', None)
+               keys = list(keys)
+               keys.sort()
+               return "\n".join(["%r %r" % (x, self.__getitem__(x)) for x in keys])
+
+       def __getitem__(self, key):
+               try:
+                       while 1:
+                               x = self.table.get(key, None)
+                               if not x is None:
+                                       return x
+                               self = self.parent
+               except AttributeError:
+                       return []
+
+       def __setitem__(self, key, value):
+               self.table[key] = value
+
+       def __delitem__(self, key):
+               del self.table[key]
+
+       def pop(self, key, *args):
+               if len(args):
+                       return self.table.pop(key, *args)
+               return self.table.pop(key)
+
+       def set_variant(self, name):
+               self.table[VARIANT] = name
+
+       def variant(self):
+               try:
+                       while 1:
+                               x = self.table.get(VARIANT, None)
+                               if not x is None:
+                                       return x
+                               self = self.parent
+               except AttributeError:
+                       return DEFAULT
+
+       def copy(self):
+               # TODO waf 1.6 rename this method derive, #368
+               newenv = Environment()
+               newenv.parent = self
+               return newenv
+
+       def detach(self):
+               """TODO try it
+               modifying the original env will not change the copy"""
+               tbl = self.get_merged_dict()
+               try:
+                       delattr(self, 'parent')
+               except AttributeError:
+                       pass
+               else:
+                       keys = tbl.keys()
+                       for x in keys:
+                               tbl[x] = copy.deepcopy(tbl[x])
+                       self.table = tbl
+
+       def get_flat(self, key):
+               s = self[key]
+               if isinstance(s, str): return s
+               return ' '.join(s)
+
+       def _get_list_value_for_modification(self, key):
+               """Gets a value that must be a list for further modification.  The
+               list may be modified inplace and there is no need to
+               "self.table[var] = value" afterwards.
+               """
+               try:
+                       value = self.table[key]
+               except KeyError:
+                       try: value = self.parent[key]
+                       except AttributeError: value = []
+                       if isinstance(value, list):
+                               value = value[:]
+                       else:
+                               value = [value]
+               else:
+                       if not isinstance(value, list):
+                               value = [value]
+               self.table[key] = value
+               return value
+
+       def append_value(self, var, value):
+               current_value = self._get_list_value_for_modification(var)
+
+               if isinstance(value, list):
+                       current_value.extend(value)
+               else:
+                       current_value.append(value)
+
+       def prepend_value(self, var, value):
+               current_value = self._get_list_value_for_modification(var)
+
+               if isinstance(value, list):
+                       current_value = value + current_value
+                       # a new list: update the dictionary entry
+                       self.table[var] = current_value
+               else:
+                       current_value.insert(0, value)
+
+       # prepend unique would be ambiguous
+       def append_unique(self, var, value):
+               current_value = self._get_list_value_for_modification(var)
+
+               if isinstance(value, list):
+                       for value_item in value:
+                               if value_item not in current_value:
+                                       current_value.append(value_item)
+               else:
+                       if value not in current_value:
+                               current_value.append(value)
+
+       def get_merged_dict(self):
+               """compute a merged table"""
+               table_list = []
+               env = self
+               while 1:
+                       table_list.insert(0, env.table)
+                       try: env = env.parent
+                       except AttributeError: break
+               merged_table = {}
+               for table in table_list:
+                       merged_table.update(table)
+               return merged_table
+
+       def store(self, filename):
+               "Write the variables into a file"
+               file = open(filename, 'w')
+               merged_table = self.get_merged_dict()
+               keys = list(merged_table.keys())
+               keys.sort()
+               for k in keys: file.write('%s = %r\n' % (k, merged_table[k]))
+               file.close()
+
+       def load(self, filename):
+               "Retrieve the variables from a file"
+               tbl = self.table
+               code = Utils.readf(filename)
+               for m in re_imp.finditer(code):
+                       g = m.group
+                       tbl[g(2)] = eval(g(3))
+               Logs.debug('env: %s', self.table)
+
+       def get_destdir(self):
+               "return the destdir, useful for installing"
+               if self.__getitem__('NOINSTALL'): return ''
+               return Options.options.destdir
+
+       def update(self, d):
+               for k, v in d.iteritems():
+                       self[k] = v
+
+
+       def __getattr__(self, name):
+               if name in self.__slots__:
+                       return object.__getattr__(self, name)
+               else:
+                       return self[name]
+
+       def __setattr__(self, name, value):
+               if name in self.__slots__:
+                       object.__setattr__(self, name, value)
+               else:
+                       self[name] = value
+
+       def __delattr__(self, name):
+               if name in self.__slots__:
+                       object.__delattr__(self, name)
+               else:
+                       del self[name]
+