summaryrefslogtreecommitdiff
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 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake Utility Functions
+"""
+
+# Copyright (C) 2004 Michael Lauer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+digits = "0123456789"
+ascii_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+import re, fcntl, os
+
+def explode_version(s):
+ r = []
+ alpha_regexp = re.compile('^([a-zA-Z]+)(.*)$')
+ numeric_regexp = re.compile('^(\d+)(.*)$')
+ while (s != ''):
+ if s[0] in digits:
+ m = numeric_regexp.match(s)
+ r.append(int(m.group(1)))
+ s = m.group(2)
+ continue
+ if s[0] in ascii_letters:
+ m = alpha_regexp.match(s)
+ r.append(m.group(1))
+ s = m.group(2)
+ continue
+ s = s[1:]
+ return r
+
+def vercmp_part(a, b):
+ va = explode_version(a)
+ vb = explode_version(b)
+ while True:
+ if va == []:
+ ca = None
+ else:
+ ca = va.pop(0)
+ if vb == []:
+ cb = None
+ else:
+ cb = vb.pop(0)
+ if ca == None and cb == None:
+ return 0
+ if ca > cb:
+ return 1
+ if ca < cb:
+ return -1
+
+def vercmp(ta, tb):
+ (ea, va, ra) = ta
+ (eb, vb, rb) = tb
+
+ r = int(ea)-int(eb)
+ if (r == 0):
+ r = vercmp_part(va, vb)
+ if (r == 0):
+ r = vercmp_part(ra, rb)
+ return r
+
+def explode_deps(s):
+ """
+ Take an RDEPENDS style string of format:
+ "DEPEND1 (optional version) DEPEND2 (optional version) ..."
+ and return a list of dependencies.
+ Version information is ignored.
+ """
+ r = []
+ l = s.split()
+ flag = False
+ for i in l:
+ if i[0] == '(':
+ flag = True
+ #j = []
+ if not flag:
+ r.append(i)
+ #else:
+ # j.append(i)
+ if flag and i.endswith(')'):
+ flag = False
+ # Ignore version
+ #r[-1] += ' ' + ' '.join(j)
+ return r
+
+
+
+def _print_trace(body, line):
+ """
+ Print the Environment of a Text Body
+ """
+ import bb
+
+ # print the environment of the method
+ bb.msg.error(bb.msg.domain.Util, "Printing the environment of the function")
+ min_line = max(1,line-4)
+ max_line = min(line+4,len(body)-1)
+ for i in range(min_line,max_line+1):
+ bb.msg.error(bb.msg.domain.Util, "\t%.4d:%s" % (i, body[i-1]) )
+
+
+def better_compile(text, file, realfile):
+ """
+ A better compile method. This method
+ will print the offending lines.
+ """
+ try:
+ return compile(text, file, "exec")
+ except Exception, e:
+ import bb,sys
+
+ # split the text into lines again
+ body = text.split('\n')
+ bb.msg.error(bb.msg.domain.Util, "Error in compiling python function in: ", realfile)
+ bb.msg.error(bb.msg.domain.Util, "The lines resulting into this error were:")
+ bb.msg.error(bb.msg.domain.Util, "\t%d:%s:'%s'" % (e.lineno, e.__class__.__name__, body[e.lineno-1]))
+
+ _print_trace(body, e.lineno)
+
+ # exit now
+ sys.exit(1)
+
+def better_exec(code, context, text, realfile):
+ """
+ Similiar to better_compile, better_exec will
+ print the lines that are responsible for the
+ error.
+ """
+ import bb,sys
+ try:
+ exec code in context
+ except:
+ (t,value,tb) = sys.exc_info()
+
+ if t in [bb.parse.SkipPackage, bb.build.FuncFailed]:
+ raise
+
+ # print the Header of the Error Message
+ bb.msg.error(bb.msg.domain.Util, "Error in executing python function in: ", realfile)
+ bb.msg.error(bb.msg.domain.Util, "Exception:%s Message:%s" % (t,value) )
+
+ # let us find the line number now
+ while tb.tb_next:
+ tb = tb.tb_next
+
+ import traceback
+ line = traceback.tb_lineno(tb)
+
+ _print_trace( text.split('\n'), line )
+
+ raise
+
+def Enum(*names):
+ """
+ A simple class to give Enum support
+ """
+
+ assert names, "Empty enums are not supported"
+
+ class EnumClass(object):
+ __slots__ = names
+ def __iter__(self): return iter(constants)
+ def __len__(self): return len(constants)
+ def __getitem__(self, i): return constants[i]
+ def __repr__(self): return 'Enum' + str(names)
+ def __str__(self): return 'enum ' + str(constants)
+
+ class EnumValue(object):
+ __slots__ = ('__value')
+ def __init__(self, value): self.__value = value
+ Value = property(lambda self: self.__value)
+ EnumType = property(lambda self: EnumType)
+ def __hash__(self): return hash(self.__value)
+ def __cmp__(self, other):
+ # C fans might want to remove the following assertion
+ # to make all enums comparable by ordinal value {;))
+ assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
+ return cmp(self.__value, other.__value)
+ def __invert__(self): return constants[maximum - self.__value]
+ def __nonzero__(self): return bool(self.__value)
+ def __repr__(self): return str(names[self.__value])
+
+ maximum = len(names) - 1
+ constants = [None] * len(names)
+ for i, each in enumerate(names):
+ val = EnumValue(i)
+ setattr(EnumClass, each, val)
+ constants[i] = val
+ constants = tuple(constants)
+ EnumType = EnumClass()
+ return EnumType
+
+def lockfile(name):
+ """
+ Use the file fn as a lock file, return when the lock has been acquired.
+ Returns a variable to pass to unlockfile().
+ """
+ while True:
+ # If we leave the lockfiles lying around there is no problem
+ # but we should clean up after ourselves. This gives potential
+ # for races though. To work around this, when we acquire the lock
+ # we check the file we locked was still the lock file on disk.
+ # by comparing inode numbers. If they don't match or the lockfile
+ # no longer exists, we start again.
+
+ # This implementation is unfair since the last person to request the
+ # lock is the most likely to win it.
+
+ lf = open(name, "a+")
+ fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
+ statinfo = os.fstat(lf.fileno())
+ if os.path.exists(lf.name):
+ statinfo2 = os.stat(lf.name)
+ if statinfo.st_ino == statinfo2.st_ino:
+ return lf
+ # File no longer exists or changed, retry
+ lf.close
+
+def unlockfile(lf):
+ """
+ Unlock a file locked using lockfile()
+ """
+ os.unlink(lf.name)
+ fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
+ lf.close
+
+def md5_file(filename):
+ """
+ Return the hex string representation of the MD5 checksum of filename.
+ """
+ try:
+ import hashlib
+ m = hashlib.md5()
+ except ImportError:
+ import md5
+ m = md5.new()
+
+ for line in open(filename):
+ m.update(line)
+ return m.hexdigest()
+
+def sha256_file(filename):
+ """
+ Return the hex string representation of the 256-bit SHA checksum of
+ filename. On Python 2.4 this will return None, so callers will need to
+ handle that by either skipping SHA checks, or running a standalone sha256sum
+ binary.
+ """
+ try:
+ import hashlib
+ except ImportError:
+ return None
+
+ s = hashlib.sha256()
+ for line in open(filename):
+ s.update(line)
+ return s.hexdigest()