CMS 3D CMS Logo

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