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