summaryrefslogtreecommitdiffstats
path: root/bitbake-dev/lib/bb/utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake-dev/lib/bb/utils.py')
-rw-r--r--bitbake-dev/lib/bb/utils.py270
1 files changed, 270 insertions, 0 deletions
diff --git a/bitbake-dev/lib/bb/utils.py b/bitbake-dev/lib/bb/utils.py
new file mode 100644
index 0000000000..17e22e389e
--- /dev/null
+++ b/bitbake-dev/lib/bb/utils.py
@@ -0,0 +1,270 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake Utility Functions
5"""
6
7# Copyright (C) 2004 Michael Lauer
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22digits = "0123456789"
23ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
24
25import re, fcntl, os
26
27def 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
45def 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
64def vercmp(ta, tb):
65 (ea, va, ra) = ta
66 (eb, vb, rb) = tb
67
68 r = int(ea)-int(eb)
69 if (r == 0):
70 r = vercmp_part(va, vb)
71 if (r == 0):
72 r = vercmp_part(ra, rb)
73 return r
74
75def explode_deps(s):
76 """
77 Take an RDEPENDS style string of format:
78 "DEPEND1 (optional version) DEPEND2 (optional version) ..."
79 and return a list of dependencies.
80 Version information is ignored.
81 """
82 r = []
83 l = s.split()
84 flag = False
85 for i in l:
86 if i[0] == '(':
87 flag = True
88 #j = []
89 if not flag:
90 r.append(i)
91 #else:
92 # j.append(i)
93 if flag and i.endswith(')'):
94 flag = False
95 # Ignore version
96 #r[-1] += ' ' + ' '.join(j)
97 return r
98
99
100
101def _print_trace(body, line):
102 """
103 Print the Environment of a Text Body
104 """
105 import bb
106
107 # print the environment of the method
108 bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function")
109 min_line = max(1,line-4)
110 max_line = min(line+4,len(body)-1)
111 for i in range(min_line,max_line+1):
112 bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) )
113
114
115def better_compile(text, file, realfile):
116 """
117 A better compile method. This method
118 will print the offending lines.
119 """
120 try:
121 return compile(text, file, "exec")
122 except Exception, e:
123 import bb,sys
124
125 # split the text into lines again
126 body = text.split('\n')
127 bb.msg.error(bb.msg.domain.Util, "Error in compiling python function in: ", realfile)
128 bb.msg.error(bb.msg.domain.Util, "The lines resulting into this error were:")
129 bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1]))
130
131 _print_trace(body, e.lineno)
132
133 # exit now
134 sys.exit(1)
135
136def better_exec(code, context, text, realfile):
137 """
138 Similiar to better_compile, better_exec will
139 print the lines that are responsible for the
140 error.
141 """
142 import bb,sys
143 try:
144 exec code in context
145 except:
146 (t,value,tb) = sys.exc_info()
147
148 if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
149 raise
150
151 # print the Header of the Error Message
152 bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: ", realfile)
153 bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t,value) )
154
155 # let us find the line number now
156 while tb.tb_next:
157 tb = tb.tb_next
158
159 import traceback
160 line = traceback.tb_lineno(tb)
161
162 _print_trace( text.split('\n'), line )
163
164 raise
165
166def Enum(*names):
167 """
168 A simple class to give Enum support
169 """
170
171 assert names, "Empty enums are not supported"
172
173 class EnumClass(object):
174 __slots__ = names
175 def __iter__(self): return iter(constants)
176 def __len__(self): return len(constants)
177 def __getitem__(self, i): return constants[i]
178 def __repr__(self): return 'Enum' + str(names)
179 def __str__(self): return 'enum ' + str(constants)
180
181 class EnumValue(object):
182 __slots__ = ('__value')
183 def __init__(self, value): self.__value = value
184 Value = property(lambda self: self.__value)
185 EnumType = property(lambda self: EnumType)
186 def __hash__(self): return hash(self.__value)
187 def __cmp__(self, other):
188 # C fans might want to remove the following assertion
189 # to make all enums comparable by ordinal value {;))
190 assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
191 return cmp(self.__value, other.__value)
192 def __invert__(self): return constants[maximum - self.__value]
193 def __nonzero__(self): return bool(self.__value)
194 def __repr__(self): return str(names[self.__value])
195
196 maximum = len(names) - 1
197 constants = [None] * len(names)
198 for i, each in enumerate(names):
199 val = EnumValue(i)
200 setattr(EnumClass, each, val)
201 constants[i] = val
202 constants = tuple(constants)
203 EnumType = EnumClass()
204 return EnumType
205
206def lockfile(name):
207 """
208 Use the file fn as a lock file, return when the lock has been acquired.
209 Returns a variable to pass to unlockfile().
210 """
211 while True:
212 # If we leave the lockfiles lying around there is no problem
213 # but we should clean up after ourselves. This gives potential
214 # for races though. To work around this, when we acquire the lock
215 # we check the file we locked was still the lock file on disk.
216 # by comparing inode numbers. If they don't match or the lockfile
217 # no longer exists, we start again.
218
219 # This implementation is unfair since the last person to request the
220 # lock is the most likely to win it.
221
222 lf = open(name, "a+")
223 fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
224 statinfo = os.fstat(lf.fileno())
225 if os.path.exists(lf.name):
226 statinfo2 = os.stat(lf.name)
227 if statinfo.st_ino == statinfo2.st_ino:
228 return lf
229 # File no longer exists or changed, retry
230 lf.close
231
232def unlockfile(lf):
233 """
234 Unlock a file locked using lockfile()
235 """
236 os.unlink(lf.name)
237 fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
238 lf.close
239
240def md5_file(filename):
241 """
242 Return the hex string representation of the MD5 checksum of filename.
243 """
244 try:
245 import hashlib
246 m = hashlib.md5()
247 except ImportError:
248 import md5
249 m = md5.new()
250
251 for line in open(filename):
252 m.update(line)
253 return m.hexdigest()
254
255def sha256_file(filename):
256 """
257 Return the hex string representation of the 256-bit SHA checksum of
258 filename. On Python 2.4 this will return None, so callers will need to
259 handle that by either skipping SHA checks, or running a standalone sha256sum
260 binary.
261 """
262 try:
263 import hashlib
264 except ImportError:
265 return None
266
267 s = hashlib.sha256()
268 for line in open(filename):
269 s.update(line)
270 return s.hexdigest()