1
2
3
4
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
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
30 Exception.__init__(self, msg)
31 self.number = number
32
33
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
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
73
82
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
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
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
127
150
152 return self._display(interactive = interactive)
153
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
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):
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
236
237 - def cd(self, path = os.sep):
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
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
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
274 """Returns current folder"""
275 return os.path.join(*self.cwd())
276
278 """Gives list of all jobs (objects) referenced in current folder
279 or folder in the path if the latter is provided.
280 """
281
282
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
324 """Removes all references for the jobs not present in the registry.
325 Normally you don't need to call this method since it is called automatically whenever
326 job is deleted from the registry.
327 """
328 registry = self._getRegistry()
329 if registry is not None:
330 registry = registry._parent
331 f = self.__select_dir(path)
332 fc = f.copy()
333 for i in fc:
334 if type(fc[i]) == types.DictionaryType:
335 self.cleanlinks(os.path.join(path,i))
336 else:
337 try:
338 j = registry[int(fc[i])]
339 except RegistryKeyError:
340 self._getWriteAccess()
341 try:
342 del f[i]
343 self._setDirty()
344 finally:
345 self._releaseWriteAccess()
346
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
372
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