diff options
author | Richard Purdie <richard@openedhand.com> | 2008-09-30 15:08:33 +0000 |
---|---|---|
committer | Richard Purdie <richard@openedhand.com> | 2008-09-30 15:08:33 +0000 |
commit | c30eddb243e7e65f67f656e62848a033cf6f2e5c (patch) | |
tree | 110dd95788b76f55d31cb8d30aac2de8400b6f4a /bitbake-dev/lib/bb/utils.py | |
parent | 5ef0510474004eeb2ae8a99b64e2febb1920e077 (diff) | |
download | poky-c30eddb243e7e65f67f656e62848a033cf6f2e5c.tar.gz |
Add bitbake-dev to allow ease of testing and development of bitbake trunk
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@5337 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake-dev/lib/bb/utils.py')
-rw-r--r-- | bitbake-dev/lib/bb/utils.py | 270 |
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 | """ | ||
4 | BitBake 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 | |||
22 | digits = "0123456789" | ||
23 | ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | ||
24 | |||
25 | import re, fcntl, os | ||
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 | (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 | |||
75 | def 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 | |||
101 | def _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 | |||
115 | def 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 | |||
136 | def 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 | |||
166 | def 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 | |||
206 | def 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 | |||
232 | def 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 | |||
240 | def 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 | |||
255 | def 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() | ||