Package Ganga :: Package GPIDev :: Package Lib :: Package JobTree :: Module JobTree'
[hide private]
[frames] | no frames]

Source Code for Module Ganga.GPIDev.Lib.JobTree.JobTree'

  1  ################################################################################
 
  2  # Ganga Project. http://cern.ch/ganga
 
  3  #
 
  4  # $Id: JobTree.py,v 1.2.4.4 2009-07-24 13:39:39 ebke Exp $
 
  5  ################################################################################
 
  6  import os 
  7  import types 
  8  import atexit 
  9  from Ganga.GPIDev.Base   import GangaObject 
 10  from Ganga.GPIDev.Base.Proxy import GPIProxyObjectFactory 
 11  from Ganga.GPIDev.Schema import Schema, SimpleItem, Version 
 12  from Ganga.GPIDev.Lib.Job import Job 
 13  from Ganga.GPIDev.Lib.Registry.JobRegistry import RegistryAccessError, RegistryKeyError 
 14  from Ganga.GPIDev.Lib.Registry.JobRegistry import JobRegistrySlice, JobRegistrySliceProxy, _wrap 
 15  from Ganga.GPIDev.Base.Proxy import GPIProxyObject 
 16  
 
 17  import Ganga.Utility.logging 
 18  logger = Ganga.Utility.logging.getLogger() 
 19  
 
