diff options
Diffstat (limited to 'bitbake-dev/lib/bb/utils.py')
-rw-r--r-- | bitbake-dev/lib/bb/utils.py | 431 |
1 files changed, 0 insertions, 431 deletions
diff --git a/bitbake-dev/lib/bb/utils.py b/bitbake-dev/lib/bb/utils.py deleted file mode 100644 index 5fc1463e67..0000000000 --- a/bitbake-dev/lib/bb/utils.py +++ /dev/null | |||
@@ -1,431 +0,0 @@ | |||
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 | separators = ".-" | ||
25 | |||
26 | import re, fcntl, os, types | ||
27 | |||
28 | def explode_version(s): | ||
29 | r = [] | ||
30 | alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$') | ||
31 | numeric_regexp = re.compile('^(\d+)(.*)$') | ||
32 | while (s != ''): | ||
33 | if s[0] in digits: | ||
34 | m = numeric_regexp.match(s) | ||
35 | r.append(int(m.group(1))) | ||
36 | s = m.group(2) | ||
37 | continue | ||
38 | if s[0] in ascii_letters: | ||
39 | m = alpha_regexp.match(s) | ||
40 | r.append(m.group(1)) | ||
41 | s = m.group(2) | ||
42 | continue | ||
43 | r.append(s[0]) | ||
44 | s = s[1:] | ||
45 | return r | ||
46 | |||
47 | def vercmp_part(a, b): | ||
48 | va = explode_version(a) | ||
49 | vb = explode_version(b) | ||
50 | sa = False | ||
51 | sb = False | ||
52 | while True: | ||
53 | if va == []: | ||
54 | ca = None | ||
55 | else: | ||
56 | ca = va.pop(0) | ||
57 | if vb == []: | ||
58 | cb = None | ||
59 | else: | ||
60 | cb = vb.pop(0) | ||
61 | if ca == None and cb == None: | ||
62 | return 0 | ||
63 | |||
64 | if type(ca) is types.StringType: | ||
65 | sa = ca in separators | ||
66 | if type(cb) is types.StringType: | ||
67 | sb = cb in separators | ||
68 | if sa and not sb: | ||
69 | return -1 | ||
70 | if not sa and sb: | ||
71 | return 1 | ||
72 | |||
73 | if ca > cb: | ||
74 | return 1 | ||
75 | if ca < cb: | ||
76 | return -1 | ||
77 | |||
78 | def vercmp(ta, tb): | ||
79 | (ea, va, ra) = ta | ||
80 | (eb, vb, rb) = tb | ||
81 | |||
82 | r = int(ea)-int(eb) | ||
83 | if (r == 0): | ||
84 | r = vercmp_part(va, vb) | ||
85 | if (r == 0): | ||
86 | r = vercmp_part(ra, rb) | ||
87 | return r | ||
88 | |||
89 | def explode_deps(s): | ||
90 | """ | ||
91 | Take an RDEPENDS style string of format: | ||
92 | "DEPEND1 (optional version) DEPEND2 (optional version) ..." | ||
93 | and return a list of dependencies. | ||
94 | Version information is ignored. | ||
95 | """ | ||
96 | r = [] | ||
97 | l = s.split() | ||
98 | flag = False | ||
99 | for i in l: | ||
100 | if i[0] == '(': | ||
101 | flag = True | ||
102 | #j = [] | ||
103 | if not flag: | ||
104 | r.append(i) | ||
105 | #else: | ||
106 | # j.append(i) | ||
107 | if flag and i.endswith(')'): | ||
108 | flag = False | ||
109 | # Ignore version | ||
110 | #r[-1] += ' ' + ' '.join(j) | ||
111 | return r | ||
112 | |||
113 | def explode_dep_versions(s): | ||
114 | """ | ||
115 | Take an RDEPENDS style string of format: | ||
116 | "DEPEND1 (optional version) DEPEND2 (optional version) ..." | ||
117 | and return a dictonary of dependencies and versions. | ||
118 | """ | ||
119 | r = {} | ||
120 | l = s.split() | ||
121 | lastdep = None | ||
122 | lastver = "" | ||
123 | inversion = False | ||
124 | for i in l: | ||
125 | if i[0] == '(': | ||
126 | inversion = True | ||
127 | lastver = i[1:] or "" | ||
128 | #j = [] | ||
129 | elif inversion and i.endswith(')'): | ||
130 | inversion = False | ||
131 | lastver = lastver + " " + (i[:-1] or "") | ||
132 | r[lastdep] = lastver | ||
133 | elif not inversion: | ||
134 | r[i] = None | ||
135 | lastdep = i | ||
136 | lastver = "" | ||
137 | elif inversion: | ||
138 | lastver = lastver + " " + i | ||
139 | |||
140 | return r | ||
141 | |||
142 | def _print_trace(body, line): | ||
143 | """ | ||
144 | Print the Environment of a Text Body | ||
145 | """ | ||
146 | import bb | ||
147 | |||
148 | # print the environment of the method | ||
149 | bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function") | ||
150 | min_line = max(1,line-4) | ||
151 | max_line = min(line+4,len(body)-1) | ||
152 | for i in range(min_line,max_line+1): | ||
153 | bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) ) | ||
154 | |||
155 | |||
156 | def better_compile(text, file, realfile): | ||
157 | """ | ||
158 | A better compile method. This method | ||
159 | will print the offending lines. | ||
160 | """ | ||
161 | try: | ||
162 | return compile(text, file, "exec") | ||
163 | except Exception, e: | ||
164 | import bb,sys | ||
165 | |||
166 | # split the text into lines again | ||
167 | body = text.split('\n') | ||
168 | bb.msg.error(bb.msg.domain.Util, "Error in compiling python function in: ", realfile) | ||
169 | bb.msg.error(bb.msg.domain.Util, "The lines resulting into this error were:") | ||
170 | bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1])) | ||
171 | |||
172 | _print_trace(body, e.lineno) | ||
173 | |||
174 | # exit now | ||
175 | sys.exit(1) | ||
176 | |||
177 | def better_exec(code, context, text, realfile): | ||
178 | """ | ||
179 | Similiar to better_compile, better_exec will | ||
180 | print the lines that are responsible for the | ||
181 | error. | ||
182 | """ | ||
183 | import bb,sys | ||
184 | try: | ||
185 | exec code in context | ||
186 | except: | ||
187 | (t,value,tb) = sys.exc_info() | ||
188 | |||
189 | if t in [bb.parse.SkipPackage, bb.build.FuncFailed]: | ||
190 | raise | ||
191 | |||
192 | # print the Header of the Error Message | ||
193 | bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: %s" % realfile) | ||
194 | bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t,value) ) | ||
195 | |||
196 | # let us find the line number now | ||
197 | while tb.tb_next: | ||
198 | tb = tb.tb_next | ||
199 | |||
200 | import traceback | ||
201 | line = traceback.tb_lineno(tb) | ||
202 | |||
203 | _print_trace( text.split('\n'), line ) | ||
204 | |||
205 | raise | ||
206 | |||
207 | def Enum(*names): | ||
208 | """ | ||
209 | A simple class to give Enum support | ||
210 | """ | ||
211 | |||
212 | assert names, "Empty enums are not supported" | ||
213 | |||
214 | class EnumClass(object): | ||
215 | __slots__ = names | ||
216 | def __iter__(self): return iter(constants) | ||
217 | def __len__(self): return len(constants) | ||
218 | def __getitem__(self, i): return constants[i] | ||
219 | def __repr__(self): return 'Enum' + str(names) | ||
220 | def __str__(self): return 'enum ' + str(constants) | ||
221 | |||
222 | class EnumValue(object): | ||
223 | __slots__ = ('__value') | ||
224 | def __init__(self, value): self.__value = value | ||
225 | Value = property(lambda self: self.__value) | ||
226 | EnumType = property(lambda self: EnumType) | ||
227 | def __hash__(self): return hash(self.__value) | ||
228 | def __cmp__(self, other): | ||
229 | # C fans might want to remove the following assertion | ||
230 | # to make all enums comparable by ordinal value {;)) | ||
231 | assert self.EnumType is other.EnumType, "Only values from the same enum are comparable" | ||
232 | return cmp(self.__value, other.__value) | ||
233 | def __invert__(self): return constants[maximum - self.__value] | ||
234 | def __nonzero__(self): return bool(self.__value) | ||
235 | def __repr__(self): return str(names[self.__value]) | ||
236 | |||
237 | maximum = len(names) - 1 | ||
238 | constants = [None] * len(names) | ||
239 | for i, each in enumerate(names): | ||
240 | val = EnumValue(i) | ||
241 | setattr(EnumClass, each, val) | ||
242 | constants[i] = val | ||
243 | constants = tuple(constants) | ||
244 | EnumType = EnumClass() | ||
245 | return EnumType | ||
246 | |||
247 | def lockfile(name): | ||
248 | """ | ||
249 | Use the file fn as a lock file, return when the lock has been acquired. | ||
250 | Returns a variable to pass to unlockfile(). | ||
251 | """ | ||
252 | path = os.path.dirname(name) | ||
253 | if not os.path.isdir(path): | ||
254 | import bb, sys | ||
255 | bb.msg.error(bb.msg.domain.Util, "Error, lockfile path does not exist!: %s" % path) | ||
256 | sys.exit(1) | ||
257 | |||
258 | while True: | ||
259 | # If we leave the lockfiles lying around there is no problem | ||
260 | # but we should clean up after ourselves. This gives potential | ||
261 | # for races though. To work around this, when we acquire the lock | ||
262 | # we check the file we locked was still the lock file on disk. | ||
263 | # by comparing inode numbers. If they don't match or the lockfile | ||
264 | # no longer exists, we start again. | ||
265 | |||
266 | # This implementation is unfair since the last person to request the | ||
267 | # lock is the most likely to win it. | ||
268 | |||
269 | try: | ||
270 | lf = open(name, "a+") | ||
271 | fcntl.flock(lf.fileno(), fcntl.LOCK_EX) | ||
272 | statinfo = os.fstat(lf.fileno()) | ||
273 | if os.path.exists(lf.name): | ||
274 | statinfo2 = os.stat(lf.name) | ||
275 | if statinfo.st_ino == statinfo2.st_ino: | ||
276 | return lf | ||
277 | # File no longer exists or changed, retry | ||
278 | lf.close | ||
279 | except Exception, e: | ||
280 | continue | ||
281 | |||
282 | def unlockfile(lf): | ||
283 | """ | ||
284 | Unlock a file locked using lockfile() | ||
285 | """ | ||
286 | os.unlink(lf.name) | ||
287 | fcntl.flock(lf.fileno(), fcntl.LOCK_UN) | ||
288 | lf.close | ||
289 | |||
290 | def md5_file(filename): | ||
291 | """ | ||
292 | Return the hex string representation of the MD5 checksum of filename. | ||
293 | """ | ||
294 | try: | ||
295 | import hashlib | ||
296 | m = hashlib.md5() | ||
297 | except ImportError: | ||
298 | import md5 | ||
299 | m = md5.new() | ||
300 | |||
301 | for line in open(filename): | ||
302 | m.update(line) | ||
303 | return m.hexdigest() | ||
304 | |||
305 | def sha256_file(filename): | ||
306 | """ | ||
307 | Return the hex string representation of the 256-bit SHA checksum of | ||
308 | filename. On Python 2.4 this will return None, so callers will need to | ||
309 | handle that by either skipping SHA checks, or running a standalone sha256sum | ||
310 | binary. | ||
311 | """ | ||
312 | try: | ||
313 | import hashlib | ||
314 | except ImportError: | ||
315 | return None | ||
316 | |||
317 | s = hashlib.sha256() | ||
318 | for line in open(filename): | ||
319 | s.update(line) | ||
320 | return s.hexdigest() | ||
321 | |||
322 | def preserved_envvars_list(): | ||
323 | return [ | ||
324 | 'BBPATH', | ||
325 | 'BB_PRESERVE_ENV', | ||
326 | 'BB_ENV_WHITELIST', | ||
327 | 'BB_ENV_EXTRAWHITE', | ||
328 | 'COLORTERM', | ||
329 | 'DBUS_SESSION_BUS_ADDRESS', | ||
330 | 'DESKTOP_SESSION', | ||
331 | 'DESKTOP_STARTUP_ID', | ||
332 | 'DISPLAY', | ||
333 | 'GNOME_KEYRING_PID', | ||
334 | 'GNOME_KEYRING_SOCKET', | ||
335 | 'GPG_AGENT_INFO', | ||
336 | 'GTK_RC_FILES', | ||
337 | 'HOME', | ||
338 | 'LANG', | ||
339 | 'LOGNAME', | ||
340 | 'PATH', | ||
341 | 'PWD', | ||
342 | 'SESSION_MANAGER', | ||
343 | 'SHELL', | ||
344 | 'SSH_AUTH_SOCK', | ||
345 | 'TERM', | ||
346 | 'USER', | ||
347 | 'USERNAME', | ||
348 | '_', | ||
349 | 'XAUTHORITY', | ||
350 | 'XDG_DATA_DIRS', | ||
351 | 'XDG_SESSION_COOKIE', | ||
352 | ] | ||
353 | |||
354 | def filter_environment(good_vars): | ||
355 | """ | ||
356 | Create a pristine environment for bitbake. This will remove variables that | ||
357 | are not known and may influence the build in a negative way. | ||
358 | """ | ||
359 | |||
360 | import bb | ||
361 | |||
362 | removed_vars = [] | ||
363 | for key in os.environ.keys(): | ||
364 | if key in good_vars: | ||
365 | continue | ||
366 | |||
367 | removed_vars.append(key) | ||
368 | os.unsetenv(key) | ||
369 | del os.environ[key] | ||
370 | |||
371 | if len(removed_vars): | ||
372 | bb.debug(1, "Removed the following variables from the environment:", ",".join(removed_vars)) | ||
373 | |||
374 | return removed_vars | ||
375 | |||
376 | def clean_environment(): | ||
377 | """ | ||
378 | Clean up any spurious environment variables. This will remove any | ||
379 | variables the user hasn't chose to preserve. | ||
380 | """ | ||
381 | if 'BB_PRESERVE_ENV' not in os.environ: | ||
382 | if 'BB_ENV_WHITELIST' in os.environ: | ||
383 | good_vars = os.environ['BB_ENV_WHITELIST'].split() | ||
384 | else: | ||
385 | good_vars = preserved_envvars_list() | ||
386 | if 'BB_ENV_EXTRAWHITE' in os.environ: | ||
387 | good_vars.extend(os.environ['BB_ENV_EXTRAWHITE'].split()) | ||
388 | filter_environment(good_vars) | ||
389 | |||
390 | def empty_environment(): | ||
391 | """ | ||
392 | Remove all variables from the environment. | ||
393 | """ | ||
394 | for s in os.environ.keys(): | ||
395 | os.unsetenv(s) | ||
396 | del os.environ[s] | ||
397 | |||
398 | def build_environment(d): | ||
399 | """ | ||
400 | Build an environment from all exported variables. | ||
401 | """ | ||
402 | import bb | ||
403 | for var in bb.data.keys(d): | ||
404 | export = bb.data.getVarFlag(var, "export", d) | ||
405 | if export: | ||
406 | os.environ[var] = bb.data.getVar(var, d, True) | ||
407 | |||
408 | def prunedir(topdir): | ||
409 | # Delete everything reachable from the directory named in 'topdir'. | ||
410 | # CAUTION: This is dangerous! | ||
411 | for root, dirs, files in os.walk(topdir, topdown=False): | ||
412 | for name in files: | ||
413 | os.remove(os.path.join(root, name)) | ||
414 | for name in dirs: | ||
415 | if os.path.islink(os.path.join(root, name)): | ||
416 | os.remove(os.path.join(root, name)) | ||
417 | else: | ||
418 | os.rmdir(os.path.join(root, name)) | ||
419 | os.rmdir(topdir) | ||
420 | |||
421 | # | ||
422 | # Could also use return re.compile("(%s)" % "|".join(map(re.escape, suffixes))).sub(lambda mo: "", var) | ||
423 | # but thats possibly insane and suffixes is probably going to be small | ||
424 | # | ||
425 | def prune_suffix(var, suffixes, d): | ||
426 | # See if var ends with any of the suffixes listed and | ||
427 | # remove it if found | ||
428 | for suffix in suffixes: | ||
429 | if var.endswith(suffix): | ||
430 | return var.replace(suffix, "") | ||
431 | return var | ||