- add sources.
[platform/framework/web/crosswalk.git] / src / tools / telemetry / build / update_docs.py
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 import logging
5 import optparse
6 import os
7 import pkgutil
8 import pydoc
9 import re
10 import sys
11
12 import telemetry
13 from telemetry.core import util
14
15 telemetry_dir = util.GetTelemetryDir()
16 docs_dir = os.path.join(telemetry_dir, 'docs')
17
18 def RemoveAllDocs():
19   for dirname, _, filenames in os.walk(docs_dir):
20     for filename in filenames:
21       os.remove(os.path.join(dirname, filename))
22
23 def GenerateHTMLForModule(module):
24   html = pydoc.html.page(pydoc.describe(module),
25                          pydoc.html.document(module, module.__name__))
26
27   # pydoc writes out html with links in a variety of funky ways. We need
28   # to fix them up.
29   assert not telemetry_dir.endswith(os.sep)
30   links = re.findall('(<a href="(.+?)">(.+?)</a>)', html)
31   for link_match in links:
32     link, href, link_text = link_match
33     if not href.startswith('file:'):
34       continue
35
36     new_href = href.replace('file:', '')
37     new_href = new_href.replace(telemetry_dir, os.pardir)
38     new_href = new_href.replace(os.sep, '/')
39
40     new_link_text = link_text.replace(telemetry_dir + os.sep, '')
41
42     new_link = '<a href="%s">%s</a>' % (new_href, new_link_text)
43     html = html.replace(link, new_link)
44
45   # pydoc writes out html with absolute path file links. This is not suitable
46   # for checked in documentation. So, fix up the HTML after it is generated.
47   #html = re.sub('href="file:%s' % telemetry_dir, 'href="..', html)
48   #html = re.sub(telemetry_dir + os.sep, '', html)
49   return html
50
51 def WriteHTMLForModule(module):
52   page = GenerateHTMLForModule(module)
53   path = os.path.join(docs_dir, '%s.html' % module.__name__)
54   with open(path, 'w') as f:
55     sys.stderr.write('Wrote %s\n' % os.path.relpath(path))
56     f.write(page)
57
58 def GetAllModulesToDocument(module):
59   modules = [module]
60   for _, modname, _ in pkgutil.walk_packages(
61       module.__path__, module.__name__ + '.'):
62     if modname.endswith('_unittest'):
63       logging.debug("skipping %s due to being a unittest", modname)
64       continue
65
66     module = __import__(modname, fromlist=[""])
67     name, _ = os.path.splitext(module.__file__)
68     if not os.path.exists(name + '.py'):
69       logging.info("skipping %s due to being an orphan .pyc", module.__file__)
70       continue
71
72     modules.append(module)
73   return modules
74
75 class AlreadyDocumentedModule(object):
76   def __init__(self, filename):
77     self.filename = filename
78
79   @property
80   def name(self):
81     basename = os.path.basename(self.filename)
82     return os.path.splitext(basename)[0]
83
84   @property
85   def contents(self):
86     with open(self.filename, 'r') as f:
87       return f.read()
88
89 def GetAlreadyDocumentedModules():
90   modules = []
91   for dirname, _, filenames in os.walk(docs_dir):
92     for filename in filenames:
93       path = os.path.join(dirname, filename)
94       modules.append(AlreadyDocumentedModule(path))
95   return modules
96
97
98 def IsUpdateDocsNeeded():
99   already_documented_modules = GetAlreadyDocumentedModules()
100   already_documented_modules_by_name = dict(
101     (module.name, module) for module in already_documented_modules)
102   current_modules = GetAllModulesToDocument(telemetry)
103
104   # Quick check: if the names of modules has changed, we definitely need
105   # an update.
106   already_documented_module_names = set(
107     m.name for m in already_documented_modules)
108
109   current_module_names = set([m.__name__ for m in current_modules])
110
111   if current_module_names != already_documented_module_names:
112     return True
113
114   # Generate the new docs and compare aganist the old. If changed, then a
115   # an update is needed.
116   for current_module in current_modules:
117     already_documented_module = already_documented_modules_by_name[
118       current_module.__name__]
119     current_html = GenerateHTMLForModule(current_module)
120     if current_html != already_documented_module.contents:
121       return True
122
123   return False
124
125 def Main(args):
126   parser = optparse.OptionParser()
127   parser.add_option(
128       '-v', '--verbose', action='count', dest='verbosity',
129       help='Increase verbosity level (repeat as needed)')
130   options, args = parser.parse_args(args)
131   if options.verbosity >= 2:
132     logging.getLogger().setLevel(logging.DEBUG)
133   elif options.verbosity:
134     logging.getLogger().setLevel(logging.INFO)
135   else:
136     logging.getLogger().setLevel(logging.WARNING)
137
138   assert os.path.isdir(docs_dir)
139
140   RemoveAllDocs()
141
142   old_cwd = os.getcwd()
143   try:
144     os.chdir(telemetry_dir)
145     for module in GetAllModulesToDocument(telemetry):
146       WriteHTMLForModule(module)
147   finally:
148     os.chdir(old_cwd)