Package omero :: Package util :: Module temp_files
[hide private]
[frames] | no frames]

Source Code for Module omero.util.temp_files

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright 2009 Glencoe Software, Inc.  All Rights Reserved. 
  4  # Use is subject to license terms supplied in LICENSE.txt 
  5  # 
  6  """ 
  7  OMERO Support for temporary files and directories 
  8  """ 
  9   
 10  import os 
 11  import sys 
 12  import atexit 
 13  import getpass 
 14  import logging 
 15  import tempfile 
 16  import threading 
 17  import traceback 
 18  import exceptions 
 19  import portalocker 
 20   
 21  from path import path 
 22   
 23  # TODO: 
 24  #  - locking for command-line cleanup 
 25  #  - plugin for cleaning unlocked files 
 26  #  - plugin for counting sizes, etc. 
 27  #  - decorator 
 28   
29 -class TempFileManager(object):
30 """ 31 Creates temporary files and folders and makes a best effort 32 to remove them on exit (or sooner). Typically only a single 33 instance of this class will exist ("manager" variable in this 34 module below) 35 """ 36
37 - def __init__(self, prefix = "omero"):
38 """ 39 Initializes a TempFileManager instance with a userDir containing 40 the given prefix value, or "omero" by default. Also registers 41 an atexit callback to call self.cleanup() on exit. 42 """ 43 self.logger = logging.getLogger("omero.util.TempFileManager") 44 self.is_win32 = ( sys.platform == "win32" ) 45 self.prefix = prefix 46 47 self.userdir = self.tmpdir() / ("%s_%s" % (self.prefix, self.username())) 48 """ 49 User-accessible directory of the form $TMPDIR/omero_$USERNAME. 50 If the given directory is not writable, an attempt is made 51 to use an alternative 52 """ 53 if not self.create(self.userdir) and not self.access(self.userdir): 54 i = 0 55 while i < 10: 56 t = path("%s_%s" % (self.userdir, i)) 57 if self.create(t) or self.access(t): 58 self.userdir = t 59 break 60 raise exceptions.Exception("Failed to create temporary directory: %s" % self.userdir) 61 self.dir = self.userdir / self.pid() 62 """ 63 Directory under which all temporary files and folders will be created. 64 An attempt to remove a path not in this directory will lead to an 65 exception. 66 """ 67 68 # Now create the directory. If a later step throws an 69 # exception, we should try to rollback this change. 70 if not self.dir.exists(): 71 self.dir.makedirs() 72 self.logger.debug("Using temp dir: %s" % self.dir) 73 74 self.lock = None 75 try: 76 self.lock = open(str(self.dir / ".lock"), "a+") 77 """ 78 .lock file under self.dir which is used to prevent other 79 TempFileManager instances (also in other languages) from 80 cleaning up this directory. 81 """ 82 try: 83 portalocker.lock(self.lock, portalocker.LOCK_EX|portalocker.LOCK_NB) 84 atexit.register(self.cleanup) 85 except: 86 lock = self.lock 87 self.lock = None 88 if lock: 89 self.lock.close() 90 raise 91 finally: 92 try: 93 if not self.lock: 94 self.cleanup() 95 except: 96 self.logger.warn("Error on cleanup after error", exc_info = True)
97
98 - def cleanup(self):
99 """ 100 Releases self.lock and deletes self.dir. 101 The lock is released first since on some platforms like Windows 102 the lock file cannot be deleted even by the owner of the lock. 103 """ 104 try: 105 if self.lock: 106 self.lock.close() # Allow others access 107 except: 108 self.logger.error("Failed to release lock", exc_info = True) 109 self.clean_tempdir()
110
111 - def tmpdir(self):
112 """ 113 Returns a platform-specific user-writable temporary directory 114 """ 115 try: 116 from win32com.shell import shellcon, shell 117 homedir = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0) 118 except ImportError: 119 homedir = os.path.expanduser("~") 120 return path(homedir) / "omero" / "tmp"
121
122 - def username(self):
123 """ 124 Returns the current OS-user's name 125 """ 126 try: 127 return getpass.getuser() # Uses environment variable or pwd 128 except ImportError: # No pwd on Windows 129 import win32api 130 return win32api.GetUserName()
131
132 - def pid(self):
133 """ 134 Returns some representation of the current process's id 135 """ 136 return str(os.getpid())
137
138 - def access(self, dir):
139 """ 140 Returns True if the current user can write to the given directory 141 """ 142 dir = str(dir) 143 return os.access(dir, os.W_OK)
144
145 - def create(self, dir):
146 """ 147 If the given directory doesn't exist, creates it (with mode 0700) and returns True. 148 Otherwise False. 149 """ 150 dir = path(dir) 151 if not dir.exists(): 152 dir.makedirs(0700) 153 return True 154 return False
155
156 - def gettempdir(self):
157 """ 158 Returns the directory under which all temporary 159 files and folders will be created. 160 """ 161 return self.dir
162
163 - def create_path(self, prefix, suffix, folder = False, text = False, mode = "r+"):
164 """ 165 Uses tempfile.mkdtemp and tempfile.mkstemp to create temporary 166 folders and files, respectively, under self.dir 167 """ 168 169 if folder: 170 name = tempfile.mkdtemp(prefix = prefix, suffix = suffix, dir = self.dir) 171 self.logger.debug("Added folder %s", name) 172 else: 173 fd, name = tempfile.mkstemp(prefix = prefix, suffix = suffix, dir = self.dir, text = text) 174 self.logger.debug("Added file %s", name) 175 try: 176 os.close(fd) 177 except: 178 self.logger.warn("Failed to close fd %s" % fd) 179 180 return path(name)
181
182 - def remove_path(self, name):
183 """ 184 If the given path is under self.dir, then it is deleted 185 whether file or folder. Otherwise, an exception is thrown. 186 """ 187 p = path(name) 188 parpath = p.parpath(self.dir) 189 if len(parpath) < 1: 190 raise exceptions.Exception("%s is not in %s" % (p, self.dir)) 191 192 if p.exists(): 193 if p.isdir(): 194 p.rmtree(onerror = self.on_rmtree) 195 self.logger.debug("Removed folder %s", name) 196 else: 197 p.remove() 198 self.logger.debug("Removed file %s", name)
199
200 - def clean_tempdir(self):
201 """ 202 Deletes self.dir 203 """ 204 dir = self.gettempdir() 205 if dir.exists(): 206 self.logger.debug("Removing tree: %s", dir) 207 dir.rmtree(onerror = self.on_rmtree)
208
209 - def clean_userdir(self):
210 """ 211 Attempts to delete all directories under self.userdir 212 other than the one owned by this process. If a directory 213 is locked, it is skipped. 214 """ 215 self.logger.debug("Cleaning user dir: %s" % self.userdir) 216 dirs = self.userdir.dirs() 217 for dir in dirs: 218 if str(dir) == str(self.dir): 219 self.logger.debug("Skipping self: %s", dir) 220 continue 221 lock = dir / ".lock" 222 f = open(str(lock),"r") 223 try: 224 portalocker.lock(f, portalocker.LOCK_EX|portalocker.LOCK_NB) 225 except: 226 print "Locked: %s" % dir 227 continue 228 dir.rmtree(self.on_rmtree) 229 print "Deleted: %s" % dir
230
231 - def on_rmtree(self, func, name, exc):
232 self.logger.error("rmtree error: %s('%s') => %s", func.__name__, name, exc[1])
233 234 manager = TempFileManager() 235 """ 236 Global TempFileManager instance for use by the current process and 237 registered with the atexit module for cleaning up all created files on exit. 238 Other instances can be created for specialized purposes. 239 """ 240
241 -def create_path(prefix = "omero", suffix = ".tmp", folder = False):
242 """ 243 Uses the global TempFileManager to create a temporary file. 244 """ 245 return manager.create_path(prefix, suffix, folder = folder)
246
247 -def remove_path(file):
248 """ 249 Removes the file from the global TempFileManager. The file will be deleted 250 if it still exists. 251 """ 252 return manager.remove_path(file)
253
254 -def gettempdir():
255 """ 256 Returns the dir value for the global TempFileManager. 257 """ 258 return manager.gettempdir()
259 260 if __name__ == "__main__": 261 262 from omero.util import configure_logging 263 264 if len(sys.argv) > 1: 265 args = sys.argv[1:] 266 else: 267 args = [] 268 269 if "--debug" in args: 270 configure_logging(loglevel=logging.DEBUG) 271 else: 272 configure_logging() 273 274 if "clean" in args: 275 manager.clean_userdir() 276 sys.exit(0) 277 elif "dir" in args: 278 print manager.gettempdir() 279 sys.exit(0) 280 elif "lock" in args: 281 print "Locking %s" % manager.gettempdir() 282 raw_input("Waiting on user input...") 283 sys.exit(0) 284 285 print "Usage: %s clean" % sys.argv[0] 286 print " or: %s dir " % sys.argv[0] 287 sys.exit(2) 288