| # Copyright 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| import logging |
| import optparse |
| import os |
| import pkgutil |
| import pydoc |
| import re |
| import sys |
| |
| import telemetry |
| from telemetry.core import util |
| |
| telemetry_dir = util.GetTelemetryDir() |
| docs_dir = os.path.join(telemetry_dir, 'docs') |
| |
| def RemoveAllDocs(): |
| for dirname, _, filenames in os.walk(docs_dir): |
| for filename in filenames: |
| os.remove(os.path.join(dirname, filename)) |
| |
| def GenerateHTMLForModule(module): |
| html = pydoc.html.page(pydoc.describe(module), |
| pydoc.html.document(module, module.__name__)) |
| |
| # pydoc writes out html with links in a variety of funky ways. We need |
| # to fix them up. |
| assert not telemetry_dir.endswith(os.sep) |
| links = re.findall('(<a href="(.+?)">(.+?)</a>)', html) |
| for link_match in links: |
| link, href, link_text = link_match |
| if not href.startswith('file:'): |
| continue |
| |
| new_href = href.replace('file:', '') |
| new_href = new_href.replace(telemetry_dir, os.pardir) |
| new_href = new_href.replace(os.sep, '/') |
| |
| new_link_text = link_text.replace(telemetry_dir + os.sep, '') |
| |
| new_link = '<a href="%s">%s</a>' % (new_href, new_link_text) |
| html = html.replace(link, new_link) |
| |
| # pydoc writes out html with absolute path file links. This is not suitable |
| # for checked in documentation. So, fix up the HTML after it is generated. |
| #html = re.sub('href="file:%s' % telemetry_dir, 'href="..', html) |
| #html = re.sub(telemetry_dir + os.sep, '', html) |
| return html |
| |
| def WriteHTMLForModule(module): |
| page = GenerateHTMLForModule(module) |
| path = os.path.join(docs_dir, '%s.html' % module.__name__) |
| with open(path, 'w') as f: |
| sys.stderr.write('Wrote %s\n' % os.path.relpath(path)) |
| f.write(page) |
| |
| def GetAllModulesToDocument(module): |
| modules = [module] |
| for _, modname, _ in pkgutil.walk_packages( |
| module.__path__, module.__name__ + '.'): |
| if modname.endswith('_unittest'): |
| logging.debug("skipping %s due to being a unittest", modname) |
| continue |
| |
| module = __import__(modname, fromlist=[""]) |
| name, _ = os.path.splitext(module.__file__) |
| if not os.path.exists(name + '.py'): |
| logging.info("skipping %s due to being an orphan .pyc", module.__file__) |
| continue |
| |
| modules.append(module) |
| return modules |
| |
| class AlreadyDocumentedModule(object): |
| def __init__(self, filename): |
| self.filename = filename |
| |
| @property |
| def name(self): |
| basename = os.path.basename(self.filename) |
| return os.path.splitext(basename)[0] |
| |
| @property |
| def contents(self): |
| with open(self.filename, 'r') as f: |
| return f.read() |
| |
| def GetAlreadyDocumentedModules(): |
| modules = [] |
| for dirname, _, filenames in os.walk(docs_dir): |
| for filename in filenames: |
| path = os.path.join(dirname, filename) |
| modules.append(AlreadyDocumentedModule(path)) |
| return modules |
| |
| |
| def IsUpdateDocsNeeded(): |
| already_documented_modules = GetAlreadyDocumentedModules() |
| already_documented_modules_by_name = dict( |
| (module.name, module) for module in already_documented_modules) |
| current_modules = GetAllModulesToDocument(telemetry) |
| |
| # Quick check: if the names of modules has changed, we definitely need |
| # an update. |
| already_documented_module_names = set( |
| m.name for m in already_documented_modules) |
| |
| current_module_names = set([m.__name__ for m in current_modules]) |
| |
| if current_module_names != already_documented_module_names: |
| return True |
| |
| # Generate the new docs and compare aganist the old. If changed, then a |
| # an update is needed. |
| for current_module in current_modules: |
| already_documented_module = already_documented_modules_by_name[ |
| current_module.__name__] |
| current_html = GenerateHTMLForModule(current_module) |
| if current_html != already_documented_module.contents: |
| return True |
| |
| return False |
| |
| def Main(args): |
| parser = optparse.OptionParser() |
| parser.add_option( |
| '-v', '--verbose', action='count', dest='verbosity', |
| help='Increase verbosity level (repeat as needed)') |
| options, args = parser.parse_args(args) |
| if options.verbosity >= 2: |
| logging.getLogger().setLevel(logging.DEBUG) |
| elif options.verbosity: |
| logging.getLogger().setLevel(logging.INFO) |
| else: |
| logging.getLogger().setLevel(logging.WARNING) |
| |
| assert os.path.isdir(docs_dir) |
| |
| RemoveAllDocs() |
| |
| old_cwd = os.getcwd() |
| try: |
| os.chdir(telemetry_dir) |
| for module in GetAllModulesToDocument(telemetry): |
| WriteHTMLForModule(module) |
| finally: |
| os.chdir(old_cwd) |