CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
MainPageGenerator.py
Go to the documentation of this file.
1 import json, urllib2, os, sys
2 from BeautifulSoup import *
3 
4 ## MainPageGenerator class is used for generating main page that contains domain trees (Analysis, Calibration and Alignment, Core, DAQ etc.)
6  ## Constructor method.
7  # @param dataPath parameter gives path of data directory that contains .js, .css and image files needed for generating tree pages
8  # @param path is the reference manual directory path and it is used as destination and source.
9  # @param cmsVer is version of CMSSW.
10  def __init__(self, dataPath, path, cmsVer = ""):
11  self.path = path
12  self.dataPath = dataPath
13 
14  self.CMSVER = cmsVer
15 
16  self.managersURL = 'http://cmsdoxy.web.cern.ch/cmsdoxy/tcproxy.php?type=managers'
17  self.usersURL = 'http://cmsdoxy.web.cern.ch/cmsdoxy/tcproxy.php?type=users'
18  self.CMSSWURL = 'http://cmsdoxy.web.cern.ch/cmsdoxy/tcproxy.php?type=packages&release=CMSSW_4_4_2'
19 
20  self.tWikiLinks = {'Analysis':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideCrab',
21  'Calibration and Alignment':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideCalAli',
22  'Core':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideFrameWork',
23  'DAQ':'https://twiki.cern.ch/twiki/bin/view/CMS/TriDASWikiHome',
24  'DQM':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideDQM',
25  'Database':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideCondDB',
26  'Documentation':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuide',
27  'Fast Simulation':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideFastSimulation',
28  'Full Simulation':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideSimulation',
29  'Generators':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideEventGeneration',
30  'Geometry':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideDetectorDescription',
31  'HLT':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideHighLevelTrigger',
32  'L1':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideL1Trigger',
33  'Reconstruction':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideReco',
34  'Visualization':'https://twiki.cern.ch/twiki/bin/view/CMS/SWGuideVisualization'}
35 
36  self.data = None
37 
38  self.GitLink = "https://github.com/cms-sw/cmssw/tree/" + self.CMSVER + "/%s/%s"
39 
40  self.title = "<center>\n<h1>CMSSW Documentation</h1>\n<h2>" + self.CMSVER + "</h2>\n</center>\n"
41  self.links = """
42 <p style="margin-left:10px;">
43 Learn <a href="ReferenceManual.html">how to build Reference Manual</a><br>
44 Learn more about <a target="_blank" href="http://www.stack.nl/~dimitri/doxygen/commands.html">special doxygen commands</a>
45 </p>\n\n"""
46  self.head = """
47 <!-- Content Script & Style -->
48 <script type="text/javascript">
49 var itemList = [];
50 
51 function toggleHoba(item, path)
52 {
53  for(var i = 0; i < itemList.length; i++)
54  {
55  if(itemList[i] == item)
56  {
57  var iframe = $("#"+itemList[i]+"_div").children("iframe:first");
58  if(!iframe.attr("src"))
59  {
60  iframe.attr("src", path)
61  }
62  $("#"+item+"_div").slideToggle();
63  }
64  else
65  $("#"+itemList[i]+"_div").slideUp();
66  }
67 }
68 
69 $(document).ready(function() {
70 searchBox.OnSelectItem(0);
71 $(".doctable").find("td").each(function(){ if (this.id.indexOf("hoba_") != -1)itemList.push(this.id);});
72 });
73 </script>
74 <style>
75 .DCRow
76 {
77  background: #eeeeff;
78  border-spacing: 0px;
79  padding: 0px;
80  border-bottom: 1px solid #c1c1dc;
81 }
82 
83 .DCRow:hover
84 {
85  background: #cde4ec;
86 }
87 </style>
88 <!-- Content Script & Style -->
89  """
90  self.contentStamp = '$CONTENT$'
91  self.mainPageTemplate = self.ReadFile("index.html")
92  self.WriteFile("index_backup.html", self.mainPageTemplate) #backup file
93  soup = BeautifulSoup(self.mainPageTemplate)
94  soup.head.insert(len(soup.head), self.head)
95 
96  contents = soup.find("div", { "class" : "contents" })
97  for child in contents.findChildren():
98  child.extract()
99  contents.insert(0, self.contentStamp)
100  self.mainPageTemplate = str(soup)
101  self.mainPageTemplate = self.mainPageTemplate.replace("CSCDQM Framework Guide", "")
102  self.mainPageTemplate = self.mainPageTemplate.replace('&lt;','<').replace('&gt;', '>')
103  print "Main page template created..."
104 
105  self.CreateBuildRefMan()
106  print "RefMan created..."
107 
108  self.treePageTamplate = self.ReadFile(self.dataPath + "tree_template.html", pathFlag = False)
109  self.classesSource = self.ReadFile("classes.html")
110  self.filesSource = self.ReadFile("files.html")
111  self.packageSource = self.ReadFile("pages.html")
112 
113  def ReadFile(self, fileName, pathFlag = True):
114  """This method reads file directly or from path."""
115  if pathFlag:
116  print "Read:", self.path + fileName
117  f = open(self.path + fileName)
118  else:
119  f = open(fileName)
120  print "Read:", fileName
121  data = f.read()
122  f.close()
123  return data
124 
125  def WriteFile(self, fileName, data):
126  """This method writes data"""
127  print "Write:", self.path + fileName
128  f = open(self.path + fileName, "w")
129  f.write(data)
130  f.close()
131 
132  def GetFileName(self, fileName):
133  """This method returns file name without extension"""
134  if '.' in fileName:
135  return fileName[0:fileName.find('.')]
136  else:
137  return fileName
138 
139  def ParseJsonFromURL(self, URL):
140  """This method returns data which is read from URL"""
141  u = urllib2.urlopen(URL)
142  return json.loads(u.read())
143 
144  def __ParseItem(self, str_):
145  return str_[0:str_.find('/')]
146 
147  def __ParseSubItem(self, str_):
148  if '/' in str_:
149  return str_[str_.find('/')+1:]
150  else:
151  return None
152 
153  def __GetHTMLItemDepth(self, item):
154  return item["id"].count("_") - 1 # 1 for doxygen 1.8.5, 2 for old ver.
155 
156  def __HTMLFileName(self, fileName):
157  return fileName.lower().replace(' ', '_')
158 
159  def PrepareData(self):
161  print "Managers loaded and parsed..."
162 
163  self.users = self.ParseJsonFromURL(self.usersURL)
164  print "Users loaded and parsed..."
165 
166  self.data = {}
167  for i in self.managers.keys():
168  self.data[i] = {"__DATA__":{"Contact":[]}}
169  for j in self.managers[i]:
170  self.data[i]["__DATA__"]["Contact"].append(self.users[j])
172  print "Domains loaded and parsed..."
173 
174  for i in self.domains.keys():
175  for j in self.domains[i]:
176  if not self.data[i].has_key(self.__ParseItem(j)):
177  self.data[i][self.__ParseItem(j)] = {}
178  if not self.data[i][self.__ParseItem(j)].has_key(self.__ParseSubItem(j)):
179  self.data[i][self.__ParseItem(j)][self.__ParseSubItem(j)] = {}
180 
181  self.data[i][self.__ParseItem(j)][self.__ParseSubItem(j)]["__DATA__"] = {
182  'git': self.GitLink % (self.__ParseItem(j), self.__ParseSubItem(j))
183  }
184 
185  # for getting package links
186  soup = BeautifulSoup(self.packageSource)
187  contents = soup.find("div", { "class" : "contents" })
188  li = contents.findAll("tr", {})
189 
190  self.packages = {}
191  for i in li:
192  if i.a["href"]:
193  self.packages[i.a.text] = i.a["href"]
194  print "Packages parsed(%d)..." % len(self.packages)
195 
196  # for getting items from file.html
197  soup = BeautifulSoup(self.filesSource)
198  contents = soup.find("div", { "class" : "contents" })
199  tr = contents.findAll("tr", {})
200  self.classes= {}
201  origin = 0
202  if tr[0].text == 'src': origin = -1
203  # depth of interface items can be only 3
204  flag = False
205  for i in tr:
206  if self.__GetHTMLItemDepth(i) + origin == 1:
207  self.classes[i.text] = {}
208  level1 = i.text
209  flag = False
210 
211  if self.__GetHTMLItemDepth(i) + origin == 2:
212  self.classes[level1][i.text] = {}
213  level2 = i.text
214  flag = False
215 
216  if self.__GetHTMLItemDepth(i) + origin == 3 and i.text == u'interface':
217  flag = True
218  if self.__GetHTMLItemDepth(i) + origin == 3 and i.text != u'interface':
219  flag = False
220 
221 # print i.text, self.__GetHTMLItemDepth(i)
222 # raw_input()
223 
224  if flag and i.text != u'interface':
225  self.classes[level1][level2][i.text] = i.a["href"]
226  #self.ZEG = i
227  print "Class hierarchy loaded(%d)..." % len(self.classes)
228 
229 # self.WriteFile("dbg.json", json.dumps(self.classes, indent = 1))
230 
231  # for parsing classes links from classes.html
232  soup = BeautifulSoup(self.classesSource)
233  contents = soup.find("div", { "class" : "contents" })
234  td = contents.findAll("td", {})
235  self.classesURLs = {}
236  # add items to self.classesURLs
237  for i in td:
238  if i.a and i.a.has_key('href'):
239  self.classesURLs[i.a.text] = i.a['href']
240  print "Class URLs was loaded... (%s)" % len(self.classesURLs)
241 
242  for i in self.data.keys():
243  for j in self.data[i].keys():
244  if not self.classes.has_key(j): continue
245  for k in self.data[i][j].keys():
246  if "Package " + j + "/" + k in self.packages:
247  self.data[i][j][k]["__DATA__"]["packageDoc"] = '../' + self.packages["Package " + j + "/" + k]
248  if not self.classes[j].has_key(k): continue
249  for h in self.classes[j][k]:
250  if self.classesURLs.has_key(self.GetFileName(h)):
251  self.data[i][j][k][self.GetFileName(h)] = {"__DATA__": '../' + self.classesURLs[self.GetFileName(h)]}
252  else:
253  self.data[i][j][k][self.GetFileName(h) + ".h"] = {"__DATA__": '../' + self.classes[j][k][h]}
254 
255  def ExportJSON(self, fileName):
256  if self.data == None:
257  self.PrepareData()
258  self.WriteFile(fileName, json.dumps(self.data, indent = 1))
259 
260  def CreateBuildRefMan(self):
261  content = """<h1>The Reference Manual </h1>
262  This is the CMSSW Reference Manual, the reference documentation of all classes and packages in CMSSW.<p>
263  This page explains how to write the documentation for your code.
264 
265  </p><h2>Class Documentation</h2>
266 
267  Classes and methods are documented with properly formatted <a target="_blank" class="el" href="d3/d88/namespacecomments.html">comments</a> in the code.<p>
268  Here is a template of a documented <a target="_blank" href="http://cmssw.cvs.cern.ch/cgi-bin/cmssw.cgi/CMSSW/Documentation/CodingRules/Template.h?rev=HEAD&amp;cvsroot=CMSSW&amp;content-type=text/vnd.viewcvs-markup">.h file</a>, and of a <a target="_blank" href="http://cmssw.cvs.cern.ch/cgi-bin/cmssw.cgi/CMSSW/Documentation/CodingRules/Template.cc?rev=HEAD&amp;cvsroot=CMSSW&amp;content-type=text/vnd.viewcvs-markup">.cc file</a>. The resulting doxygen page is <a target="_blank" class="el" href="d6/d3e/classTemplate.html">here</a>.
269 
270  </p><h2>Package Documentation</h2>
271 
272  Each package should contain a very brief description of its content and purpose. Remember that this is a reference, and not a user's guide: tutorials, howtos, etc. are best documented in the <a target="_blank" href="https://twiki.cern.ch/twiki/bin/view/CMS/SWGuide">CMS Offline Guide</a> and in the <a target="_blank" href="https://twiki.cern.ch/twiki/bin/view/CMS/WorkBook">WorkBook</a>. Cross links between the CMS Offline Guide and the WorkBook and this manual are a good way to avoid duplication of content.<p>
273  This documentation should be written in a file [Package]/doc/[Package].doc. The simplest way of doing this is to go to the doc/ directory in your package and then run the script
274  <a target="_blank" href="http://cmssw.cvs.cern.ch/cgi-bin/cmssw.cgi/*checkout*/CMSSW/Documentation/ReferenceManualScripts/scripts/makePackageDoc?rev=HEAD&amp;cvsroot=CMSSW">makePackageDoc</a>,
275  which is available in your PATH.
276 
277  </p><h2> How to generate your documentation locally </h2>
278  One you have updated your documentation, you can look at how it displays in the following way:
279 
280  <ul>
281  <li>check out the following packages:
282  <pre> &gt; cmsrel CMSSW_7_X_X
283  &gt; cd CMSSW_7_X_X/
284  &gt; cmsenv
285  &gt; git cms-addpkg Documentation
286 
287  &gt; generate_reference_manual
288 
289  wait...
290 
291  &gt; firefox doc/html/index.html </pre>
292  </li>
293  </ul>"""
294  self.WriteFile('ReferenceManual.html', self.mainPageTemplate.replace(self.contentStamp, content))
295 
296  def CreateNewMainPage(self, outputFileName):
297  if self.data == None:
298  self.PrepareData()
299 
300  contents = """
301  <table class="doctable" border="0" cellpadding="0" cellspacing="0">
302  <tbody>
303  <tr class="top" valign="top">
304  <th class="domain">Domain</th><th class="contact">Contact</th>
305  </tr>
306  """
307  keysI = self.data.keys()
308  keysI.sort()
309  for i in keysI:
310  #########################
311  if i == 'Other': continue
312 
313  self.__NewTreePage(i)
314  contents = contents + '\n<tr class="DCRow">\n' ######### TAG: TR1
315  #########################
316  if i == 'Operations':
317  contents = contents + """<td width="50%%" style="padding:8px">%s</td>\n""" % i
318  else:
319  contents = contents + """<td width="50%%" style="padding:8px;cursor:pointer" onclick="toggleHoba('hoba_%s', 'iframes/%s.html')" id="hoba_%s"><a>%s</a></td>\n""" % (i.replace(' ', '_'), i.lower().replace(' ', '_'), i.replace(' ', '_'), i)
320  #########################
321 
322  contents = contents + '<td width="50%" class="contact">'
323  for j in range(len(self.data[i]["__DATA__"]["Contact"])):
324  if j == len(self.data[i]["__DATA__"]["Contact"]) - 1:
325  contents = contents + '<a href="mailto:%s">%s</a> ' % (self.data[i]["__DATA__"]["Contact"][j][1], self.data[i]["__DATA__"]["Contact"][j][0])
326  else:
327  contents = contents + '<a href="mailto:%s">%s</a>, ' % (self.data[i]["__DATA__"]["Contact"][j][1], self.data[i]["__DATA__"]["Contact"][j][0])
328  contents = contents + '</td>\n'
329  contents = contents + '</tr>\n\n' ######### TAG: TR1
330  #########################
331  if i == 'Operations': continue
332  #########################
333  contents = contents + """
334  <tr><td colspan="2" style="background:#d7dbe3">
335  <div style="display:none;" id="hoba_%s_div"><iframe width="100%%" frameborder="0"></iframe></div>
336  </td></tr>
337  """ % (i.replace(' ', '_'))
338 
339  contents = contents + "</table>"
340  self.WriteFile(outputFileName, self.mainPageTemplate.replace(self.contentStamp, self.title + contents + self.links))
341 
342  def __NewTreePage(self, domain):
343 
344  if not self.data.has_key(domain): return
345 
346  content = ''
347  keysI = self.data[domain].keys()
348  keysI.sort()
349  for i in keysI:
350  if i == '__DATA__': continue
351  content += self.HTMLTreeBegin(i)
352  keysJ = self.data[domain][i].keys()
353  keysJ.sort()
354  for j in keysJ:
355 # if len(self.data[domain][i][j].keys()) == 1:
356 # if self.data[domain][i][j].has_key("__DATA__"):
357 # content += self.HTMLTreeAddItem(j, self.data[domain][i][j]["__DATA__"])
358 # else:
359 # content += self.HTMLTreeAddItem(j)
360 # continue
361  keysK = self.data[domain][i][j].keys()
362  keysK.sort()
363  length = len(keysK)
364 # content += "<!-- Begin -->"
365  if length > 1:
366  if self.data[domain][i][j].has_key("__DATA__"):
367  content += self.HTMLTreeBegin(j, self.data[domain][i][j]["__DATA__"])
368  else:
369  content += self.HTMLTreeBegin(j)
370  else:
371  if self.data[domain][i][j].has_key("__DATA__"):
372  content += self.HTMLTreeAddItem(j, self.data[domain][i][j]["__DATA__"], folder = True)
373  else:
374  content += self.HTMLTreeAddItem(j, folder = True)
375 
376  for k in keysK:
377  if k == '__DATA__': continue
378  if self.data[domain][i][j][k]["__DATA__"]: content += self.HTMLTreeAddItem(k, self.data[domain][i][j][k]["__DATA__"])
379  else: content += self.HTMLTreeAddItem(k)
380  if length > 1:
381  content += self.HTMLTreeEnd()
382 # content += "<!-- End -->"
383  content += self.HTMLTreeEnd()
384  if self.tWikiLinks.has_key(domain):
385  self.WriteFile("iframes/%s.html" % domain.lower().replace(' ', '_'), self.treePageTamplate % (domain, self.tWikiLinks[domain], content))
386  else:
387  print 'Warning: The twiki link of "%s" domain not found...' % domain
388  self.WriteFile("iframes/%s.html" % domain.lower().replace(' ', '_'), self.treePageTamplate % (domain, '#', content))
389 
390  def HTMLTreeBegin(self, title, links = {}):
391  html = '\n<li>\n<div class="hitarea expandable-hitarea"></div>\n'
392  html = html + '<span class="folder">%s\n' % title
393  for i in links.keys():
394  html = html + '<a target="_blank" href="%s">[%s]</a> \n' % (links[i], i)
395  html = html + '</span>\n'
396  html = html + '<ul style="display: block;">\n'
397  return html
398 
399  def HTMLTreeEnd(self):
400  return '</li></ul>\n\n'
401 
402  def HTMLTreeAddItem(self, title, links = None, endNode = False, folder = False):
403  if endNode: html = '\t<li class="last">'
404  else: html = '\t<li>'
405 
406  if type(links) == str or type(links) == type(u''):
407  if folder:
408  html = html + '\t<a href="%s" target="_blank" class=""><span class="emptyFolder">%s</span></a>\n' % (links, title)
409  else:
410  html = html + '\t<a href="%s" target="_blank" class=""><span class="file">%s</span></a>\n' % (links, title)
411  elif type(links) == dict:
412  if folder:
413  html = html + '<span class="emptyFolder">%s ' % title
414  else:
415  html = html + '<span class="file">%s ' % title
416  for i in links.keys():
417  html = html + '<a target="_blank" href="%s">[%s]</a> \n' % (links[i], i)
418  html = html + '</span>'
419  else:
420  html = html + '\t<span class="file">%s</span>\n' % title
421  return html + '\t</li>\n'
422 
423 if len(sys.argv) == 5:
424  DATA_PATH = sys.argv[1]
425  PATH = sys.argv[2]
426  VER = sys.argv[3]
427  OUTF = sys.argv[4]
428 
429  #os.system("cp -rf %s../data/iframes/ %s" % (os.path.split(__file__)[0], PATH))
430 
431  l = MainPageGenerator(DATA_PATH, PATH, cmsVer = VER)
432 
433  l.CreateNewMainPage(OUTF)
434 else:
435  print "parameter error. It must be like this: python MainPageGenerator.py DATA_PATH/ CMSSW/doc/html/ CMS_VER OUTPUT_FILE_NAME"
MainPageGenerator class is used for generating main page that contains domain trees (Analysis...