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.py431
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"""
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"
24separators = ".-"
25
26import re, fcntl, os, types
27
28def 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
47def 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
78def 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
89def 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
113def 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
142def _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
156def 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
177def 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
207def 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
247def 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
282def 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
290def 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
305def 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
322def 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
354def 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
376def 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
390def 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
398def 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
408def 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#
425def 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