parse_py/ConfHandler.py: Remove broken default options (as identified by mithro)
[bitbake.git] / lib / bb / utils.py
1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 """
4 BitBake Utility Functions
5
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; either version 2 of the License, or (at your option) any later
9 version.
10
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 Place, Suite 330, Boston, MA 02111-1307 USA.
18
19 This file is part of the BitBake build tools.
20 """
21
22 digits = "0123456789"
23 ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
24
25 import re
26
27 def explode_version(s):
28     r = []
29     alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
30     numeric_regexp = re.compile('^(\d+)(.*)$')
31     while (s != ''):
32         if s[0] in digits:
33             m = numeric_regexp.match(s)
34             r.append(int(m.group(1)))
35             s = m.group(2)
36             continue
37         if s[0] in ascii_letters:
38             m = alpha_regexp.match(s)
39             r.append(m.group(1))
40             s = m.group(2)
41             continue
42         s = s[1:]
43     return r
44
45 def vercmp_part(a, b):
46     va = explode_version(a)
47     vb = explode_version(b)
48     while True:
49         if va == []:
50             ca = None
51         else:
52             ca = va.pop(0)
53         if vb == []:
54             cb = None
55         else:
56             cb = vb.pop(0)
57         if ca == None and cb == None:
58             return 0
59         if ca > cb:
60             return 1
61         if ca < cb:
62             return -1
63
64 def vercmp(ta, tb):
65     (va, ra) = ta
66     (vb, rb) = tb
67
68     r = vercmp_part(va, vb)
69     if (r == 0):
70         r = vercmp_part(ra, rb)
71     return r
72
73 def explode_deps(s):
74     """
75     Take an RDEPENDS style string of format:
76     "DEPEND1 (optional version) DEPEND2 (optional version) ..."
77     and return a list of dependencies.
78     Version information is ignored.
79     """
80     r = []
81     l = s.split()
82     flag = False
83     for i in l:
84         if i[0] == '(':
85             flag = True
86             j = []
87         if flag:
88             j.append(i)
89         else:
90             r.append(i)
91         if flag and i.endswith(')'):
92             flag = False
93             # Ignore version
94             #r[-1] += ' ' + ' '.join(j)
95     return r
96
97
98
99 def _print_trace(body, line):
100     """
101     Print the Environment of a Text Body
102     """
103     import bb
104
105     # print the environment of the method
106     bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function")
107     min_line = max(1,line-4)
108     max_line = min(line+4,len(body)-1)
109     for i in range(min_line,max_line+1):
110         bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) )
111
112
113 def better_compile(text, file, realfile):
114     """
115     A better compile method. This method
116     will print  the offending lines.
117     """
118     try:
119         return compile(text, file, "exec")
120     except Exception, e:
121         import bb,sys
122
123         # split the text into lines again
124         body = text.split('\n')
125         bb.msg.error(bb.msg.domain.Util, "Error in compiling: ", realfile)
126         bb.msg.error(bb.msg.domain.Util, "The lines resulting into this error were:")
127         bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1]))
128
129         _print_trace(body, e.lineno)
130
131         # exit now
132         sys.exit(1)
133
134 def better_exec(code, context, text, realfile):
135     """
136     Similiar to better_compile, better_exec will
137     print the lines that are responsible for the
138     error.
139     """
140     import bb,sys
141     try:
142         exec code in context
143     except:
144         (t,value,tb) = sys.exc_info()
145
146         if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
147             raise
148
149         # print the Header of the Error Message
150         bb.msg.error(bb.msg.domain.Util, "Error in executing: ", realfile)
151         bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t,value) )
152
153         # let us find the line number now
154         while tb.tb_next:
155             tb = tb.tb_next
156
157         import traceback
158         line = traceback.tb_lineno(tb)
159
160         _print_trace( text.split('\n'), line )
161         
162         raise
163
164 def Enum(*names):
165    """
166    A simple class to give Enum support
167    """
168
169    assert names, "Empty enums are not supported"
170
171    class EnumClass(object):
172       __slots__ = names
173       def __iter__(self):        return iter(constants)
174       def __len__(self):         return len(constants)
175       def __getitem__(self, i):  return constants[i]
176       def __repr__(self):        return 'Enum' + str(names)
177       def __str__(self):         return 'enum ' + str(constants)
178
179    class EnumValue(object):
180       __slots__ = ('__value')
181       def __init__(self, value): self.__value = value
182       Value = property(lambda self: self.__value)
183       EnumType = property(lambda self: EnumType)
184       def __hash__(self):        return hash(self.__value)
185       def __cmp__(self, other):
186          # C fans might want to remove the following assertion
187          # to make all enums comparable by ordinal value {;))
188          assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
189          return cmp(self.__value, other.__value)
190       def __invert__(self):      return constants[maximum - self.__value]
191       def __nonzero__(self):     return bool(self.__value)
192       def __repr__(self):        return str(names[self.__value])
193
194    maximum = len(names) - 1
195    constants = [None] * len(names)
196    for i, each in enumerate(names):
197       val = EnumValue(i)
198       setattr(EnumClass, each, val)
199       constants[i] = val
200    constants = tuple(constants)
201    EnumType = EnumClass()
202    return EnumType