|
rpm-build |
95f51c |
#!/usr/bin/env python
|
|
rpm-build |
95f51c |
# encoding: utf-8
|
|
rpm-build |
95f51c |
# Thomas Nagy, 2005-2018 (ita)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Utilities and platform-specific fixes
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
The portability fixes try to provide a consistent behavior of the Waf API
|
|
rpm-build |
95f51c |
through Python versions 2.5 to 3.X and across different platforms (win32, linux, etc)
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
from __future__ import with_statement
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
import atexit, os, sys, errno, inspect, re, datetime, platform, base64, signal, functools, time
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
import cPickle
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
import pickle as cPickle
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
# leave this
|
|
rpm-build |
95f51c |
if os.name == 'posix' and sys.version_info[0] < 3:
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
import subprocess32 as subprocess
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
import subprocess
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
import subprocess
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
TimeoutExpired = subprocess.TimeoutExpired
|
|
rpm-build |
95f51c |
except AttributeError:
|
|
rpm-build |
95f51c |
class TimeoutExpired(Exception):
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
from collections import deque, defaultdict
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
import _winreg as winreg
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
import winreg
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
winreg = None
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
from waflib import Errors
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
from hashlib import md5
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
from hashlib import sha1 as md5
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
# never fail to enable potential fixes from another module
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
md5().digest()
|
|
rpm-build |
95f51c |
except ValueError:
|
|
rpm-build |
95f51c |
# Fips? #2213
|
|
rpm-build |
95f51c |
from hashlib import sha1 as md5
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
import threading
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
if not 'JOBS' in os.environ:
|
|
rpm-build |
95f51c |
# no threading :-(
|
|
rpm-build |
95f51c |
os.environ['JOBS'] = '1'
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
class threading(object):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
A fake threading class for platforms lacking the threading module.
|
|
rpm-build |
95f51c |
Use ``waf -j1`` on those platforms
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
class Lock(object):
|
|
rpm-build |
95f51c |
"""Fake Lock class"""
|
|
rpm-build |
95f51c |
def acquire(self):
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
def release(self):
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
threading.Lock = threading.Thread = Lock
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
SIG_NIL = 'SIG_NIL_SIG_NIL_'.encode()
|
|
rpm-build |
95f51c |
"""Arbitrary null value for hashes. Modify this value according to the hash function in use"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
O644 = 420
|
|
rpm-build |
95f51c |
"""Constant representing the permissions for regular files (0644 raises a syntax error on python 3)"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
O755 = 493
|
|
rpm-build |
95f51c |
"""Constant representing the permissions for executable files (0755 raises a syntax error on python 3)"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
rot_chr = ['\\', '|', '/', '-']
|
|
rpm-build |
95f51c |
"List of characters to use when displaying the throbber (progress bar)"
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
rot_idx = 0
|
|
rpm-build |
95f51c |
"Index of the current throbber character (progress bar)"
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
class ordered_iter_dict(dict):
|
|
rpm-build |
95f51c |
"""Ordered dictionary that provides iteration from the most recently inserted keys first"""
|
|
rpm-build |
95f51c |
def __init__(self, *k, **kw):
|
|
rpm-build |
95f51c |
self.lst = deque()
|
|
rpm-build |
95f51c |
dict.__init__(self, *k, **kw)
|
|
rpm-build |
95f51c |
def clear(self):
|
|
rpm-build |
95f51c |
dict.clear(self)
|
|
rpm-build |
95f51c |
self.lst = deque()
|
|
rpm-build |
95f51c |
def __setitem__(self, key, value):
|
|
rpm-build |
95f51c |
if key in dict.keys(self):
|
|
rpm-build |
95f51c |
self.lst.remove(key)
|
|
rpm-build |
95f51c |
dict.__setitem__(self, key, value)
|
|
rpm-build |
95f51c |
self.lst.append(key)
|
|
rpm-build |
95f51c |
def __delitem__(self, key):
|
|
rpm-build |
95f51c |
dict.__delitem__(self, key)
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
self.lst.remove(key)
|
|
rpm-build |
95f51c |
except ValueError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
def __iter__(self):
|
|
rpm-build |
95f51c |
return reversed(self.lst)
|
|
rpm-build |
95f51c |
def keys(self):
|
|
rpm-build |
95f51c |
return reversed(self.lst)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
class lru_node(object):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Used by :py:class:`waflib.Utils.lru_cache`
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
__slots__ = ('next', 'prev', 'key', 'val')
|
|
rpm-build |
95f51c |
def __init__(self):
|
|
rpm-build |
95f51c |
self.next = self
|
|
rpm-build |
95f51c |
self.prev = self
|
|
rpm-build |
95f51c |
self.key = None
|
|
rpm-build |
95f51c |
self.val = None
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
class lru_cache(object):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
A simple least-recently used cache with lazy allocation
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
__slots__ = ('maxlen', 'table', 'head')
|
|
rpm-build |
95f51c |
def __init__(self, maxlen=100):
|
|
rpm-build |
95f51c |
self.maxlen = maxlen
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Maximum amount of elements in the cache
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
self.table = {}
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Mapping key-value
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
self.head = lru_node()
|
|
rpm-build |
95f51c |
self.head.next = self.head
|
|
rpm-build |
95f51c |
self.head.prev = self.head
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def __getitem__(self, key):
|
|
rpm-build |
95f51c |
node = self.table[key]
|
|
rpm-build |
95f51c |
# assert(key==node.key)
|
|
rpm-build |
95f51c |
if node is self.head:
|
|
rpm-build |
95f51c |
return node.val
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
# detach the node found
|
|
rpm-build |
95f51c |
node.prev.next = node.next
|
|
rpm-build |
95f51c |
node.next.prev = node.prev
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
# replace the head
|
|
rpm-build |
95f51c |
node.next = self.head.next
|
|
rpm-build |
95f51c |
node.prev = self.head
|
|
rpm-build |
95f51c |
self.head = node.next.prev = node.prev.next = node
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
return node.val
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def __setitem__(self, key, val):
|
|
rpm-build |
95f51c |
if key in self.table:
|
|
rpm-build |
95f51c |
# update the value for an existing key
|
|
rpm-build |
95f51c |
node = self.table[key]
|
|
rpm-build |
95f51c |
node.val = val
|
|
rpm-build |
95f51c |
self.__getitem__(key)
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
if len(self.table) < self.maxlen:
|
|
rpm-build |
95f51c |
# the very first item is unused until the maximum is reached
|
|
rpm-build |
95f51c |
node = lru_node()
|
|
rpm-build |
95f51c |
node.prev = self.head
|
|
rpm-build |
95f51c |
node.next = self.head.next
|
|
rpm-build |
95f51c |
node.prev.next = node.next.prev = node
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
node = self.head = self.head.next
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
# that's another key
|
|
rpm-build |
95f51c |
del self.table[node.key]
|
|
rpm-build |
95f51c |
except KeyError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
node.key = key
|
|
rpm-build |
95f51c |
node.val = val
|
|
rpm-build |
95f51c |
self.table[key] = node
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
class lazy_generator(object):
|
|
rpm-build |
95f51c |
def __init__(self, fun, params):
|
|
rpm-build |
95f51c |
self.fun = fun
|
|
rpm-build |
95f51c |
self.params = params
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def __iter__(self):
|
|
rpm-build |
95f51c |
return self
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def __next__(self):
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
it = self.it
|
|
rpm-build |
95f51c |
except AttributeError:
|
|
rpm-build |
95f51c |
it = self.it = self.fun(*self.params)
|
|
rpm-build |
95f51c |
return next(it)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
next = __next__
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
is_win32 = os.sep == '\\' or sys.platform == 'win32' or os.name == 'nt' # msys2
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Whether this system is a Windows series
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def readf(fname, m='r', encoding='latin-1'):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Reads an entire file into a string. See also :py:meth:`waflib.Node.Node.readf`::
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def build(ctx):
|
|
rpm-build |
95f51c |
from waflib import Utils
|
|
rpm-build |
95f51c |
txt = Utils.readf(self.path.find_node('wscript').abspath())
|
|
rpm-build |
95f51c |
txt = ctx.path.find_node('wscript').read()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type fname: string
|
|
rpm-build |
95f51c |
:param fname: Path to file
|
|
rpm-build |
95f51c |
:type m: string
|
|
rpm-build |
95f51c |
:param m: Open mode
|
|
rpm-build |
95f51c |
:type encoding: string
|
|
rpm-build |
95f51c |
:param encoding: encoding value, only used for python 3
|
|
rpm-build |
95f51c |
:rtype: string
|
|
rpm-build |
95f51c |
:return: Content of the file
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if sys.hexversion > 0x3000000 and not 'b' in m:
|
|
rpm-build |
95f51c |
m += 'b'
|
|
rpm-build |
95f51c |
with open(fname, m) as f:
|
|
rpm-build |
95f51c |
txt = f.read()
|
|
rpm-build |
95f51c |
if encoding:
|
|
rpm-build |
95f51c |
txt = txt.decode(encoding)
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
txt = txt.decode()
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
with open(fname, m) as f:
|
|
rpm-build |
95f51c |
txt = f.read()
|
|
rpm-build |
95f51c |
return txt
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def writef(fname, data, m='w', encoding='latin-1'):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Writes an entire file from a string.
|
|
rpm-build |
95f51c |
See also :py:meth:`waflib.Node.Node.writef`::
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def build(ctx):
|
|
rpm-build |
95f51c |
from waflib import Utils
|
|
rpm-build |
95f51c |
txt = Utils.writef(self.path.make_node('i_like_kittens').abspath(), 'some data')
|
|
rpm-build |
95f51c |
self.path.make_node('i_like_kittens').write('some data')
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type fname: string
|
|
rpm-build |
95f51c |
:param fname: Path to file
|
|
rpm-build |
95f51c |
:type data: string
|
|
rpm-build |
95f51c |
:param data: The contents to write to the file
|
|
rpm-build |
95f51c |
:type m: string
|
|
rpm-build |
95f51c |
:param m: Open mode
|
|
rpm-build |
95f51c |
:type encoding: string
|
|
rpm-build |
95f51c |
:param encoding: encoding value, only used for python 3
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if sys.hexversion > 0x3000000 and not 'b' in m:
|
|
rpm-build |
95f51c |
data = data.encode(encoding)
|
|
rpm-build |
95f51c |
m += 'b'
|
|
rpm-build |
95f51c |
with open(fname, m) as f:
|
|
rpm-build |
95f51c |
f.write(data)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def h_file(fname):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Computes a hash value for a file by using md5. Use the md5_tstamp
|
|
rpm-build |
95f51c |
extension to get faster build hashes if necessary.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type fname: string
|
|
rpm-build |
95f51c |
:param fname: path to the file to hash
|
|
rpm-build |
95f51c |
:return: hash of the file contents
|
|
rpm-build |
95f51c |
:rtype: string or bytes
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
m = md5()
|
|
rpm-build |
95f51c |
with open(fname, 'rb') as f:
|
|
rpm-build |
95f51c |
while fname:
|
|
rpm-build |
95f51c |
fname = f.read(200000)
|
|
rpm-build |
95f51c |
m.update(fname)
|
|
rpm-build |
95f51c |
return m.digest()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def readf_win32(f, m='r', encoding='latin-1'):
|
|
rpm-build |
95f51c |
flags = os.O_NOINHERIT | os.O_RDONLY
|
|
rpm-build |
95f51c |
if 'b' in m:
|
|
rpm-build |
95f51c |
flags |= os.O_BINARY
|
|
rpm-build |
95f51c |
if '+' in m:
|
|
rpm-build |
95f51c |
flags |= os.O_RDWR
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
fd = os.open(f, flags)
|
|
rpm-build |
95f51c |
except OSError:
|
|
rpm-build |
95f51c |
raise IOError('Cannot read from %r' % f)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if sys.hexversion > 0x3000000 and not 'b' in m:
|
|
rpm-build |
95f51c |
m += 'b'
|
|
rpm-build |
95f51c |
with os.fdopen(fd, m) as f:
|
|
rpm-build |
95f51c |
txt = f.read()
|
|
rpm-build |
95f51c |
if encoding:
|
|
rpm-build |
95f51c |
txt = txt.decode(encoding)
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
txt = txt.decode()
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
with os.fdopen(fd, m) as f:
|
|
rpm-build |
95f51c |
txt = f.read()
|
|
rpm-build |
95f51c |
return txt
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def writef_win32(f, data, m='w', encoding='latin-1'):
|
|
rpm-build |
95f51c |
if sys.hexversion > 0x3000000 and not 'b' in m:
|
|
rpm-build |
95f51c |
data = data.encode(encoding)
|
|
rpm-build |
95f51c |
m += 'b'
|
|
rpm-build |
95f51c |
flags = os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT
|
|
rpm-build |
95f51c |
if 'b' in m:
|
|
rpm-build |
95f51c |
flags |= os.O_BINARY
|
|
rpm-build |
95f51c |
if '+' in m:
|
|
rpm-build |
95f51c |
flags |= os.O_RDWR
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
fd = os.open(f, flags)
|
|
rpm-build |
95f51c |
except OSError:
|
|
rpm-build |
95f51c |
raise OSError('Cannot write to %r' % f)
|
|
rpm-build |
95f51c |
with os.fdopen(fd, m) as f:
|
|
rpm-build |
95f51c |
f.write(data)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def h_file_win32(fname):
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
fd = os.open(fname, os.O_BINARY | os.O_RDONLY | os.O_NOINHERIT)
|
|
rpm-build |
95f51c |
except OSError:
|
|
rpm-build |
95f51c |
raise OSError('Cannot read from %r' % fname)
|
|
rpm-build |
95f51c |
m = md5()
|
|
rpm-build |
95f51c |
with os.fdopen(fd, 'rb') as f:
|
|
rpm-build |
95f51c |
while fname:
|
|
rpm-build |
95f51c |
fname = f.read(200000)
|
|
rpm-build |
95f51c |
m.update(fname)
|
|
rpm-build |
95f51c |
return m.digest()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
# always save these
|
|
rpm-build |
95f51c |
readf_unix = readf
|
|
rpm-build |
95f51c |
writef_unix = writef
|
|
rpm-build |
95f51c |
h_file_unix = h_file
|
|
rpm-build |
95f51c |
if hasattr(os, 'O_NOINHERIT') and sys.hexversion < 0x3040000:
|
|
rpm-build |
95f51c |
# replace the default functions
|
|
rpm-build |
95f51c |
readf = readf_win32
|
|
rpm-build |
95f51c |
writef = writef_win32
|
|
rpm-build |
95f51c |
h_file = h_file_win32
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
x = ''.encode('hex')
|
|
rpm-build |
95f51c |
except LookupError:
|
|
rpm-build |
95f51c |
import binascii
|
|
rpm-build |
95f51c |
def to_hex(s):
|
|
rpm-build |
95f51c |
ret = binascii.hexlify(s)
|
|
rpm-build |
95f51c |
if not isinstance(ret, str):
|
|
rpm-build |
95f51c |
ret = ret.decode('utf-8')
|
|
rpm-build |
95f51c |
return ret
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
def to_hex(s):
|
|
rpm-build |
95f51c |
return s.encode('hex')
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
to_hex.__doc__ = """
|
|
rpm-build |
95f51c |
Return the hexadecimal representation of a string
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param s: string to convert
|
|
rpm-build |
95f51c |
:type s: string
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def listdir_win32(s):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Lists the contents of a folder in a portable manner.
|
|
rpm-build |
95f51c |
On Win32, returns the list of drive letters: ['C:', 'X:', 'Z:'] when an empty string is given.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type s: string
|
|
rpm-build |
95f51c |
:param s: a string, which can be empty on Windows
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if not s:
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
import ctypes
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
# there is nothing much we can do
|
|
rpm-build |
95f51c |
return [x + ':\\' for x in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
dlen = 4 # length of "?:\\x00"
|
|
rpm-build |
95f51c |
maxdrives = 26
|
|
rpm-build |
95f51c |
buf = ctypes.create_string_buffer(maxdrives * dlen)
|
|
rpm-build |
95f51c |
ndrives = ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives*dlen, ctypes.byref(buf))
|
|
rpm-build |
95f51c |
return [ str(buf.raw[4*i:4*i+2].decode('ascii')) for i in range(int(ndrives/dlen)) ]
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if len(s) == 2 and s[1] == ":":
|
|
rpm-build |
95f51c |
s += os.sep
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if not os.path.isdir(s):
|
|
rpm-build |
95f51c |
e = OSError('%s is not a directory' % s)
|
|
rpm-build |
95f51c |
e.errno = errno.ENOENT
|
|
rpm-build |
95f51c |
raise e
|
|
rpm-build |
95f51c |
return os.listdir(s)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
listdir = os.listdir
|
|
rpm-build |
95f51c |
if is_win32:
|
|
rpm-build |
95f51c |
listdir = listdir_win32
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def num2ver(ver):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Converts a string, tuple or version number into an integer. The number is supposed to have at most 4 digits::
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
from waflib.Utils import num2ver
|
|
rpm-build |
95f51c |
num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0))
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type ver: string or tuple of numbers
|
|
rpm-build |
95f51c |
:param ver: a version number
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if isinstance(ver, str):
|
|
rpm-build |
95f51c |
ver = tuple(ver.split('.'))
|
|
rpm-build |
95f51c |
if isinstance(ver, tuple):
|
|
rpm-build |
95f51c |
ret = 0
|
|
rpm-build |
95f51c |
for i in range(4):
|
|
rpm-build |
95f51c |
if i < len(ver):
|
|
rpm-build |
95f51c |
ret += 256**(3 - i) * int(ver[i])
|
|
rpm-build |
95f51c |
return ret
|
|
rpm-build |
95f51c |
return ver
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def to_list(val):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Converts a string argument to a list by splitting it by spaces.
|
|
rpm-build |
95f51c |
Returns the object if not a string::
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
from waflib.Utils import to_list
|
|
rpm-build |
95f51c |
lst = to_list('a b c d')
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param val: list of string or space-separated string
|
|
rpm-build |
95f51c |
:rtype: list
|
|
rpm-build |
95f51c |
:return: Argument converted to list
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if isinstance(val, str):
|
|
rpm-build |
95f51c |
return val.split()
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
return val
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def console_encoding():
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
import ctypes
|
|
rpm-build |
95f51c |
except ImportError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
codepage = ctypes.windll.kernel32.GetConsoleCP()
|
|
rpm-build |
95f51c |
except AttributeError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
if codepage:
|
|
rpm-build |
95f51c |
return 'cp%d' % codepage
|
|
rpm-build |
95f51c |
return sys.stdout.encoding or ('cp1252' if is_win32 else 'latin-1')
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def split_path_unix(path):
|
|
rpm-build |
95f51c |
return path.split('/')
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def split_path_cygwin(path):
|
|
rpm-build |
95f51c |
if path.startswith('//'):
|
|
rpm-build |
95f51c |
ret = path.split('/')[2:]
|
|
rpm-build |
95f51c |
ret[0] = '/' + ret[0]
|
|
rpm-build |
95f51c |
return ret
|
|
rpm-build |
95f51c |
return path.split('/')
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
re_sp = re.compile('[/\\\\]+')
|
|
rpm-build |
95f51c |
def split_path_win32(path):
|
|
rpm-build |
95f51c |
if path.startswith('\\\\'):
|
|
rpm-build |
95f51c |
ret = re_sp.split(path)[1:]
|
|
rpm-build |
95f51c |
ret[0] = '\\\\' + ret[0]
|
|
rpm-build |
95f51c |
if ret[0] == '\\\\?':
|
|
rpm-build |
95f51c |
return ret[1:]
|
|
rpm-build |
95f51c |
return ret
|
|
rpm-build |
95f51c |
return re_sp.split(path)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
msysroot = None
|
|
rpm-build |
95f51c |
def split_path_msys(path):
|
|
rpm-build |
95f51c |
if path.startswith(('/', '\\')) and not path.startswith(('//', '\\\\')):
|
|
rpm-build |
95f51c |
# msys paths can be in the form /usr/bin
|
|
rpm-build |
95f51c |
global msysroot
|
|
rpm-build |
95f51c |
if not msysroot:
|
|
rpm-build |
95f51c |
# msys has python 2.7 or 3, so we can use this
|
|
rpm-build |
95f51c |
msysroot = subprocess.check_output(['cygpath', '-w', '/']).decode(sys.stdout.encoding or 'latin-1')
|
|
rpm-build |
95f51c |
msysroot = msysroot.strip()
|
|
rpm-build |
95f51c |
path = os.path.normpath(msysroot + os.sep + path)
|
|
rpm-build |
95f51c |
return split_path_win32(path)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if sys.platform == 'cygwin':
|
|
rpm-build |
95f51c |
split_path = split_path_cygwin
|
|
rpm-build |
95f51c |
elif is_win32:
|
|
rpm-build |
95f51c |
# Consider this an MSYSTEM environment if $MSYSTEM is set and python
|
|
rpm-build |
95f51c |
# reports is executable from a unix like path on a windows host.
|
|
rpm-build |
95f51c |
if os.environ.get('MSYSTEM') and sys.executable.startswith('/'):
|
|
rpm-build |
95f51c |
split_path = split_path_msys
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
split_path = split_path_win32
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
split_path = split_path_unix
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
split_path.__doc__ = """
|
|
rpm-build |
95f51c |
Splits a path by / or \\; do not confuse this function with with ``os.path.split``
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type path: string
|
|
rpm-build |
95f51c |
:param path: path to split
|
|
rpm-build |
95f51c |
:return: list of string
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def check_dir(path):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Ensures that a directory exists (similar to ``mkdir -p``).
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type path: string
|
|
rpm-build |
95f51c |
:param path: Path to directory
|
|
rpm-build |
95f51c |
:raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added.
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if not os.path.isdir(path):
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
os.makedirs(path)
|
|
rpm-build |
95f51c |
except OSError as e:
|
|
rpm-build |
95f51c |
if not os.path.isdir(path):
|
|
rpm-build |
95f51c |
raise Errors.WafError('Cannot create the folder %r' % path, ex=e)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def check_exe(name, env=None):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Ensures that a program exists
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type name: string
|
|
rpm-build |
95f51c |
:param name: path to the program
|
|
rpm-build |
95f51c |
:param env: configuration object
|
|
rpm-build |
95f51c |
:type env: :py:class:`waflib.ConfigSet.ConfigSet`
|
|
rpm-build |
95f51c |
:return: path of the program or None
|
|
rpm-build |
95f51c |
:raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added.
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if not name:
|
|
rpm-build |
95f51c |
raise ValueError('Cannot execute an empty string!')
|
|
rpm-build |
95f51c |
def is_exe(fpath):
|
|
rpm-build |
95f51c |
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
fpath, fname = os.path.split(name)
|
|
rpm-build |
95f51c |
if fpath and is_exe(name):
|
|
rpm-build |
95f51c |
return os.path.abspath(name)
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
env = env or os.environ
|
|
rpm-build |
95f51c |
for path in env['PATH'].split(os.pathsep):
|
|
rpm-build |
95f51c |
path = path.strip('"')
|
|
rpm-build |
95f51c |
exe_file = os.path.join(path, name)
|
|
rpm-build |
95f51c |
if is_exe(exe_file):
|
|
rpm-build |
95f51c |
return os.path.abspath(exe_file)
|
|
rpm-build |
95f51c |
return None
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def def_attrs(cls, **kw):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Sets default attributes on a class instance
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type cls: class
|
|
rpm-build |
95f51c |
:param cls: the class to update the given attributes in.
|
|
rpm-build |
95f51c |
:type kw: dict
|
|
rpm-build |
95f51c |
:param kw: dictionary of attributes names and values.
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
for k, v in kw.items():
|
|
rpm-build |
95f51c |
if not hasattr(cls, k):
|
|
rpm-build |
95f51c |
setattr(cls, k, v)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def quote_define_name(s):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Converts a string into an identifier suitable for C defines.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type s: string
|
|
rpm-build |
95f51c |
:param s: String to convert
|
|
rpm-build |
95f51c |
:rtype: string
|
|
rpm-build |
95f51c |
:return: Identifier suitable for C defines
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
fu = re.sub('[^a-zA-Z0-9]', '_', s)
|
|
rpm-build |
95f51c |
fu = re.sub('_+', '_', fu)
|
|
rpm-build |
95f51c |
fu = fu.upper()
|
|
rpm-build |
95f51c |
return fu
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
re_sh = re.compile('\\s|\'|"')
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Regexp used for shell_escape below
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def shell_escape(cmd):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Escapes a command:
|
|
rpm-build |
95f51c |
['ls', '-l', 'arg space'] -> ls -l 'arg space'
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if isinstance(cmd, str):
|
|
rpm-build |
95f51c |
return cmd
|
|
rpm-build |
95f51c |
return ' '.join(repr(x) if re_sh.search(x) else x for x in cmd)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def h_list(lst):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Hashes lists of ordered data.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
Using hash(tup) for tuples would be much more efficient,
|
|
rpm-build |
95f51c |
but Python now enforces hash randomization
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param lst: list to hash
|
|
rpm-build |
95f51c |
:type lst: list of strings
|
|
rpm-build |
95f51c |
:return: hash of the list
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
return md5(repr(lst).encode()).digest()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if sys.hexversion < 0x3000000:
|
|
rpm-build |
95f51c |
def h_list_python2(lst):
|
|
rpm-build |
95f51c |
return md5(repr(lst)).digest()
|
|
rpm-build |
95f51c |
h_list_python2.__doc__ = h_list.__doc__
|
|
rpm-build |
95f51c |
h_list = h_list_python2
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def h_fun(fun):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Hash functions
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param fun: function to hash
|
|
rpm-build |
95f51c |
:type fun: function
|
|
rpm-build |
95f51c |
:return: hash of the function
|
|
rpm-build |
95f51c |
:rtype: string or bytes
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
return fun.code
|
|
rpm-build |
95f51c |
except AttributeError:
|
|
rpm-build |
95f51c |
if isinstance(fun, functools.partial):
|
|
rpm-build |
95f51c |
code = list(fun.args)
|
|
rpm-build |
95f51c |
# The method items() provides a sequence of tuples where the first element
|
|
rpm-build |
95f51c |
# represents an optional argument of the partial function application
|
|
rpm-build |
95f51c |
#
|
|
rpm-build |
95f51c |
# The sorting result outcome will be consistent because:
|
|
rpm-build |
95f51c |
# 1. tuples are compared in order of their elements
|
|
rpm-build |
95f51c |
# 2. optional argument namess are unique
|
|
rpm-build |
95f51c |
code.extend(sorted(fun.keywords.items()))
|
|
rpm-build |
95f51c |
code.append(h_fun(fun.func))
|
|
rpm-build |
95f51c |
fun.code = h_list(code)
|
|
rpm-build |
95f51c |
return fun.code
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
h = inspect.getsource(fun)
|
|
rpm-build |
95f51c |
except EnvironmentError:
|
|
rpm-build |
95f51c |
h = 'nocode'
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
fun.code = h
|
|
rpm-build |
95f51c |
except AttributeError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
return h
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def h_cmd(ins):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Hashes objects recursively
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param ins: input object
|
|
rpm-build |
95f51c |
:type ins: string or list or tuple or function
|
|
rpm-build |
95f51c |
:rtype: string or bytes
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
# this function is not meant to be particularly fast
|
|
rpm-build |
95f51c |
if isinstance(ins, str):
|
|
rpm-build |
95f51c |
# a command is either a string
|
|
rpm-build |
95f51c |
ret = ins
|
|
rpm-build |
95f51c |
elif isinstance(ins, list) or isinstance(ins, tuple):
|
|
rpm-build |
95f51c |
# or a list of functions/strings
|
|
rpm-build |
95f51c |
ret = str([h_cmd(x) for x in ins])
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
# or just a python function
|
|
rpm-build |
95f51c |
ret = str(h_fun(ins))
|
|
rpm-build |
95f51c |
if sys.hexversion > 0x3000000:
|
|
rpm-build |
95f51c |
ret = ret.encode('latin-1', 'xmlcharrefreplace')
|
|
rpm-build |
95f51c |
return ret
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")
|
|
rpm-build |
95f51c |
def subst_vars(expr, params):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Replaces ${VAR} with the value of VAR taken from a dict or a config set::
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
from waflib import Utils
|
|
rpm-build |
95f51c |
s = Utils.subst_vars('${PREFIX}/bin', env)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type expr: string
|
|
rpm-build |
95f51c |
:param expr: String to perform substitution on
|
|
rpm-build |
95f51c |
:param params: Dictionary or config set to look up variable values.
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
def repl_var(m):
|
|
rpm-build |
95f51c |
if m.group(1):
|
|
rpm-build |
95f51c |
return '\\'
|
|
rpm-build |
95f51c |
if m.group(2):
|
|
rpm-build |
95f51c |
return '$'
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
# ConfigSet instances may contain lists
|
|
rpm-build |
95f51c |
return params.get_flat(m.group(3))
|
|
rpm-build |
95f51c |
except AttributeError:
|
|
rpm-build |
95f51c |
return params[m.group(3)]
|
|
rpm-build |
95f51c |
# if you get a TypeError, it means that 'expr' is not a string...
|
|
rpm-build |
95f51c |
# Utils.subst_vars(None, env) will not work
|
|
rpm-build |
95f51c |
return reg_subst.sub(repl_var, expr)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def destos_to_binfmt(key):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Returns the binary format based on the unversioned platform name,
|
|
rpm-build |
95f51c |
and defaults to ``elf`` if nothing is found.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param key: platform name
|
|
rpm-build |
95f51c |
:type key: string
|
|
rpm-build |
95f51c |
:return: string representing the binary format
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if key == 'darwin':
|
|
rpm-build |
95f51c |
return 'mac-o'
|
|
rpm-build |
95f51c |
elif key in ('win32', 'cygwin', 'uwin', 'msys'):
|
|
rpm-build |
95f51c |
return 'pe'
|
|
rpm-build |
95f51c |
return 'elf'
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def unversioned_sys_platform():
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Returns the unversioned platform name.
|
|
rpm-build |
95f51c |
Some Python platform names contain versions, that depend on
|
|
rpm-build |
95f51c |
the build environment, e.g. linux2, freebsd6, etc.
|
|
rpm-build |
95f51c |
This returns the name without the version number. Exceptions are
|
|
rpm-build |
95f51c |
os2 and win32, which are returned verbatim.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:rtype: string
|
|
rpm-build |
95f51c |
:return: Unversioned platform name
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
s = sys.platform
|
|
rpm-build |
95f51c |
if s.startswith('java'):
|
|
rpm-build |
95f51c |
# The real OS is hidden under the JVM.
|
|
rpm-build |
95f51c |
from java.lang import System
|
|
rpm-build |
95f51c |
s = System.getProperty('os.name')
|
|
rpm-build |
95f51c |
# see http://lopica.sourceforge.net/os.html for a list of possible values
|
|
rpm-build |
95f51c |
if s == 'Mac OS X':
|
|
rpm-build |
95f51c |
return 'darwin'
|
|
rpm-build |
95f51c |
elif s.startswith('Windows '):
|
|
rpm-build |
95f51c |
return 'win32'
|
|
rpm-build |
95f51c |
elif s == 'OS/2':
|
|
rpm-build |
95f51c |
return 'os2'
|
|
rpm-build |
95f51c |
elif s == 'HP-UX':
|
|
rpm-build |
95f51c |
return 'hp-ux'
|
|
rpm-build |
95f51c |
elif s in ('SunOS', 'Solaris'):
|
|
rpm-build |
95f51c |
return 'sunos'
|
|
rpm-build |
95f51c |
else: s = s.lower()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
# powerpc == darwin for our purposes
|
|
rpm-build |
95f51c |
if s == 'powerpc':
|
|
rpm-build |
95f51c |
return 'darwin'
|
|
rpm-build |
95f51c |
if s == 'win32' or s == 'os2':
|
|
rpm-build |
95f51c |
return s
|
|
rpm-build |
95f51c |
if s == 'cli' and os.name == 'nt':
|
|
rpm-build |
95f51c |
# ironpython is only on windows as far as we know
|
|
rpm-build |
95f51c |
return 'win32'
|
|
rpm-build |
95f51c |
return re.split(r'\d+$', s)[0]
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def nada(*k, **kw):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Does nothing
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:return: None
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
class Timer(object):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Simple object for timing the execution of commands.
|
|
rpm-build |
95f51c |
Its string representation is the duration::
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
from waflib.Utils import Timer
|
|
rpm-build |
95f51c |
timer = Timer()
|
|
rpm-build |
95f51c |
a_few_operations()
|
|
rpm-build |
95f51c |
s = str(timer)
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
def __init__(self):
|
|
rpm-build |
95f51c |
self.start_time = self.now()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def __str__(self):
|
|
rpm-build |
95f51c |
delta = self.now() - self.start_time
|
|
rpm-build |
95f51c |
if not isinstance(delta, datetime.timedelta):
|
|
rpm-build |
95f51c |
delta = datetime.timedelta(seconds=delta)
|
|
rpm-build |
95f51c |
days = delta.days
|
|
rpm-build |
95f51c |
hours, rem = divmod(delta.seconds, 3600)
|
|
rpm-build |
95f51c |
minutes, seconds = divmod(rem, 60)
|
|
rpm-build |
95f51c |
seconds += delta.microseconds * 1e-6
|
|
rpm-build |
95f51c |
result = ''
|
|
rpm-build |
95f51c |
if days:
|
|
rpm-build |
95f51c |
result += '%dd' % days
|
|
rpm-build |
95f51c |
if days or hours:
|
|
rpm-build |
95f51c |
result += '%dh' % hours
|
|
rpm-build |
95f51c |
if days or hours or minutes:
|
|
rpm-build |
95f51c |
result += '%dm' % minutes
|
|
rpm-build |
95f51c |
return '%s%.3fs' % (result, seconds)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def now(self):
|
|
rpm-build |
95f51c |
return datetime.datetime.utcnow()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if hasattr(time, 'perf_counter'):
|
|
rpm-build |
95f51c |
def now(self):
|
|
rpm-build |
95f51c |
return time.perf_counter()
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def read_la_file(path):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Reads property files, used by msvc.py
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param path: file to read
|
|
rpm-build |
95f51c |
:type path: string
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
sp = re.compile(r'^([^=]+)=\'(.*)\'$')
|
|
rpm-build |
95f51c |
dc = {}
|
|
rpm-build |
95f51c |
for line in readf(path).splitlines():
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
_, left, right, _ = sp.split(line.strip())
|
|
rpm-build |
95f51c |
dc[left] = right
|
|
rpm-build |
95f51c |
except ValueError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
return dc
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def run_once(fun):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Decorator: let a function cache its results, use like this::
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
@run_once
|
|
rpm-build |
95f51c |
def foo(k):
|
|
rpm-build |
95f51c |
return 345*2343
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
.. note:: in practice this can cause memory leaks, prefer a :py:class:`waflib.Utils.lru_cache`
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param fun: function to execute
|
|
rpm-build |
95f51c |
:type fun: function
|
|
rpm-build |
95f51c |
:return: the return value of the function executed
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
cache = {}
|
|
rpm-build |
95f51c |
def wrap(*k):
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
return cache[k]
|
|
rpm-build |
95f51c |
except KeyError:
|
|
rpm-build |
95f51c |
ret = fun(*k)
|
|
rpm-build |
95f51c |
cache[k] = ret
|
|
rpm-build |
95f51c |
return ret
|
|
rpm-build |
95f51c |
wrap.__cache__ = cache
|
|
rpm-build |
95f51c |
wrap.__name__ = fun.__name__
|
|
rpm-build |
95f51c |
return wrap
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def get_registry_app_path(key, filename):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Returns the value of a registry key for an executable
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:type key: string
|
|
rpm-build |
95f51c |
:type filename: list of string
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if not winreg:
|
|
rpm-build |
95f51c |
return None
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
result = winreg.QueryValue(key, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s.exe" % filename[0])
|
|
rpm-build |
95f51c |
except OSError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
if os.path.isfile(result):
|
|
rpm-build |
95f51c |
return result
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def lib64():
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Guess the default ``/usr/lib`` extension for 64-bit applications
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:return: '64' or ''
|
|
rpm-build |
95f51c |
:rtype: string
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
# default settings for /usr/lib
|
|
rpm-build |
95f51c |
if os.sep == '/':
|
|
rpm-build |
95f51c |
if platform.architecture()[0] == '64bit':
|
|
rpm-build |
95f51c |
if os.path.exists('/usr/lib64') and not os.path.exists('/usr/lib32'):
|
|
rpm-build |
95f51c |
return '64'
|
|
rpm-build |
95f51c |
return ''
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def sane_path(p):
|
|
rpm-build |
95f51c |
# private function for the time being!
|
|
rpm-build |
95f51c |
return os.path.abspath(os.path.expanduser(p))
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
process_pool = []
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
List of processes started to execute sub-process commands
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def get_process():
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Returns a process object that can execute commands as sub-processes
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:rtype: subprocess.Popen
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
return process_pool.pop()
|
|
rpm-build |
95f51c |
except IndexError:
|
|
rpm-build |
95f51c |
filepath = os.path.dirname(os.path.abspath(__file__)) + os.sep + 'processor.py'
|
|
rpm-build |
95f51c |
cmd = [sys.executable, '-c', readf(filepath)]
|
|
rpm-build |
95f51c |
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0, close_fds=not is_win32)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def run_prefork_process(cmd, kwargs, cargs):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Delegates process execution to a pre-forked process instance.
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if not 'env' in kwargs:
|
|
rpm-build |
95f51c |
kwargs['env'] = dict(os.environ)
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
obj = base64.b64encode(cPickle.dumps([cmd, kwargs, cargs]))
|
|
rpm-build |
95f51c |
except (TypeError, AttributeError):
|
|
rpm-build |
95f51c |
return run_regular_process(cmd, kwargs, cargs)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
proc = get_process()
|
|
rpm-build |
95f51c |
if not proc:
|
|
rpm-build |
95f51c |
return run_regular_process(cmd, kwargs, cargs)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
proc.stdin.write(obj)
|
|
rpm-build |
95f51c |
proc.stdin.write('\n'.encode())
|
|
rpm-build |
95f51c |
proc.stdin.flush()
|
|
rpm-build |
95f51c |
obj = proc.stdout.readline()
|
|
rpm-build |
95f51c |
if not obj:
|
|
rpm-build |
95f51c |
raise OSError('Preforked sub-process %r died' % proc.pid)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
process_pool.append(proc)
|
|
rpm-build |
95f51c |
lst = cPickle.loads(base64.b64decode(obj))
|
|
rpm-build |
95f51c |
# Jython wrapper failures (bash/execvp)
|
|
rpm-build |
95f51c |
assert len(lst) == 5
|
|
rpm-build |
95f51c |
ret, out, err, ex, trace = lst
|
|
rpm-build |
95f51c |
if ex:
|
|
rpm-build |
95f51c |
if ex == 'OSError':
|
|
rpm-build |
95f51c |
raise OSError(trace)
|
|
rpm-build |
95f51c |
elif ex == 'ValueError':
|
|
rpm-build |
95f51c |
raise ValueError(trace)
|
|
rpm-build |
95f51c |
elif ex == 'TimeoutExpired':
|
|
rpm-build |
95f51c |
exc = TimeoutExpired(cmd, timeout=cargs['timeout'], output=out)
|
|
rpm-build |
95f51c |
exc.stderr = err
|
|
rpm-build |
95f51c |
raise exc
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
raise Exception(trace)
|
|
rpm-build |
95f51c |
return ret, out, err
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def lchown(path, user=-1, group=-1):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Change the owner/group of a path, raises an OSError if the
|
|
rpm-build |
95f51c |
ownership change fails.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param user: user to change
|
|
rpm-build |
95f51c |
:type user: int or str
|
|
rpm-build |
95f51c |
:param group: group to change
|
|
rpm-build |
95f51c |
:type group: int or str
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if isinstance(user, str):
|
|
rpm-build |
95f51c |
import pwd
|
|
rpm-build |
95f51c |
entry = pwd.getpwnam(user)
|
|
rpm-build |
95f51c |
if not entry:
|
|
rpm-build |
95f51c |
raise OSError('Unknown user %r' % user)
|
|
rpm-build |
95f51c |
user = entry[2]
|
|
rpm-build |
95f51c |
if isinstance(group, str):
|
|
rpm-build |
95f51c |
import grp
|
|
rpm-build |
95f51c |
entry = grp.getgrnam(group)
|
|
rpm-build |
95f51c |
if not entry:
|
|
rpm-build |
95f51c |
raise OSError('Unknown group %r' % group)
|
|
rpm-build |
95f51c |
group = entry[2]
|
|
rpm-build |
95f51c |
return os.lchown(path, user, group)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def run_regular_process(cmd, kwargs, cargs={}):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Executes a subprocess command by using subprocess.Popen
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
proc = subprocess.Popen(cmd, **kwargs)
|
|
rpm-build |
95f51c |
if kwargs.get('stdout') or kwargs.get('stderr'):
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
out, err = proc.communicate(**cargs)
|
|
rpm-build |
95f51c |
except TimeoutExpired:
|
|
rpm-build |
95f51c |
if kwargs.get('start_new_session') and hasattr(os, 'killpg'):
|
|
rpm-build |
95f51c |
os.killpg(proc.pid, signal.SIGKILL)
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
proc.kill()
|
|
rpm-build |
95f51c |
out, err = proc.communicate()
|
|
rpm-build |
95f51c |
exc = TimeoutExpired(proc.args, timeout=cargs['timeout'], output=out)
|
|
rpm-build |
95f51c |
exc.stderr = err
|
|
rpm-build |
95f51c |
raise exc
|
|
rpm-build |
95f51c |
status = proc.returncode
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
out, err = (None, None)
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
status = proc.wait(**cargs)
|
|
rpm-build |
95f51c |
except TimeoutExpired as e:
|
|
rpm-build |
95f51c |
if kwargs.get('start_new_session') and hasattr(os, 'killpg'):
|
|
rpm-build |
95f51c |
os.killpg(proc.pid, signal.SIGKILL)
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
proc.kill()
|
|
rpm-build |
95f51c |
proc.wait()
|
|
rpm-build |
95f51c |
raise e
|
|
rpm-build |
95f51c |
return status, out, err
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def run_process(cmd, kwargs, cargs={}):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Executes a subprocess by using a pre-forked process when possible
|
|
rpm-build |
95f51c |
or falling back to subprocess.Popen. See :py:func:`waflib.Utils.run_prefork_process`
|
|
rpm-build |
95f51c |
and :py:func:`waflib.Utils.run_regular_process`
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
if kwargs.get('stdout') and kwargs.get('stderr'):
|
|
rpm-build |
95f51c |
return run_prefork_process(cmd, kwargs, cargs)
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
return run_regular_process(cmd, kwargs, cargs)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def alloc_process_pool(n, force=False):
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
Allocates an amount of processes to the default pool so its size is at least *n*.
|
|
rpm-build |
95f51c |
It is useful to call this function early so that the pre-forked
|
|
rpm-build |
95f51c |
processes use as little memory as possible.
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
:param n: pool size
|
|
rpm-build |
95f51c |
:type n: integer
|
|
rpm-build |
95f51c |
:param force: if True then *n* more processes are added to the existing pool
|
|
rpm-build |
95f51c |
:type force: bool
|
|
rpm-build |
95f51c |
"""
|
|
rpm-build |
95f51c |
# mandatory on python2, unnecessary on python >= 3.2
|
|
rpm-build |
95f51c |
global run_process, get_process, alloc_process_pool
|
|
rpm-build |
95f51c |
if not force:
|
|
rpm-build |
95f51c |
n = max(n - len(process_pool), 0)
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
lst = [get_process() for x in range(n)]
|
|
rpm-build |
95f51c |
except OSError:
|
|
rpm-build |
95f51c |
run_process = run_regular_process
|
|
rpm-build |
95f51c |
get_process = alloc_process_pool = nada
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
for x in lst:
|
|
rpm-build |
95f51c |
process_pool.append(x)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
def atexit_pool():
|
|
rpm-build |
95f51c |
for k in process_pool:
|
|
rpm-build |
95f51c |
try:
|
|
rpm-build |
95f51c |
os.kill(k.pid, 9)
|
|
rpm-build |
95f51c |
except OSError:
|
|
rpm-build |
95f51c |
pass
|
|
rpm-build |
95f51c |
else:
|
|
rpm-build |
95f51c |
k.wait()
|
|
rpm-build |
95f51c |
# see #1889
|
|
rpm-build |
95f51c |
if (sys.hexversion<0x207000f and not is_win32) or sys.hexversion>=0x306000f:
|
|
rpm-build |
95f51c |
atexit.register(atexit_pool)
|
|
rpm-build |
95f51c |
|
|
rpm-build |
95f51c |
if os.environ.get('WAF_NO_PREFORK') or sys.platform == 'cli' or not sys.executable:
|
|
rpm-build |
95f51c |
run_process = run_regular_process
|
|
rpm-build |
95f51c |
get_process = alloc_process_pool = nada
|
|
rpm-build |
95f51c |
|