ATLAS Offline Software
AtlCoolTool.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 from PyCool import cool
4 from re import match
5 import time,calendar
6 import CoolConvUtilities.AtlCoolLib as AtlCoolLib
7 
8 from zlib import crc32
9 
10 from posixpath import normpath
11 
12 def expandConnectString( connectString ):
13  """
14  Expands a connect string.
15 
16  This expansion can occur when a connect string without a containing
17  '://' or not in the format 'alias/DBNAME' is specified. In this case
18  the string is interpreted as a sqlite file name and rewritten to a
19  COOL compliant format:
20 
21  TEST.db --> 'sqlite://;schema=TEST.db;dbname=TEST'
22  TEST --> 'sqlite://;schema=TEST;dbname=TEST'
23 
24  The filename can have a '.db' suffix which will be stripped for the
25  'dbname' part of the connect string. Other suffixes will not be recognized.
26 
27  Actually for ATLAS, a simple string without / is interpreted as a database
28  instance name within the SQLite file mycool.db, for consistency with
29  AtlCoolLib behavior
30  """
31  if connectString.find( '://' ) == -1:
32  if connectString.endswith( '.db' ):
33  base = connectString[:-3]
34  elif match("[a-zA-Z0-9_-]+/[A-Z0-9_-]{1,8}",connectString):
35  # it is an alias/DBNAME
36  return connectString
37  else:
38  base = connectString
39  #return ( 'sqlite://;schema=%s;dbname=%s' ) % ( connectString, base )
40  return ('sqlite://;schema=mycool.db;dbname=%s' % base)
41  else:
42  return connectString
43 
44 
45 def connect( connectString, verbose = False):
46  """
47  Connects to the given database and returns a tuple
48  database, connectString
49  where 'database' is a cool.IDatabase object and 'connectString' is the
50  possibly expanded connectString that 'database' is based on.
51 
52  This expansion can occur when a connect string without a containing
53  '://' is specified. In this case the string is interpreted as a sqlite
54  file name and rewritten to a RAL compliant format:
55 
56  TEST.db --> 'sqlite://;schema=TEST.db;dbname=TEST'
57  TEST --> 'sqlite://;schema=TEST;dbname=TEST'
58 
59  The filename can have a '.db' suffix which will be stripped for the
60  'dbname' part of the connect string. Other suffixes will not be recognized.
61 
62  Note that the COOL database inside the file must have the same name as the
63  base of the filename for this shortcut to work. Storing a COOL database
64  MYTEST in a file mytest.db will not work.
65 
66  Set verbose to True to obtain an error print out.
67  """
68  connectString = expandConnectString( connectString )
69  debug=False
70  if (';readoracle' in connectString):
71  # new default is forceOracle - but giving keyword explicitly
72  # forces debug printout
73  connectString=connectString.replace(';readoracle','')
74  debug=True
75  if (';readsqlite' in connectString):
76  connectString=connectString.replace(';readsqlite','')
77  debug=True
78  try:
79  dbSvc = cool.DatabaseSvcFactory.databaseService()
80  readonly=True
81  # frontier/logical cannot do update connections - only real dbs
82  if ('oracle' in connectString or 'mysql' in connectString or 'sqlite' in connectString): readonly=False
83  db=AtlCoolLib.indirectOpen(connectString,readonly,debug)
84  except Exception as e:
85  if 'The database does not exist' in str(e):
86  print ("Creating new database")
87  db = dbSvc.createDatabase( connectString )
88  else:
89  if verbose: print ('Error while connecting:', str(e))
90  db = None
91  return db, connectString
92 
93 
94 typeSizes = { cool.StorageType.Bool : 1,
95  cool.StorageType.UChar : 1,
96  cool.StorageType.Int16 : 2,
97  cool.StorageType.UInt16 : 2,
98  cool.StorageType.Int32 : 4,
99  cool.StorageType.UInt32 : 4,
100  cool.StorageType.UInt63 : 8,
101  cool.StorageType.Int64 : 8,
102  cool.StorageType.Float : 4,
103  cool.StorageType.Double : 8,
104  cool.StorageType.String255 : 255,
105  cool.StorageType.String4k : 4000,
106  cool.StorageType.String64k : 65535,
107  cool.StorageType.String16M : 16777215,
108  cool.StorageType.Blob64k : 65535,
109  cool.StorageType.Blob16M : 16777215,
110  }
111 
112 def byteSize( spec ):
113  """
114  Determines the (effective) byte size of an AttributeListSpecification.
115  This does not account for any extra size for the specification's own
116  structure but just the byte sizes of the attributes. In other words an
117  AttributeListSpecification with a single 'int' fields will report a byte
118  size of 4.
119  """
120  size = 0
121  for i in spec:
122  size += typeSizes[i.storageType().id()]
123  return size
124 
125 
126 
127 class Info(dict):
128  """
129  This class extends a dictionary with a format string for its representation.
130  It is used as the return value for the inspection commands, such that one
131  can both query for the inspected object's information:
132 
133  res = tool.ls( '/a' )
134  print (res['name'])
135 
136  as well as obtain a standard printout of the information:
137 
138  print (res)
139 
140  """
141  def __init__( self, format = None ):
142  super( Info, self ).__init__()
143  self.format = format
144 
145  def __str__( self ):
146  if self.format is None:
147  return super( Info, self ).__str__()
148  else:
149  return self.format % self
150 
151 
152 class InfoList(list):
153  """
154  This class extends a list with a custom string representation.
155  """
156  def __str__( self ):
157  return '\n'.join( [ str(i) for i in self ] )
158 
159  def __repr__( self ):
160  return str( self )
161 
162 
164 
165  def __init__( self, database ):
166  """
167  Initialize the object to a given database.
168 
169  If 'database' is of type string, it must be a RAL compliant connect
170  string or an sqlite filename following the requirements described
171  in CoolTool.connect.
172 
173  Otherwise it must be a valid cool.IDatabase object.
174  """
175  if isinstance(database, str):
176  self.db, connectString = connect( database )
177  else:
178  self.db = database
179  self.curdir='/'
180  self.curtag=""
181  self.curchan=-1
182  self.currunlumi=[cool.ValidityKeyMin,cool.ValidityKeyMax]
183  self.curtimes=[cool.ValidityKeyMin,cool.ValidityKeyMax]
184  self.useoracle=False
185 
186 
187  def connectString( self ):
188  return self.db.databaseId()
189 
190  def cd(self,node='/'):
191  if node.startswith("/"):
192  npath=normpath(node)
193  else:
194  npath=normpath(self.curdir+"/"+node)
195  #Clean out possible double-slash at the beginning
196  if npath.startswith("//"): npath=npath[1:]
197 
198  if self.db.existsFolder(npath) or self.db.existsFolderSet(npath):
199  self.curdir=npath
200  else:
201  raise Exception('Node %s does not exist' % node)
202 
203 
204  def pwd(self):
205  res=InfoList()
206  res.append('Current directory: %s' % self.curdir)
207  return res
208 
209 
210  def usetag(self,tag=""):
211  res=InfoList()
212  try:
213  itag=int(tag)
214  if self.db.existsFolder(self.curdir):
215  f=self.db.getFolder(self.curdir)
216  else:
217  f=self.db.getFolderSet(self.curdir)
218  taglist=f.listTags()
219  # sort the tags in alphabetical order - convert to a list
220  staglist=[]
221  for tag in taglist:
222  staglist+=[str(tag)]
223  staglist.sort()
224  if (itag<len(staglist)):
225  self.curtag=staglist[itag]
226  else:
227  self.curtag=staglist[-1]
228  except ValueError:
229  if (tag!="HEAD"):
230  self.curtag=tag.strip()
231  else:
232  self.curtag=""
233  res.append('Changed current tag selection to %s' % self.curtag)
234  return res
235 
236  def usechan(self,chan="ALL"):
237  if (chan=="ALL" or chan=="all"):
238  ichan=-1
239  else:
240  ichan=int(chan)
241  res=InfoList()
242  self.curchan=ichan
243  if (ichan!=-1):
244  res.append('Changed current channel selection to %i' % self.curchan)
245  else:
246  res.append('Changed current channel selection to ALL')
247  return res
248 
249  def pws(self):
250  res=InfoList()
251  res.append('Current tag selection: %s' % self.curtag)
252  if (self.curchan==-1):
253  res.append('Current channel selection: ALL')
254  else:
255  res.append('Current channel selection: %i' % self.curchan)
256  return res
257 
258  def rmdir(self, node):
259  if node is None or node == '' or node == '.':
260  node=self.curdir
261  elif not node.startswith('/'): node=self.curdir+'/'+node
262  if (node.startswith('//')): node=node[1:]
263  res=InfoList()
264  chk=input('Delete folder(set) '+node+' ? (y/n)')
265  if not (chk=='y' or chk=='Y'):
266  res.append('Deletion aborted!')
267  return res
268  if self.db.existsFolder(node) or self.db.existsFolderSet(node):
269  try:
270  retcode=self.db.dropNode(node)
271  res.append('Folder dropped with return code '+str(retcode))
272  except Exception as e:
273  print (e)
274  res.append('Could not drop folder')
275  else:
276  res.append('Folder '+node+' does not exist')
277  return res
278 
279  def less( self, node, header = False, more=False ):
280  if node is None or node == '' or node == '.':
281  node=self.curdir
282  elif not node.startswith('/'): node=self.curdir+'/'+node
283  if (node.startswith('//')): node=node[1:]
284  res = InfoList()
285  if self.db.existsFolder( node ):
286  f = self.db.getFolder( node )
287  fdesc=f.description()
288  if (self.curchan==-1):
289  chansel=cool.ChannelSelection.all()
290  else:
291  chansel=cool.ChannelSelection(self.curchan)
292  res.append('Using channel: %i' % self.curchan)
293  istime=(fdesc.find('<timeStamp>time')!=-1)
294  if istime:
295  limmin=self.curtimes[0]
296  limmax=self.curtimes[1]
297  else:
298  limmin=self.currunlumi[0]
299  limmax=self.currunlumi[1]
300  if (limmin!=cool.ValidityKeyMin or limmax!=cool.ValidityKeyMax):
301  res.append('Using rawIOV range [%i,%i]' % (limmin,limmax))
302  if (self.curtag==''):
303  restag=""
304  else:
305  if self.curtag not in f.listTags():
306  # tag is not defined here, try hierarchical tag
307  try:
308  restag=f.resolveTag(self.curtag)
309  res.append('Using tag selection: %s resolved to %s' % (self.curtag,restag))
310  except Exception:
311  res.append('Tag %s not defined here' % self.curtag)
312  return res
313  else:
314  restag=self.curtag
315  res.append('Using tag selection: %s' % self.curtag)
316  coolvec=(fdesc.find('CondAttrListVec')>=0 and fdesc.find('coracool')<0)
317  if coolvec: print ("Folder has CoolVector payload")
318  objs = f.browseObjects( limmin,limmax,chansel,restag )
319  while objs.goToNext():
320  if (more):
321  obj=objs.currentRef()
322  i=self.timeRep(obj.since(),istime)+" - "+self.timeRep(obj.until(),istime,True)+" ("+str(obj.channelId())+")"
323  if coolvec:
324  j=0
325  pitr=obj.payloadIterator()
326  while pitr.goToNext():
327  pobj=pitr.currentRef()
328  i+='\nVector element %i:' % j
329  i+=self.payloadRep(pobj,istime)
330  j+=1
331  else:
332  i+=self.payloadRep(obj.payload(),istime)
333  else:
334  i = Info( ' %(str)s' )
335  i['str'] = str(objs.currentRef())
336  res.append( i )
337  else:
338  raise Exception( "Node '%s' is not a folder" % node )
339 
340  return res
341 
342  def more( self, node, header=False ):
343  return self.less(node,header,True)
344 
345  def timeRep(self,value,istime,isend=False):
346  "Print COOL Validity Key in run/LB or time notation"
347  trail=']'
348  if isend: trail=')'
349  if istime:
350  if (value==cool.ValidityKeyMin):
351  return "ValidityKeyMin"
352  elif (cool.ValidityKeyMax-value<1000000000):
353  return "ValidityKeyMax"
354  else:
355  stime=int(value/1000000000)
356  return time.asctime(time.gmtime(stime))+" UTC"
357  else:
358  return "[%i,%i%s" % (value >> 32, value & 0xFFFFFFFF,trail)
359 
360  def payloadRep(self,payload,istime):
361  "Pretty-print the payload of an object - helper function for more cmd"
362  spec=payload.specification()
363  i=""
364  for idx in range(spec.size()):
365  if (idx>0): i+=","
366  typename=spec[idx].storageType().name()
367  i+= " ["+spec[idx].name() + " (" + typename + ") : "
368  if (typename.startswith("Blob")):
369  blob=payload[idx]
370  blobdata=blob.read()
371  if isinstance(blobdata,bytes):
372  chksum=crc32(blobdata)
373  else:
374  chksum=crc32(blobdata.encode())
375  i+= "size=%i,chk=%d" % (blob.size(),chksum)
376  else:
377  i+= str(payload[idx])
378  i+="]"
379  return i
380 
381  def defaultFolderInfo( self ):
382  res = Info( ' %(name)-16s %(description)-16s'
383  ' %(cardinality)-8s %(size)-12s' )
384  res['name'] = 'Name'
385  res['description'] = 'Description'
386  res['cardinality'] = 'Count'
387  res['size'] = 'Size'
388  return res
389 
390 
391  def folderInfo( self, node, doCount=False ):
392  f = self.db.getFolder( node )
393  res = self.defaultFolderInfo()
394  res['name'] = node
395  res['description'] = f.description()
396  if (doCount):
397  res['cardinality'] = f.countObjects( cool.ValidityKeyMin,
398  cool.ValidityKeyMax,
399  cool.ChannelSelection.all() )
400  res['size'] = res['cardinality'] * byteSize( f.payloadSpecification() )
401  else:
402  res['cardinality']='-'
403  res['size']='-'
404  return res
405 
406 
407  def defaultFolderSetInfo( self ):
408  res = Info( ' %(name)-16s %(description)-16s' )
409  res['name'] = 'Name'
410  res['description'] = 'Description'
411  return res
412 
413 
414  def folderSetInfo( self, node ):
415  f = self.db.getFolderSet( node )
416  res = self.defaultFolderSetInfo()
417  res['name'] = node
418  res['description'] = f.description()
419  return res
420 
421 
422  def ls( self, node = '/', header = False, doCount=False ):
423  if node is None or node == '' or node == '.':
424  node=self.curdir
425  elif not node.startswith('/'): node=self.curdir+'/'+node
426  if (node.startswith('//')): node=node[1:]
427 
428  res = InfoList()
429  if self.db.existsFolderSet( node ):
430  fs = self.db.getFolderSet( node )
431 
432  if header and fs.listFolderSets():
433  res.append( self.defaultFolderSetInfo() )
434  for n in fs.listFolderSets():
435  res.append( self.folderSetInfo( n ) )
436 
437  if header and fs.listFolders():
438  res.append( self.defaultFolderInfo() )
439  for n in fs.listFolders():
440  res.append( self.folderInfo( n, doCount ) )
441  else:
442  raise Exception( "Node '%s' is not a folderset" % node )
443  return res
444 
445  def lstags(self,node='/',pattern=""):
446  if node is None or node == '' or node == '.':
447  node=self.curdir
448  elif not node.startswith('/'): node=self.curdir+'/'+node
449  if (node.startswith('//')): node=node[1:]
450  res=InfoList()
451  f=None
452  if self.db.existsFolder(node):
453  f=self.db.getFolder(node)
454  res.append('Listing tags for folder '+node)
455  elif self.db.existsFolderSet(node):
456  f=self.db.getFolderSet(node)
457  res.append('Listing tags for folderset '+node)
458  # Print obsolete tags if pattern is "showObsolete"
459  showObsolete=False
460  if pattern=="showObsolete":
461  showObsolete=True
462  pattern=""
463  if pattern!="":
464  res.append('Only listing tags containing: "%s"' % pattern)
465  if f is not None:
466  staglist=[]
467  taglist=f.listTags()
468  # sort the tags in alphabetical order - convert to a list
469  for tag in taglist:
470  staglist+=[str(tag)]
471  staglist.sort()
472  for tag in staglist:
473  # check match against pattern if defined
474  if pattern!="":
475  if tag.find(pattern)<0: continue
476  else:
477  # Filter Obsolete tags
478  if (not showObsolete) and (f.tagDescription(tag).find('OBSOLETE')>-1): continue
479  # check the lock status of each tag
480  locked=f.tagLockStatus(tag)
481  if (locked==cool.HvsTagLock.UNLOCKED):
482  strlock='unlocked'
483  elif (locked==cool.HvsTagLock.PARTIALLYLOCKED):
484  strlock='partially locked'
485  else:
486  strlock='locked'
487  desc=f.tagDescription(tag)
488  res.append('%s (%s) [%s]' % (tag,strlock,desc))
489  else:
490  raise Exception("Node '%s' does not exist" % node)
491  return res
492 
493  def listchans(self,node='/'):
494  if node is None or node == '' or node == '.':
495  node=self.curdir
496  elif not node.startswith('/'): node=self.curdir+'/'+node
497  if (node.startswith('//')): node=node[1:]
498  res=InfoList()
499  f=None
500  if self.db.existsFolder(node):
501  f=self.db.getFolder(node)
502  res.append('Listing channel IDs, names, descriptions for folder'+node)
503  chanlist=f.listChannels()
504  res.append('Total number of channels defined: %i' % len(chanlist))
505  res.append('Seq ChannelNum ChannelName Desc')
506  iseq=0
507  for ichan in chanlist:
508  try:
509  channame=f.channelName(ichan)
510  except Exception:
511  channame='<none>'
512  try:
513  chandesc=f.channelDescription(ichan)
514  except Exception:
515  chandesc='<none>'
516  res.append('%i: %i %s %s' % (iseq,ichan,channame,chandesc))
517  iseq+=1
518  else:
519  raise Exception("Node '%s' is not a folder" % node)
520  return res
521 
522  def listinfo(self,node='/'):
523  if node is None or node == '' or node == '.':
524  node=self.curdir
525  elif not node.startswith('/'): node=self.curdir+'/'+node
526  if (node.startswith('//')): node=node[1:]
527  res=InfoList()
528  if self.db.existsFolder(node):
529  f=self.db.getFolder(node)
530  if (f.versioningMode()==cool.FolderVersioning.MULTI_VERSION):
531  vstr='multi'
532  else:
533  vstr='single'
534  res.append('Specification for %s-version folder %s' % (vstr,node))
535  fspec=f.payloadSpecification()
536  for field in fspec:
537  res.append(' %s (%s)' % ( field.name(),field.storageType().name()))
538  res.append('Description: %s' % f.description())
539  else:
540  res.append('Node %s is not a folder' % node)
541  return res
542 
543  def settag(self,argumentString):
544  args=argumentString.split()
545  if len(args)<3:
546  raise Exception('Usage: settag <folder> <foldertag> <parenttag>')
547  node=args[0]
548  tag1=args[1]
549  tag2=args[2]
550  if node is None or node == '' or node == '.':
551  node=self.curdir
552  elif not node.startswith('/'): node=self.curdir+'/'+node
553  if (node.startswith('//')): node=node[1:]
554  res=InfoList()
555  f=None
556  if self.db.existsFolder(node):
557  f=self.db.getFolder(node)
558  res.append('Setting tag '+tag1+' for folder '+node+ ' to parent tag '+tag2)
559  elif self.db.existsFolderSet(node):
560  f=self.db.getFolderSet(node)
561  res.append('Setting tag '+tag1+' for folderset '+node+' to parent tag '+tag2)
562  if f is not None:
563  # check tag exists, confirm action if not
564  if tag1 not in f.listTags():
565  print ("WARNING: Tag %s does not exist in node %s" % (tag1,node))
566  chk=input("Do you want to proceed anyway (y/n)")
567  if (chk.upper()!="Y"):
568  raise Exception('ABORTED - Tag %s does not exist' % tag1)
569  try:
570  f.createTagRelation(tag2,tag1)
571  except Exception as e:
572  print (e)
573  res.append('createTagRelation fails')
574  else:
575  raise Exception("Node '%s' does not exist" % node)
576  return res
577 
578  def setchan(self,argumentString):
579  args=argumentString.split()
580  if len(args)<3:
581  raise Exception('Usage: setchan <folder> <chanID> <chanName> {<chanDescr>}')
582  node=args[0]
583  chanid=int(args[1])
584  channame=args[2]
585  if (len(args)>3):
586  chandesc=args[3]
587  else:
588  chandesc=""
589  if node is None or node == '' or node == '.':
590  node=self.curdir
591  elif not node.startswith('/'): node=self.curdir+'/'+node
592  if (node.startswith('//')): node=node[1:]
593  res=InfoList()
594  f=None
595  if self.db.existsFolder(node):
596  f=self.db.getFolder(node)
597  if (f.existsChannel(chanid)):
598  res.append('Resetting data for existing channel %i %s %s' % (chanid,channame,chandesc))
599  f.setChannelName(chanid,channame)
600  if (chandesc!=""):
601  f.setChannelDescription(chanid,chandesc)
602  else:
603  # have to create channel
604  res.append('Creating data for channel %i %s %s' % (chanid ,channame,chandesc))
605  f.createChannel(chanid,channame,chandesc)
606  res.append('Done')
607  else:
608  res.append('Node %s is not a folder' % node)
609  return res
610 
611  def settginfo(self,argumentString):
612  args=argumentString.split()
613  if len(args)<2:
614  raise Exception('Usage: settginfo <folder> <tag> <description>')
615  node=args[0]
616  tag=args[1]
617  desc=' '.join(args[2:])
618  if node is None or node == '' or node == '.':
619  node=self.curdir
620  elif not node.startswith('/'): node=self.curdir+'/'+node
621  if (node.startswith('//')): node=node[1:]
622  res=InfoList()
623  f=None
624  if self.db.existsFolder(node):
625  f=self.db.getFolder(node)
626  elif self.db.existsFolderSet(node):
627  f=self.db.getFolderSet(node)
628  else:
629  res.append('Node %s does not exist' % node)
630  return res
631  res.append('Setting description for tag %s to %s' % (tag,desc))
632  f.setTagDescription(tag,desc)
633  return res
634 
635  def userunlumi(self,argumentString):
636  args=argumentString.split()
637  if len(args)==1:
638  run1=int(args[0])
639  run2=run1
640  lb1=0
641  lb2=0xFFFFFFFF
642  elif len(args)<4:
643  raise Exception('Usage: userunlumi <run1> {<LB1> <run2> <LB2>}')
644  else:
645  run1=int(args[0])
646  lb1=int(args[1])
647  run2=int(args[2])
648  lb2=int(args[3])
649  self.currunlumi[0]=(run1 << 32)+lb1
650  self.currunlumi[1]=(run2 << 32)+lb2
651 
652  def usetimes(self,argumentString):
653  args=argumentString.split()
654  if len(args)<2:
655  raise Exception('Usage: usetimes <t1> <t2>')
656  for i in range(0,2):
657  try:
658  self.curtimes[i]=int(args[i])
659  except ValueError:
660  try:
661  ts=time.strptime(args[i]+'/UTC','%Y-%m-%d:%H:%M:%S/%Z')
662  self.curtimes[i]=int(calendar.timegm(ts))*1000000000
663  except ValueError:
664  print ("ERROR in time specification, use e.g. 2007-05-25:14:01:00")
665 
666 
667  def rmtag(self,argumentString):
668  args=argumentString.split()
669  if len(args)<2:
670  raise Exception('Usage: rmtag <folder> <parenttag>')
671  node=args[0]
672  tag1=args[1]
673  if node is None or node == '' or node == '.':
674  node=self.curdir
675  elif not node.startswith('/'): node=self.curdir+'/'+node
676  if (node.startswith('//')): node=node[1:]
677  res=InfoList()
678  f=None
679  if self.db.existsFolder(node):
680  f=self.db.getFolder(node)
681  res.append('Removing association of tag '+tag1+' to folder '+node)
682  elif self.db.existsFolderSet(node):
683  f=self.db.getFolderSet(node)
684  res.append('Removing association of tag '+tag1+' to folderset '+node)
685  if f is not None:
686  # tag1 can be a leaf tag in the folder, or a parent tag
687  taglist=f.listTags()
688  if (tag1 in taglist):
689  # tag1 is in the folder itself
690  try:
691  f.deleteTag(tag1)
692  res.append('Removal of leaf tag '+tag1+' succeeded')
693  except Exception as e:
694  print (e)
695  res.append('deleteTag fails')
696  else:
697  # tag1 is a tag relation to a parent
698  try:
699  f.deleteTagRelation(tag1)
700  except Exception as e:
701  print (e)
702  res.append('deleteTagRelation fails')
703  else:
704  raise Exception("Node '%s' does not exist" % node)
705  return res
706 
707  def headtag(self,argumentString):
708  args=argumentString.split()
709  if len(args)<2:
710  raise Exception('Usage: headtag <folder> <tag>')
711  node=args[0]
712  tag=args[1]
713  if node is None or node == '' or node == '.':
714  node=self.curdir
715  elif not node.startswith('/'): node=self.curdir+'/'+node
716  if (node.startswith('//')): node=node[1:]
717  res=InfoList()
718  f=None
719  if self.db.existsFolder(node):
720  f=self.db.getFolder(node)
721  res.append('Applying tag '+tag+' to HEAD of folder '+node)
722  try:
723  f.tagCurrentHead(tag,"AtlCoolConsole tag")
724  except Exception as e:
725  print (e)
726  res.append('tagCurrentHead fails')
727  else:
728  raise Exception("Node '%s' does not exist" % node)
729  return res
730 
731  def locktag(self,argumentString):
732  args=argumentString.split()
733  if len(args)<2:
734  raise Exception('Usage: locktag <folder> <tag> {action=l|p|u|r}')
735  node=args[0]
736  tag=args[1]
737  action='L'
738  if len(args)>2:
739  action=args[2].upper()
740  if node is None or node == '' or node == '.':
741  node=self.curdir
742  elif not node.startswith('/'): node=self.curdir+'/'+node
743  if (node.startswith('//')): node=node[1:]
744  res=InfoList()
745  f=None
746  if self.db.existsFolder(node):
747  f=self.db.getFolder(node)
748  if action=='R':
749  action='L'
750  res.append('Folder %s is a leaf node, ignoring recursion' % node)
751  elif self.db.existsFolderSet(node):
752  f=self.db.getFolderSet(node)
753  else:
754  raise Exception("Node '%s' does not exist" % node)
755  if tag not in f.listTags():
756  raise Exception('Tag %s does not exist in node %s' % (tag,node))
757  state=cool.HvsTagLock.LOCKED
758  if (action=='U'): state=cool.HvsTagLock.UNLOCKED
759  if (action=='P'): state=cool.HvsTagLock.PARTIALLYLOCKED
760  if (action=='R'):
761  # find all the tags below this one and lock them too
762  nmod=0
763  nodelist=self.db.listAllNodes()
764  for inode in nodelist:
765  if (inode[:len(node)]==node):
766  # look only in multiversion folders
767  multi=True
768  if (self.db.existsFolder(inode)):
769  subf=self.db.getFolder(inode)
770  if (subf.versioningMode==cool.FolderVersioning.SINGLE_VERSION): multi=False
771  else:
772  subf=self.db.getFolderSet(inode)
773  if (multi):
774  try:
775  rtag=subf.resolveTag(tag)
776  # skip tags which are UPD1 or UPD2 - leave unlocked
777  if (rtag.find('UPD1')==-1 and rtag.find('UPD2')==-1):
778  curstate=subf.tagLockStatus(rtag)
779  if (curstate!=state):
780  subf.setTagLockStatus(rtag,state)
781  nmod+=1
782  res.append('Set lock for tag %s to %i' % (rtag,subf.tagLockStatus(rtag)))
783  else:
784  res.append('Tag %s already at state %i' % (rtag,curstate))
785  else:
786  res.append('Skip tag %s due to UPD mode' % rtag)
787  except Exception:
788  pass
789  res.append('Changed state of %i tags' % nmod)
790  else:
791  # non-recursive tag
792  f.setTagLockStatus(tag,state)
793  res.append('Set lock for tag %s to %i' % (tag,f.tagLockStatus(tag)))
794  return res
795 
796 
797  def tracetags(self,argumentString):
798  args=argumentString.split()
799  if len(args)<2:
800  raise Exception('Usage: tracetags <folder> <foldertag>')
801  node=args[0]
802  tag=args[1]
803  if node is None or node == '' or node == '.':
804  node=self.curdir
805  elif not node.startswith('/'): node=self.curdir+'/'+node
806  if (node.startswith('//')): node=node[1:]
807  res=InfoList()
808  # node must be a folderset, not a folder for this command to make sense
809  if self.db.existsFolderSet(node):
810  f=self.db.getFolderSet(node)
811  else:
812  raise Exception("Node '%s' does not exist" % node)
813  # check the given tag is actually defined in this folder
814  taglist=f.listTags()
815  if tag not in taglist:
816  raise Exception("Tag '%s' does not exist in node '%s'" % (tag,node))
817  # find all folder(sets) under this node
818  res.append('Searching under %s for tags referenced by %s' % (node,tag))
819  nodelist=self.db.listAllNodes()
820  for inode in nodelist:
821  inode = str(inode)
822  if (inode[:len(node)]==node):
823  # look only in multiversion folders
824  multi=True
825  if (self.db.existsFolder(inode)):
826  subf=self.db.getFolder(inode)
827  if (subf.versioningMode==cool.FolderVersioning.SINGLE_VERSION): multi=False
828  else:
829  subf=self.db.getFolderSet(inode)
830  if (multi):
831  try:
832  rtag=subf.resolveTag(tag)
833  except Exception:
834  rtag='<nothing>'
835  res.append('Folder %s : tag %s' % (inode,rtag))
836  return res
837 
838  def clonetag(self,argumentString):
839  args=argumentString.split()
840  if len(args)<3:
841  raise Exception('Usage: clonetag <folder> <sourcetag> <desttag>')
842  node=args[0]
843  tag1=args[1]
844  tag2=args[2]
845  if node is None or node == '' or node == '.':
846  node=self.curdir
847  elif not node.startswith('/'): node=self.curdir+'/'+node
848  if (node.startswith('//')): node=node[1:]
849  res=InfoList()
850  if self.db.existsFolder(node):
851  f=self.db.getFolder(node)
852  # do not allow cloning to existing UPDx tags
853  if (tag2.find('UPD')>=0 and tag2 in f.listTags()):
854  raise Exception('Cannot clone to existing UPDx destination tag %s' % tag2)
855  res.append('Cloning tag '+tag1+' for folder '+node+ ' to dest tag '+tag2)
856  try:
857  f.cloneTagAsUserTag(tag1,tag2)
858  res.append('All done')
859  except Exception as e:
860  res.append('cloneTagAsUserTag failed with error %s' % e)
861  elif self.db.existsFolderSet(node) : #clone tags in folderset mantaining tags hierarchy
862  addedtag = []
863  res.append('Cloning tag '+tag1+' for folder '+node+ ' to dest tag '+tag2)
864  nodelist=self.db.listAllNodes()
865  for inode in nodelist:
866  if (inode[:len(node)+1]==node+'/') or (node=='/' and inode[:len(node)]==node):
867  if self.db.existsFolder(inode):
868  finode=inode[:inode.rfind('/')]
869  if finode==('') : finode='/'
870  while finode!=node:
871  inode=finode
872  finode=inode[:inode.rfind('/')]
873  if finode==('') : finode='/'
874  try:
875  subf=self.db.getFolder(inode)
876  except Exception:
877  subf=self.db.getFolderSet(inode)
878  try:
879  rtag=subf.resolveTag(tag1)
880  try:
881  if rtag not in addedtag :
882  addedtag.append(rtag)
883  subf.createTagRelation(tag2,rtag)
884  except Exception as e:
885  print (e)
886  res.append('createTagRelation failed with error %s' %e)
887  except Exception:
888  res.append('Folder %s : no tag selected' % inode)
889  res.append('All done')
890  else:
891  raise Exception("Node '%s' does not exist" % node)
892  return res
893 
894 
895  def setdesc(self,argumentString):
896  args=argumentString.split()
897  if len(args)<1:
898  raise Exception('Usage: setdesc <folder> {<descrption>}')
899  node=args[0]
900  if (len(args)>1):
901  desc=args[1]
902  else:
903  desc=""
904  if node is None or node == '' or node == '.':
905  node=self.curdir
906  elif not node.startswith('/'): node=self.curdir+'/'+node
907  if (node.startswith('//')): node=node[1:]
908  # special strings to expand
909  if desc=="ATTRTIME" :
910  # code for an inline CondAttrListCollection stored by timestamp
911  desc='<timeStamp>time</timeStamp><addrHeader><address_header service_type="71" clid="40774348" /></addrHeader><typeName>AthenaAttributeList</typeName>'
912  elif desc=="ATTRRUN" :
913  # code for a inline AthenaAttributeList stored by run-event
914  desc='<timeStamp>run-event</timeStamp><addrHeader><address_header service_type="71" clid="40774348" /></addrHeader><typeName>AthenaAttributeList</typeName>'
915  elif desc=="ATTRCOLLTIME" :
916  # code for an inline CondAttrListCollection stored by timestamp
917  desc='<timeStamp>time</timeStamp><addrHeader><address_header service_type="71" clid="1238547719" /></addrHeader><typeName>CondAttrListCollection</typeName>'
918  elif desc=="ATTRCOLLRUN" :
919  # code for an inline CondAttrListCollection stored by run-event
920  desc='<timeStamp>run-event</timeStamp><addrHeader><address_header service_type="71" clid="1238547719" /></addrHeader><typeName>CondAttrListCollection</typeName>'
921 
922  res=InfoList()
923  f=None
924  if self.db.existsFolder(node):
925  f=self.db.getFolder(node)
926  res.append('Current folder description: %s' % f.description())
927  if (desc!=""):
928  res.append('Set folder description to: %s' % desc)
929  try:
930  f.setDescription(desc)
931  except Exception as e:
932  print (e)
933  res.append('Set folder description failed')
934  else:
935  raise Exception("Node '%s' does not exist" % node)
936  return res
937 
938  def __str__( self ):
939  if self.db is not None:
940  return "Connected to '%s'" % self.db.databaseId()
941  else:
942  return "Not connected"
python.AtlCoolTool.AtlCoolTool.useoracle
useoracle
Definition: AtlCoolTool.py:184
python.AtlCoolTool.Info
Definition: AtlCoolTool.py:127
python.AtlCoolTool.InfoList
Definition: AtlCoolTool.py:152
python.AtlCoolTool.AtlCoolTool.usechan
def usechan(self, chan="ALL")
Definition: AtlCoolTool.py:236
python.AtlCoolTool.AtlCoolTool.curchan
curchan
Definition: AtlCoolTool.py:181
python.AtlCoolTool.AtlCoolTool.__init__
def __init__(self, database)
Definition: AtlCoolTool.py:165
python.AtlCoolTool.AtlCoolTool.setchan
def setchan(self, argumentString)
Definition: AtlCoolTool.py:578
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.AtlCoolTool.AtlCoolTool.tracetags
def tracetags(self, argumentString)
Definition: AtlCoolTool.py:797
python.AtlCoolTool.Info.__str__
def __str__(self)
Definition: AtlCoolTool.py:145
python.AtlCoolTool.AtlCoolTool.timeRep
def timeRep(self, value, istime, isend=False)
Definition: AtlCoolTool.py:345
python.AtlCoolTool.connect
def connect(connectString, verbose=False)
Definition: AtlCoolTool.py:45
upper
int upper(int c)
Definition: LArBadChannelParser.cxx:49
python.AtlCoolTool.Info.__init__
def __init__(self, format=None)
Definition: AtlCoolTool.py:141
python.AtlCoolTool.AtlCoolTool
Definition: AtlCoolTool.py:163
python.AtlCoolTool.AtlCoolTool.settag
def settag(self, argumentString)
Definition: AtlCoolTool.py:543
python.AtlCoolTool.AtlCoolTool.curtag
curtag
Definition: AtlCoolTool.py:180
python.AtlCoolTool.AtlCoolTool.less
def less(self, node, header=False, more=False)
Definition: AtlCoolTool.py:279
python.AtlCoolTool.AtlCoolTool.__str__
def __str__(self)
Definition: AtlCoolTool.py:938
python.AtlCoolTool.AtlCoolTool.userunlumi
def userunlumi(self, argumentString)
Definition: AtlCoolTool.py:635
python.AtlCoolTool.AtlCoolTool.lstags
def lstags(self, node='/', pattern="")
Definition: AtlCoolTool.py:445
python.AtlCoolTool.AtlCoolTool.listchans
def listchans(self, node='/')
Definition: AtlCoolTool.py:493
PlotPulseshapeFromCool.input
input
Definition: PlotPulseshapeFromCool.py:106
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
python.AtlCoolTool.AtlCoolTool.pws
def pws(self)
Definition: AtlCoolTool.py:249
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.AtlCoolTool.AtlCoolTool.setdesc
def setdesc(self, argumentString)
Definition: AtlCoolTool.py:895
python.AtlCoolTool.AtlCoolTool.defaultFolderInfo
def defaultFolderInfo(self)
Definition: AtlCoolTool.py:381
python.AtlCoolTool.AtlCoolTool.defaultFolderSetInfo
def defaultFolderSetInfo(self)
Definition: AtlCoolTool.py:407
python.AtlCoolTool.AtlCoolTool.curdir
curdir
Definition: AtlCoolTool.py:179
python.AtlCoolTool.AtlCoolTool.clonetag
def clonetag(self, argumentString)
Definition: AtlCoolTool.py:838
python.AtlCoolTool.AtlCoolTool.currunlumi
currunlumi
Definition: AtlCoolTool.py:182
python.AtlCoolTool.AtlCoolTool.usetag
def usetag(self, tag="")
Definition: AtlCoolTool.py:210
python.AtlCoolTool.AtlCoolTool.ls
def ls(self, node='/', header=False, doCount=False)
Definition: AtlCoolTool.py:422
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.AtlCoolTool.AtlCoolTool.headtag
def headtag(self, argumentString)
Definition: AtlCoolTool.py:707
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:194
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
python.AtlCoolTool.AtlCoolTool.listinfo
def listinfo(self, node='/')
Definition: AtlCoolTool.py:522
python.AtlCoolTool.AtlCoolTool.folderSetInfo
def folderSetInfo(self, node)
Definition: AtlCoolTool.py:414
python.AtlCoolTool.AtlCoolTool.cd
def cd(self, node='/')
Definition: AtlCoolTool.py:190
python.AtlCoolTool.byteSize
def byteSize(spec)
Definition: AtlCoolTool.py:112
python.AtlCoolTool.AtlCoolTool.connectString
def connectString(self)
Definition: AtlCoolTool.py:187
python.AtlCoolTool.AtlCoolTool.more
def more(self, node, header=False)
Definition: AtlCoolTool.py:342
python.AtlCoolTool.AtlCoolTool.db
db
Definition: AtlCoolTool.py:178
python.AtlCoolTool.AtlCoolTool.locktag
def locktag(self, argumentString)
Definition: AtlCoolTool.py:731
python.AtlCoolTool.AtlCoolTool.settginfo
def settginfo(self, argumentString)
Definition: AtlCoolTool.py:611
str
Definition: BTagTrackIpAccessor.cxx:11
python.AtlCoolTool.expandConnectString
def expandConnectString(connectString)
Definition: AtlCoolTool.py:12
python.AtlCoolTool.InfoList.__str__
def __str__(self)
Definition: AtlCoolTool.py:156
python.AtlCoolTool.AtlCoolTool.rmdir
def rmdir(self, node)
Definition: AtlCoolTool.py:258
python.AtlCoolTool.AtlCoolTool.curtimes
curtimes
Definition: AtlCoolTool.py:183
python.AtlCoolTool.AtlCoolTool.payloadRep
def payloadRep(self, payload, istime)
Definition: AtlCoolTool.py:360
python.AtlCoolTool.InfoList.__repr__
def __repr__(self)
Definition: AtlCoolTool.py:159
python.AtlCoolTool.AtlCoolTool.usetimes
def usetimes(self, argumentString)
Definition: AtlCoolTool.py:652
python.AtlCoolTool.Info.format
format
Definition: AtlCoolTool.py:143
python.AtlCoolTool.AtlCoolTool.pwd
def pwd(self)
Definition: AtlCoolTool.py:204
python.AtlCoolTool.AtlCoolTool.rmtag
def rmtag(self, argumentString)
Definition: AtlCoolTool.py:667
match
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition: hcg.cxx:356
python.AtlCoolTool.AtlCoolTool.folderInfo
def folderInfo(self, node, doCount=False)
Definition: AtlCoolTool.py:391