Bug 849918 - Initial support for PannerNode's 3D positional audio (equalpower panning...
[gecko.git] / config / utils.py
blob57a03c66e8aad6b511f3efa6998f7330d7496ffd
1 # >>sys.stderr, This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 '''Utility methods to be used by python build infrastructure.
6 '''
8 import os
9 import errno
10 import sys
11 import time
12 import stat
14 class LockFile(object):
15 '''LockFile is used by the lockFile method to hold the lock.
17 This object should not be used directly, but only through
18 the lockFile method below.
19 '''
20 def __init__(self, lockfile):
21 self.lockfile = lockfile
22 def __del__(self):
23 while True:
24 try:
25 os.remove(self.lockfile)
26 break
27 except OSError as e:
28 if e.errno == errno.EACCES:
29 # another process probably has the file open, we'll retry.
30 # just a short sleep since we want to drop the lock ASAP
31 # (but we need to let some other process close the file first)
32 time.sleep(0.1)
33 else:
34 # re-raise unknown errors
35 raise
37 def lockFile(lockfile, max_wait = 600):
38 '''Create and hold a lockfile of the given name, with the given timeout.
40 To release the lock, delete the returned object.
41 '''
42 while True:
43 try:
44 fd = os.open(lockfile, os.O_EXCL | os.O_RDWR | os.O_CREAT)
45 # we created the lockfile, so we're the owner
46 break
47 except OSError as e:
48 if (e.errno == errno.EEXIST or
49 (sys.platform == "win32" and e.errno == errno.EACCES)):
50 pass
51 else:
52 # should not occur
53 raise
55 try:
56 # the lock file exists, try to stat it to get its age
57 # and read its contents to report the owner PID
58 f = open(lockfile, "r")
59 s = os.stat(lockfile)
60 except EnvironmentError as e:
61 if e.errno == errno.ENOENT or e.errno == errno.EACCES:
62 # we didn't create the lockfile, so it did exist, but it's
63 # gone now. Just try again
64 continue
65 sys.exit("{0} exists but stat() failed: {1}"
66 .format(lockfile, e.strerror))
68 # we didn't create the lockfile and it's still there, check
69 # its age
70 now = int(time.time())
71 if now - s[stat.ST_MTIME] > max_wait:
72 pid = f.readline().rstrip()
73 sys.exit("{0} has been locked for more than "
74 "{1} seconds (PID {2})".format(lockfile, max_wait, pid))
76 # it's not been locked too long, wait a while and retry
77 f.close()
78 time.sleep(1)
80 # if we get here. we have the lockfile. Convert the os.open file
81 # descriptor into a Python file object and record our PID in it
83 f = os.fdopen(fd, "w")
84 f.write("{0}\n".format(os.getpid()))
85 f.close()
86 return LockFile(lockfile)
88 class pushback_iter(object):
89 '''Utility iterator that can deal with pushed back elements.
91 This behaves like a regular iterable, just that you can call
92 iter.pushback(item)
93 to get the given item as next item in the iteration.
94 '''
95 def __init__(self, iterable):
96 self.it = iter(iterable)
97 self.pushed_back = []
99 def __iter__(self):
100 return self
102 def __nonzero__(self):
103 if self.pushed_back:
104 return True
106 try:
107 self.pushed_back.insert(0, self.it.next())
108 except StopIteration:
109 return False
110 else:
111 return True
113 def next(self):
114 if self.pushed_back:
115 return self.pushed_back.pop()
116 return self.it.next()
118 def pushback(self, item):
119 self.pushed_back.append(item)