1 # ***** BEGIN LICENSE BLOCK *****
2 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 # The contents of this file are subject to the Mozilla Public License Version
5 # 1.1 (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 # http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS IS" basis,
10 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 # for the specific language governing rights and limitations under the
14 # The Original Code is Mozilla build system.
16 # The Initial Developer of the Original Code is
18 # Portions created by the Initial Developer are Copyright (C) 2008
19 # the Initial Developer. All Rights Reserved.
22 # Axel Hecht <axel@pike.org>
24 # Alternatively, the contents of this file may be used under the terms of
25 # either the GNU General Public License Version 2 or later (the "GPL"), or
26 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 # in which case the provisions of the GPL or the LGPL are applicable instead
28 # of those above. If you wish to allow use of your version of this file only
29 # under the terms of either the GPL or the LGPL, and not to allow others to
30 # use your version of this file under the terms of the MPL, indicate your
31 # decision by deleting the provisions above and replace them with the notice
32 # and other provisions required by the GPL or the LGPL. If you do not delete
33 # the provisions above, a recipient may use your version of this file under
34 # the terms of any one of the MPL, the GPL or the LGPL.
36 # ***** END LICENSE BLOCK *****
38 '''Utility methods to be used by python build infrastructure.
47 class LockFile(object):
48 '''LockFile is used by the lockFile method to hold the lock.
50 This object should not be used directly, but only through
51 the lockFile method below.
53 def __init__(self
, lockfile
):
54 self
.lockfile
= lockfile
58 os
.remove(self
.lockfile
)
61 if e
.errno
== errno
.EACCES
:
62 # another process probably has the file open, we'll retry.
63 # just a short sleep since we want to drop the lock ASAP
64 # (but we need to let some other process close the file first)
67 # re-raise unknown errors
70 def lockFile(lockfile
, max_wait
= 600):
71 '''Create and hold a lockfile of the given name, with the given timeout.
73 To release the lock, delete the returned object.
77 fd
= os
.open(lockfile
, os
.O_EXCL | os
.O_RDWR | os
.O_CREAT
)
78 # we created the lockfile, so we're the owner
81 if e
.errno
== errno
.EEXIST
or \
82 (sys
.platform
== "win32" and e
.errno
== errno
.EACCES
):
89 # the lock file exists, try to stat it to get its age
90 # and read its contents to report the owner PID
91 f
= open(lockfile
, "r")
93 except EnvironmentError, e
:
94 if e
.errno
== errno
.ENOENT
or \
95 (sys
.platform
== "win32" and e
.errno
== errno
.EACCES
):
96 # we didn't create the lockfile, so it did exist, but it's
97 # gone now. Just try again
99 sys
.exit("%s exists but stat() failed: %s" %
100 (lockfile
, e
.strerror
))
102 # we didn't create the lockfile and it's still there, check
104 now
= int(time
.time())
105 if now
- s
[stat
.ST_MTIME
] > max_wait
:
106 pid
= f
.readline().rstrip()
107 sys
.exit("%s has been locked for more than " \
108 "%d seconds (PID %s)" % (lockfile
, max_wait
,
111 # it's not been locked too long, wait a while and retry
115 # if we get here. we have the lockfile. Convert the os.open file
116 # descriptor into a Python file object and record our PID in it
118 f
= os
.fdopen(fd
, "w")
119 f
.write("%d\n" % os
.getpid())
121 return LockFile(lockfile
)
123 class pushback_iter(object):
124 '''Utility iterator that can deal with pushed back elements.
126 This behaves like a regular iterable, just that you can call
128 to get the givem item as next item in the iteration.
130 def __init__(self
, iterable
):
131 self
.it
= iter(iterable
)
132 self
.pushed_back
= []
137 def __nonzero__(self
):
142 self
.pushed_back
.insert(0, self
.it
.next())
143 except StopIteration:
150 return self
.pushed_back
.pop()
151 return self
.it
.next()
153 def pushback(self
, item
):
154 self
.pushed_back
.append(item
)