CMS 3D CMS Logo

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