Back to index

enigmail  1.4.3
utils.py
Go to the documentation of this file.
00001 # ***** BEGIN LICENSE BLOCK *****
00002 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003 #
00004 # The contents of this file are subject to the Mozilla Public License Version
00005 # 1.1 (the "License"); you may not use this file except in compliance with
00006 # the License. You may obtain a copy of the License at
00007 # http://www.mozilla.org/MPL/
00008 #
00009 # Software distributed under the License is distributed on an "AS IS" basis,
00010 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011 # for the specific language governing rights and limitations under the
00012 # License.
00013 #
00014 # The Original Code is Mozilla build system.
00015 #
00016 # The Initial Developer of the Original Code is
00017 # Mozilla Foundation.
00018 # Portions created by the Initial Developer are Copyright (C) 2008
00019 # the Initial Developer. All Rights Reserved.
00020 #
00021 # Contributor(s):
00022 #  Axel Hecht <axel@pike.org>
00023 #
00024 # Alternatively, the contents of this file may be used under the terms of
00025 # either the GNU General Public License Version 2 or later (the "GPL"), or
00026 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027 # in which case the provisions of the GPL or the LGPL are applicable instead
00028 # of those above. If you wish to allow use of your version of this file only
00029 # under the terms of either the GPL or the LGPL, and not to allow others to
00030 # use your version of this file under the terms of the MPL, indicate your
00031 # decision by deleting the provisions above and replace them with the notice
00032 # and other provisions required by the GPL or the LGPL. If you do not delete
00033 # the provisions above, a recipient may use your version of this file under
00034 # the terms of any one of the MPL, the GPL or the LGPL.
00035 #
00036 # ***** END LICENSE BLOCK *****
00037 
00038 '''Utility methods to be used by python build infrastructure.
00039 '''
00040 
00041 import os
00042 import errno
00043 import sys
00044 import time
00045 import stat
00046 
00047 class LockFile(object):
00048   '''LockFile is used by the lockFile method to hold the lock.
00049 
00050   This object should not be used directly, but only through
00051   the lockFile method below.
00052   '''
00053   def __init__(self, lockfile):
00054     self.lockfile = lockfile
00055   def __del__(self):
00056     while True:
00057       try:
00058         os.remove(self.lockfile)
00059         break
00060       except OSError, e:
00061         if e.errno == errno.EACCES:
00062           # another process probably has the file open, we'll retry.
00063           # just a short sleep since we want to drop the lock ASAP
00064           # (but we need to let some other process close the file first)
00065           time.sleep(0.1)
00066         else:
00067           # re-raise unknown errors
00068           raise
00069 
00070 def lockFile(lockfile, max_wait = 600):
00071   '''Create and hold a lockfile of the given name, with the given timeout.
00072 
00073   To release the lock, delete the returned object.
00074   '''
00075   while True:
00076     try:
00077       fd = os.open(lockfile, os.O_EXCL | os.O_RDWR | os.O_CREAT)
00078       # we created the lockfile, so we're the owner
00079       break
00080     except OSError, e:
00081       if e.errno == errno.EEXIST or \
00082          (sys.platform == "win32" and e.errno == errno.EACCES):
00083         pass
00084       else:
00085         # should not occur
00086         raise
00087   
00088     try:
00089       # the lock file exists, try to stat it to get its age
00090       # and read its contents to report the owner PID
00091       f = open(lockfile, "r")
00092       s = os.stat(lockfile)
00093     except EnvironmentError, e:
00094       if e.errno == errno.ENOENT or e.errno == errno.EACCES:
00095         # we didn't create the lockfile, so it did exist, but it's
00096         # gone now. Just try again
00097         continue
00098       sys.exit("%s exists but stat() failed: %s" %
00099                (lockfile, e.strerror))
00100   
00101     # we didn't create the lockfile and it's still there, check
00102     # its age
00103     now = int(time.time())
00104     if now - s[stat.ST_MTIME] > max_wait:
00105       pid = f.readline().rstrip()
00106       sys.exit("%s has been locked for more than " \
00107                "%d seconds (PID %s)" % (lockfile, max_wait,
00108                                         pid))
00109   
00110     # it's not been locked too long, wait a while and retry
00111     f.close()
00112     time.sleep(1)
00113   
00114   # if we get here. we have the lockfile. Convert the os.open file
00115   # descriptor into a Python file object and record our PID in it
00116   
00117   f = os.fdopen(fd, "w")
00118   f.write("%d\n" % os.getpid())
00119   f.close()
00120   return LockFile(lockfile)
00121 
00122 class pushback_iter(object):
00123   '''Utility iterator that can deal with pushed back elements.
00124 
00125   This behaves like a regular iterable, just that you can call
00126     iter.pushback(item)
00127   to get the givem item as next item in the iteration.
00128   '''
00129   def __init__(self, iterable):
00130     self.it = iter(iterable)
00131     self.pushed_back = []
00132 
00133   def __iter__(self):
00134     return self
00135 
00136   def __nonzero__(self):
00137     if self.pushed_back:
00138       return True
00139 
00140     try:
00141       self.pushed_back.insert(0, self.it.next())
00142     except StopIteration:
00143       return False
00144     else:
00145       return True
00146 
00147   def next(self):
00148     if self.pushed_back:
00149       return self.pushed_back.pop()
00150     return self.it.next()
00151 
00152   def pushback(self, item):
00153     self.pushed_back.append(item)