20 -class TreeError(Exception):
21 """JobTree class can raise a TreeError exception. 22 Exception numbers: 23 1, Directory does not exist; 24 2, Not a directory; 25 3, Attemp to delete the root directory; 26 4, Not a job object. 27 """ 28
29 - def __init__(self, number, msg = None):
30 Exception.__init__(self, msg) 31 self.number = number
32 33
34 -class JobTree(GangaObject):
35 """The jobtree object in Ganga gives you the possibility to organise jobs 36 in a directory structure. Jobs are stored in the jobtree by their index 37 and you can think of it as a softlink. 38 This also means that jobs can be placed in several folders at the same time. 39 If you remove a job from the registry the references in the jobtreee will 40 also automatically disappear (because registry calls cleanlinks() method). 41 The jobtree is persisted in between Ganga sessions. 42 """ 43 _schema = Schema(Version(1,2),{ 'name':SimpleItem(''), 44 'folders':SimpleItem({os.sep:{}}, protected = 1, copyable = 1, hidden = 1), 45 }) 46 47 _category = 'jobtrees' 48 _name = 'JobTree' 49 _exportmethods = ['exists', 'isdir', 'add', 'rm', 'cd', 50 'mkdir', 'ls', 'pwd', 'listdirs', 'listjobs', 51 'getjobs', 'find', 'cleanlinks', 'printtree'] 52 53 default_registry = 'jobs' 54 _cwd = {} 55
56 - def __init__(self):
57 super(JobTree, self).__init__() 58 self._setRegistry(None) 59 self.cwd([os.sep])
60
61 - def cwd(self, val=None):
62 """This workaround is necessary to prevent overwriting 63 the current directory every time another session changes something""" 64 if val is None: 65 return JobTree._cwd.get(id(self), [os.sep]) 66 JobTree._cwd[id(self)] = val
67
68 - def __getstate__(self):
69 dict = super(JobTree, self).__getstate__() 70 dict['_registry'] = None 71 dict['_counter'] = 0 72 return dict
73
74 - def __setstate__(self, dict):
75 self._getWriteAccess() 76 try: 77 super(JobTree, self).__setstate__(dict) 78 self._setRegistry(None) 79 self._setDirty() 80 finally: 81 self._releaseWriteAccess()
82
83 - def __get_path(self, path = None):
84 if path == None: 85 return self.cwd()[:] 86 else: 87 pp = [] 88 if not os.path.isabs(path): 89 d = os.path.join(os.path.join(*self.cwd()), path) 90 else: 91 d = path 92 d = os.path.normpath(d) 93 while 1: 94 d, fn = os.path.split(d) 95 if fn: 96 pp.insert(0,fn) 97 else: 98 pp.insert(0,d) 99 break 100 return pp
101
102 - def __make_dir(self, path):
103 f = self.folders 104 for d in self.__get_path(path): 105 if d not in f: 106 f[d] = {} 107 f = f[d] 108 if type(f) != types.DictionaryType: 109 raise TreeError(2, "%s not a directory" % str(d)) 110 return f
111
112 - def __select_dir(self, path):
113 f = self.folders 114 for d in self.__get_path(path): 115 if d not in f: 116 raise TreeError(1, "Directory %s does not exist" % str(d)) 117 f = f[d] 118 if type(f) != types.DictionaryType: 119 raise TreeError(2, "%s not a directory" % str(d)) 120 return f
121
122 - def _copy(self):
123 reg = self._getRegistry() 124 c = self.clone() 125 c._setRegistry(reg) 126 return GPIProxyObjectFactory(c)
127
128 - def _display(self, interactive = 0):
129 from Ganga.Utility.ColourText import ANSIMarkup, NoMarkup, Foreground, Background, Effects 130 if interactive: 131 markup = ANSIMarkup() 132 else: 133 markup = NoMarkup() 134 135 dirs = self.listdirs() 136 cnt = len(dirs) 137 ds = "\n[Folders]: %d\n" % cnt 138 if cnt > 0: 139 ds += "--------------\n" 140 for d in dirs: 141 ds += "%s\n" %d 142 143 jobs = self.getjobs() 144 ds += "[Jobs]: %d\n" % len(jobs) 145 if len(jobs) > 0: 146 ds += "--------------\n" 147 ds += jobs._display(interactive) 148 149 return ds
150
151 - def _proxy_display(self, interactive = 1):
152 return self._display(interactive = interactive)
153
154 - def exists(self, path):
155 """Checks wether the path exists or not. 156 """ 157 f = self.folders 158 for d in self.__get_path(path): 159 try: 160 f = f[d] 161 except: 162 return False 163 return True
164
165 - def isdir(self, path):
166 """Checks wether the path points to a folder or not. 167 """ 168 try: 169 self.__select_dir(path) 170 except TreeError: 171 return False 172 return True
173
174 - def add(self, job, path = None):
175 """Adds job to the job tree into the current folder. 176 If path to a folder is provided as a parameter than adds job to that folder. 177 """ 178 self._getWriteAccess() 179 try: 180 if isinstance(job, GPIProxyObject): 181 job = job._impl 182 if isinstance(job, JobRegistrySliceProxy): 183 job = job._impl 184 185 if isinstance(job, Job): 186 self.__select_dir(path)[job.getFQID('.')] = job.getFQID('.') #job.id 187 self._setDirty() 188 elif isinstance(job, JobRegistrySlice): 189 for sliceKey in job.objects.iterkeys(): 190 self.__select_dir(path)[sliceKey] = sliceKey 191 self._setDirty() 192 elif isinstance(job, list): 193 for element in job: 194 self.__select_dir(path)[element.id] = element.id 195 self._setDirty() 196 else: 197 raise TreeError(4, "Not a job/slice/list object") 198 self._setDirty() 199 finally: 200 self._releaseWriteAccess()
201
202 - def rm(self, path):
203 """Removes folder or job in the path. 204 To clean all use /* as a path. 205 """ 206 self._getWriteAccess() 207 try: 208 path = str(path) 209 pp = self.__get_path(path) 210 if len(pp) > 1: 211 dpath = os.path.join(*pp[:-1]) 212 f = self.__select_dir(dpath) 213 if pp[-1] != '*': 214 try: 215 del f[pp[-1]] 216 except KeyError: 217 raise TreeError(1, "%s does not exist" % str(pp[-1])) 218 else: 219 for k in f.keys(): 220 del f[k] 221 else: 222 raise TreeError(3, "Can not delete the root directory") 223 self._setDirty() 224 finally: 225 self._releaseWriteAccess()
226
227 - def mkdir(self, path):
228 """Makes a folder. If any folders in the path are missing they will be created as well. 229 """ 230 self._getWriteAccess() 231 try: 232 self.__make_dir(path) 233 self._setDirty() 234 finally: 235 self._releaseWriteAccess()
236
237 - def cd(self, path = os.sep):
238 """Changes current directory. 239 If path is not provided, than switches to the root folder. 240 """ 241 self._getWriteAccess() 242 try: 243 self.__select_dir(path) 244 self.cwd(self.__get_path(path)) 245 self._setDirty() 246 finally: 247 self._releaseWriteAccess()
248
249 - def ls(self, path = None):
250 """Lists content of current folder or folder in the path if the latter is provided. 251 The return value is a dictionary of the format 252 {'folders':[<list of folders>], 'jobs':[<list of job ids>]}. 253 """ 254 f = self.__select_dir(path) 255 res = {'folders':[], 'jobs':[]} 256 for i in f: 257 if type(f[i]) == types.DictionaryType: 258 res['folders'].append(i) 259 else: 260 res['jobs'].append(f[i]) 261 return res
262
263 - def listdirs(self, path = None):
264 """Lists all subfolders in current folder or folder in the path if the latter is provided. 265 """ 266 return self.ls(path)['folders']
267
268 - def listjobs(self, path = None):
269 """Lists ids of all jobs in current folder or folder in the path if the latter is provided. 270 """ 271 return self.ls(path)['jobs']
272
273 - def pwd(self):
274 """Returns current folder""" 275 return os.path.join(*self.cwd())
276
277 - def getjobs(self, path = None):
278 """Gives list of all jobs (objects) referenced in current folder 279 or folder in the path if the latter is provided. 280 """ 281 #jobslice 282 ##res = [] 283 res = JobRegistrySlice("") 284 registry = self._getRegistry() 285 do_clean = False 286 if registry is not None: 287 registry = registry._parent 288 path = os.path.join(*self.__get_path(path)) 289 res.name = "jobs found in %s" % path 290 cont = self.ls(path) 291 for i in cont['jobs']: 292 try: 293 j = registry[int(i)] 294 except RegistryKeyError: 295 do_clean = True 296 else: 297 res.objects[j.id] = j 298 if do_clean: 299 self.cleanlinks() 300 return _wrap(res)
301
302 - def find(self, id, path = None):
303 """For a job with given id tries to find all references in the job tree. 304 The return value is a list of found paths. 305 """ 306 res = [] 307 if isinstance(id, GPIProxyObject): 308 id = id._impl 309 if isinstance(id, GangaObject): 310 if isinstance(id, Job): 311 id = id.getFQID('.') 312 else: 313 return res 314 path = os.path.join(*self.__get_path(path)) 315 cont = self.ls(path) 316 for i in cont['jobs']: 317 if id == i: 318 res.append(path) 319 for i in cont['folders']: 320 res.extend(self.find(id, os.path.join(path,i))) 321 return res
322 346
347 - def printtree(self, path = None):
348 """Prints content of the job tree in a well formatted way. 349 """ 350 def printdir(path, indent): 351 cont = self.ls(path) 352 ind = ' '*indent 353 ds = '' 354 for i in cont['jobs']: 355 ds += ind +'|-%s\n' % i 356 for i in cont['folders']: 357 ds += ind +'|-[%s]\n' % i 358 ds += printdir(os.path.join(path,i), indent+1) 359 return ds
360 path = os.path.join(*self.__get_path(path)) 361 bn = os.path.basename(path) 362 if bn == '': 363 bn = os.sep 364 ds = ' [%s]\n' % bn 365 print ds + printdir(path, 1)
366
367 -class _proxy_display(object):
368 - def __get__(self, obj, cls):
369 if obj is None: 370 return cls._impl._proxy_display 371 return obj._impl._proxy_display
372
373 -class _copy(object):
374 - def __get__(self, obj, cls):
375 if obj is None: 376 return cls._impl._copy 377 return obj._impl._copy
378 379 380 JobTree.__str__ = JobTree._display 381 JobTree._proxyClass._display = _proxy_display() 382 JobTree._proxyClass.__str__ = _proxy_display() 383 JobTree._proxyClass.copy = _copy() 384