CMS 3D CMS Logo

duplicateReflexLibrarySearch.py
Go to the documentation of this file.
1 #! /usr/bin/env python3
2 
3 from __future__ import print_function
4 import optparse
5 import os
6 import re
7 import sys
8 import pprint
9 import subprocess
10 from XML2Python import xml2obj
11 try:
12  from subprocess import getoutput
13 except:
14  from commands import getoutput
15 # These aren't all typedefs, but can sometimes make the output more
16 # readable
17 typedefsDict = \
18  {
19  # What we want <= What we have
20  'unsigned int' : ['unsignedint', 'UInt32_t', 'uint32_t'],
21  'unsigned long': ['unsignedlong'],
22  'int' : ['Int32_t'],
23  'float' : ['Float_t'],
24  'double' : ['Double_t'],
25  'char' : ['Char_t'],
26  '< ' : ['<', '&lt;'],
27  ' >' : ['>', '&gt;'],
28  ', ' : [','],
29  }
30 
31 
32 # Equivalent names for packages - lets script know that, for example,
33 # 'TrackReco' package should have objects 'reco::Track'.
34 #Ordered List to search for matched packages
35 equivDict = \
36  [
37  {'Associations': ['TTTrackTruthPair', 'edm::Wrapper.+edm::AssociationMap.+TrackingParticle']},
38  {'TrajectoryState' : ['TrajectoryStateOnSurface']},
39  {'TrackTriggerAssociation' : ['(TTClusterAssociationMap|TTStubAssociationMap|TTTrackAssociationMap|TrackingParticle).*Phase2TrackerDigi',
40  '(TTStub|TTCluster|TTTrack).*Phase2TrackerDigi.*TrackingParticle']},
41  {'L1TrackTrigger' : ['(TTStub|TTCluster|TTTrack).*Phase2TrackerDigi']},
42  {'L1TCalorimeterPhase2' : ['l1tp2::CaloTower.*']},
43  {'L1TCalorimeter' : ['l1t::CaloTower.*']},
44  {'VertexFinder' : ['l1tVertexFinder::Vertex']},
45  {'GsfTracking' : ['reco::GsfTrack(Collection|).*(MomentumConstraint|VertexConstraint)', 'Trajectory.*reco::GsfTrack']},
46  {'PatCandidates' : ['pat::PATObject','pat::Lepton', 'reco::RecoCandidate','pat::[A-Za-z]+Ref(Vector|)', 'pat::UserHolder']},
47  {'BTauReco' : ['reco::.*SoftLeptonTagInfo', 'reco::SoftLeptonProperties','reco::SecondaryVertexTagInfo','reco::IPTagInfo','reco::TemplatedSecondaryVertexTagInfo', 'reco::CATopJetProperties','reco::HTTTopJetProperties']},
48  {'CastorReco' : ['reco::CastorJet']},
49  {'JetMatching' : ['reco::JetFlavourInfo', 'reco::JetFlavour','reco::MatchedPartons']},
50  {'RecoCandidate' : ['reco::Candidate']},
51  {'TrackingAnalysis' : ['TrackingParticle']},
52  {'Egamma' : ['reco::ElectronID']},
53  {'TopObjects' : ['reco::CATopJetProperties']},
54  {'TauReco' : ['reco::L2TauIsolationInfo','reco::RecoTauPiZero','reco::BaseTau']},
55  {'ValidationFormats' : ['PGlobalDigi::.+','PGlobalRecHit::.+']},
56  {'TrajectorySeed' : ['TrajectorySeed']},
57  {'TrackCandidate' : ['TrackCandidate']},
58  {'PatternTools' : ['MomentumConstraint','VertexConstraint','Trajectory']},
59  {'TrackerRecHit2D' : ['SiStrip(Matched|)RecHit[12]D','SiTrackerGSRecHit[12]D','SiPixelRecHit']},
60  {'MuonReco' : ['reco::Muon(Ref|)(Vector|)']},
61  {'MuonSeed' : ['L3MuonTrajectorySeed']},
62  {'HepMCCandidate' : ['reco::GenParticle.*']},
63  {'L1Trigger' : ['l1extra::L1.+Particle', 'l1t::Vertex']},
64  {'TrackInfo' : ['reco::TrackingRecHitInfo']},
65  {'EgammaCandidates' : ['reco::GsfElectron.*','reco::Photon.*']},
66  {'HcalIsolatedTrack' : ['reco::IsolatedPixelTrackCandidate', 'reco::EcalIsolatedParticleCandidate', 'reco::HcalIsolatedTrackCandidate']},
67  {'HcalRecHit' : ['HFRecHit','HORecHit','ZDCRecHit','HBHERecHit']},
68  {'PFRootEvent' : ['EventColin::']},
69  {'CaloTowers' : ['CaloTower.*']},
70  {'GsfTrackReco' : ['GsfTrack.*']},
71  {'METReco' : ['reco::(Calo|PF|Gen|)MET','reco::PFClusterMET']},
72  {'ParticleFlowReco' : ['reco::RecoPFClusterRefCandidateRef.*']},
73  {'ParticleFlowCandidate' : ['reco::PFCandidateRef','reco::PFCandidateFwdRef','reco::PFCandidate']},
74  {'PhysicsToolsObjects' : ['PhysicsTools::Calibration']},
75  {'TrackReco' : ['reco::Track','reco::TrackRef']},
76  {'VertexReco' : ['reco::Vertex']},
77  {'TFWLiteSelectorTest' : ['tfwliteselectortest']},
78  {'TauReco' : ['reco::PFJetRef']},
79  {'JetReco' : ['reco::.*Jet','reco::.*Jet(Collection|Ref)']},
80  {'HGCDigi' : ['HGCSample']},
81  {'HGCRecHit' : ['constHGCRecHit','HGCRecHit']},
82  {'SiPixelObjects' : ['SiPixelQuality.*']},
83  ]
84 
85 ignoreEdmDP = {
86  'LCGReflex/__gnu_cxx::__normal_iterator<std::basic_string<char>*,std::vector<std::basic_string<char>%>%>' : 1,
87  '' : 1
88 }
89 
91  """ Searches through the requested directory looking at
92  'classes_def.xml' files looking for duplicate Reflex definitions."""
93  # compile necessary RE statements
94  classNameRE = re.compile (r'class\s+name\s*=\s*"([^"]*)"')
95  spacesRE = re.compile (r'\s+')
96  stdRE = re.compile (r'std::')
97  srcClassNameRE = re.compile (r'(\w+)/src/classes_def.*[.]xml')
98  ignoreSrcRE = re.compile (r'.*/FWCore/Skeletons/scripts/mkTemplates/.+')
99  braketRE = re.compile (r'<.+>')
100  print("Searching for 'classes_def.xml' in '%s'." % os.path.join(os.environ.get('CMSSW_BASE'),'src'))
101  xmlFiles = []
102  for srcDir in [os.environ.get('CMSSW_BASE'),os.environ.get('CMSSW_RELEASE_BASE')]:
103  if not len(srcDir): continue
104  for xml in getoutput ('cd '+os.path.join(srcDir,'src')+'; find . -name "*classes_def*.xml" -follow -print').split ('\n'):
105  if xml and (not xml in xmlFiles):
106  xmlFiles.append(xml)
107  if options.showXMLs:
108  pprint.pprint (xmlFiles)
109  # try and figure out the names of the packages
110  xmlPackages = []
111  packagesREs = {}
112  equivREs = {}
113  explicitREs = []
114  for item in equivDict:
115  for pack in item:
116  for equiv in item[pack]:
117  explicitREs.append( (re.compile(r'\b' + equiv + r'\b'),pack))
118  if options.lostDefs:
119  for filename in xmlFiles:
120  if (not filename) or (ignoreSrcRE.match(filename)): continue
121  match = srcClassNameRE.search (filename)
122  if not match: continue
123  packageName = match.group(1)
124  xmlPackages.append (packageName)
125  matchString = r'\b' + packageName + r'\b'
126  packagesREs[packageName] = re.compile (matchString)
127  equivList = equivREs.setdefault (packageName, [])
128  for item in equivDict:
129  for equiv in item.get (packageName, []):
130  matchString = re.compile(r'\b' + equiv + r'\b')
131  equivList.append( (matchString, equiv) )
132  equivList.append( (packagesREs[packageName], packageName) )
133  classDict = {}
134  ncdict = {'class' : 'className', 'function' : 'functionName'}
135  for filename in xmlFiles:
136  if (not filename) or (ignoreSrcRE.match(filename)): continue
137  dupProblems = ''
138  exceptName = ''
139  regexList = []
140  localObjects = []
141  simpleObjectREs = []
142  if options.lostDefs:
143  lostMatch = srcClassNameRE.search (filename)
144  if lostMatch:
145  exceptName = lostMatch.group (1)
146  regexList = equivREs[exceptName]
147  xcount = len(regexList)-1
148  if not regexList[xcount][0].search (exceptName):
149  print('%s not found in' % exceptName, end=' ')
150  print(regexList[xcount][0])
151  sys.exit()
152  else: continue
153  if options.verbose:
154  print("filename", filename)
155  try:
156  filepath = os.path.join(os.environ.get('CMSSW_BASE'),'src',filename)
157  if not os.path.exists(filepath):
158  filepath = os.path.join(os.environ.get('CMSSW_RELEASE_BASE'),'src',filename)
159  xmlObj = xml2obj (filename = filepath,
160  filtering = True,
161  nameChangeDict = ncdict)
162  except Exception as detail:
163  print("File %s is malformed XML. Please fix." % filename)
164  print(" ", detail)
165  continue
166  try:
167  classList = xmlObj.selection.className
168  except:
169  try:
170  classList = xmlObj.className
171  except:
172  # this isn't a real classes_def.xml file. Skip it
173  print("**** SKIPPING '%s' - Doesn't seem to have proper information." % filename)
174  continue
175  if not classList:
176  classList = xmlObj.functionName
177  if not classList:
178  print("**** SKIPPING '%s' - Dosen't seem to have proper information(not class/function)." % filename)
179  continue
180  for piece in classList:
181  try:
182  className = spacesRE.sub ('', piece.name)
183  except:
184  # must be one of these class pattern things. Skip it
185  #print " skipping %s" % filename, piece.__repr__()
186  continue
187  className = stdRE.sub ('', className)
188  # print " ", className
189  # Now get rid of any typedefs
190  for typedef, tdList in typedefsDict.items():
191  for alias in tdList:
192  className = re.sub (alias, typedef, className)
193  classDict.setdefault (className, set()).add (filename)
194  # should we check for lost definitions?
195  if not options.lostDefs:
196  continue
197  localObjects.append (className)
198  if options.lazyLostDefs and not braketRE.search (className):
199  #print " ", className
200  matchString = r'\b' + className + r'\b'
201  simpleObjectREs.append( (re.compile (matchString), className ) )
202  for className in localObjects:
203  # if we see our name (or equivalent) here, then let's
204  # skip complaining about this
205  foundEquiv = False
206  for equivRE in regexList:
207  #print("searching %s for %s" % (equivRE[1], className))
208  if equivRE[0].search (className):
209  foundEquiv = True
210  break
211  for simpleRE in simpleObjectREs:
212  if simpleRE[0].search (className):
213  foundEquiv = True
214  if options.verbose and simpleRE[1] != className:
215  print(" Using %s to ignore %s" \
216  % (simpleRE[1], className))
217  break
218  if foundEquiv: continue
219  for exRes in explicitREs:
220  if exRes[0].search(className):
221  dupProblems += " %s : %s\n" % (exRes[1], className)
222  foundEquiv = True
223  break
224  if foundEquiv: continue
225  for packageName in xmlPackages:
226  # don't bother looking for the name of this
227  # package in this package
228  if packagesREs[packageName].search (className):
229  dupProblems += " %s : %s\n" % (packageName, className)
230  break
231  # for piece
232  if dupProblems:
233  print('\n%s\n%s\n' % (filename, dupProblems))
234  # for filename
235  if options.dups:
236  for name, fileSet in sorted( classDict.items() ):
237  if len (fileSet) < 2:
238  continue
239  print(name)
240  fileList = sorted (fileSet)
241  for filename in fileList:
242  print(" ", filename)
243  print()
244  # for name, fileSet
245  # if not noDups
246  #pprint.pprint (classDict)
247 
248 
250  """ Searches the edmpluginFile to find any duplicate
251  plugins."""
252  edmpluginFile = ''
253  libenv = 'LD_LIBRARY_PATH'
254  if os.environ.get('SCRAM_ARCH').startswith('osx'): libenv = 'DYLD_FALLBACK_LIBRARY_PATH'
255  biglib = '/biglib/'+os.environ.get('SCRAM_ARCH')
256  for libdir in os.environ.get(libenv).split(':'):
257  if libdir.endswith(biglib): continue
258  if os.path.exists(libdir+'/.edmplugincache'): edmpluginFile = edmpluginFile + ' ' + libdir+'/.edmplugincache'
259  if edmpluginFile == '': edmpluginFile = os.path.join(os.environ.get('CMSSW_BASE'),'lib',os.environ.get('SCRAM_ARCH'),'.edmplugincache')
260  cmd = "cat %s | awk '{print $2\" \"$1}' | sort | uniq | awk '{print $1}' | sort | uniq -c | grep '2 ' | awk '{print $2}'" % edmpluginFile
261  output = getoutput (cmd).split('\n')
262  for line in output:
263  if line in ignoreEdmDP: continue
264  line = line.replace("*","\*")
265  cmd = "cat %s | grep ' %s ' | awk '{print $1}' | sort | uniq " % (edmpluginFile,line)
266  out1 = getoutput (cmd).split('\n')
267  print(line)
268  for plugin in out1:
269  if plugin:
270  print(" **"+plugin+"**")
271  print()
272 
273 if __name__ == "__main__":
274  # setup options parser
275  parser = optparse.OptionParser ("Usage: %prog [options]\n"\
276  "Searches classes_def.xml for wrong/duplicate "\
277  "definitions")
278  xmlGroup = optparse.OptionGroup (parser, "ClassDef XML options")
279  dumpGroup = optparse.OptionGroup (parser, "EdmPluginDump options")
280  xmlGroup.add_option ('--dups', dest='dups', action='store_true',
281  default=False,
282  help="Search for duplicate definitions")
283  xmlGroup.add_option ('--lostDefs', dest='lostDefs', action='store_true',
284  default=False,
285  help="Looks for definitions in the wrong libraries")
286  xmlGroup.add_option ('--lazyLostDefs', dest='lazyLostDefs',
287  action='store_true',
288  default=False,
289  help="Will try to ignore as many lost defs as reasonable")
290  xmlGroup.add_option ('--verbose', dest='verbose',
291  action='store_true',
292  default=False,
293  help="Prints out a lot of information")
294  xmlGroup.add_option ('--showXMLs', dest='showXMLs', action='store_true',
295  default=False,
296  help="Shows all 'classes_def.xml' files")
297  xmlGroup.add_option ('--dir', dest='srcdir', type='string', default='',
298  help="Obsolete")
299  dumpGroup.add_option ('--edmPD', dest='edmPD', action='store_true',
300  default=False,
301  help="Searches EDM Plugin Dump for duplicates")
302  dumpGroup.add_option ('--edmFile', dest='edmFile', type='string',
303  default='',
304  help="Obsolete")
305  parser.add_option_group (xmlGroup)
306  parser.add_option_group (dumpGroup)
307  (options, args) = parser.parse_args()
308 
309  # Let's go:
310  if options.lazyLostDefs:
311  options.lostDefs = True
312  if options.showXMLs or options.lostDefs or options.dups:
313  searchClassDefXml ()
314  if options.edmPD:
315  searchDuplicatePlugins ()
submitPVValidationJobs.split
def split(sequence, size)
Definition: submitPVValidationJobs.py:352
cond::persistency::search
std::vector< T >::const_iterator search(const cond::Time_t &val, const std::vector< T > &container)
Definition: IOVProxy.cc:21
print
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:46
duplicateReflexLibrarySearch.searchClassDefXml
def searchClassDefXml()
Definition: duplicateReflexLibrarySearch.py:90
duplicateReflexLibrarySearch.searchDuplicatePlugins
def searchDuplicatePlugins()
Definition: duplicateReflexLibrarySearch.py:249