1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5from __future__ import absolute_import 6 7import importlib 8import os 9import sys 10 11from sphinx.util.compat import Directive 12from sphinx.util.docstrings import prepare_docstring 13 14 15def function_reference(f, attr, args, doc): 16 lines = [] 17 18 lines.extend([ 19 f, 20 '-' * len(f), 21 '', 22 ]) 23 24 docstring = prepare_docstring(doc) 25 26 lines.extend([ 27 docstring[0], 28 '', 29 ]) 30 31 arg_types = [] 32 33 for t in args: 34 if isinstance(t, list): 35 inner_types = [t2.__name__ for t2 in t] 36 arg_types.append(' | ' .join(inner_types)) 37 continue 38 39 arg_types.append(t.__name__) 40 41 arg_s = '(%s)' % ', '.join(arg_types) 42 43 lines.extend([ 44 ':Arguments: %s' % arg_s, 45 '', 46 ]) 47 48 lines.extend(docstring[1:]) 49 lines.append('') 50 51 return lines 52 53 54def variable_reference(v, st_type, in_type, doc): 55 lines = [ 56 v, 57 '-' * len(v), 58 '', 59 ] 60 61 docstring = prepare_docstring(doc) 62 63 lines.extend([ 64 docstring[0], 65 '', 66 ]) 67 68 lines.extend([ 69 ':Storage Type: ``%s``' % st_type.__name__, 70 ':Input Type: ``%s``' % in_type.__name__, 71 '', 72 ]) 73 74 lines.extend(docstring[1:]) 75 lines.append('') 76 77 return lines 78 79 80def special_reference(v, func, typ, doc): 81 lines = [ 82 v, 83 '-' * len(v), 84 '', 85 ] 86 87 docstring = prepare_docstring(doc) 88 89 lines.extend([ 90 docstring[0], 91 '', 92 ':Type: ``%s``' % typ.__name__, 93 '', 94 ]) 95 96 lines.extend(docstring[1:]) 97 lines.append('') 98 99 return lines 100 101 102def format_module(m): 103 lines = [] 104 105 for subcontext, cls in sorted(m.SUBCONTEXTS.items()): 106 lines.extend([ 107 '.. _mozbuild_subcontext_%s:' % subcontext, 108 '', 109 'Sub-Context: %s' % subcontext, 110 '=============' + '=' * len(subcontext), 111 '', 112 ]) 113 lines.extend(prepare_docstring(cls.__doc__)) 114 if lines[-1]: 115 lines.append('') 116 117 for k, v in sorted(cls.VARIABLES.items()): 118 lines.extend(variable_reference(k, *v)) 119 120 lines.extend([ 121 'Variables', 122 '=========', 123 '', 124 ]) 125 126 for v in sorted(m.VARIABLES): 127 lines.extend(variable_reference(v, *m.VARIABLES[v])) 128 129 lines.extend([ 130 'Functions', 131 '=========', 132 '', 133 ]) 134 135 for func in sorted(m.FUNCTIONS): 136 lines.extend(function_reference(func, *m.FUNCTIONS[func])) 137 138 lines.extend([ 139 'Special Variables', 140 '=================', 141 '', 142 ]) 143 144 for v in sorted(m.SPECIAL_VARIABLES): 145 lines.extend(special_reference(v, *m.SPECIAL_VARIABLES[v])) 146 147 return lines 148 149 150class MozbuildSymbols(Directive): 151 """Directive to insert mozbuild sandbox symbol information.""" 152 153 required_arguments = 1 154 155 def run(self): 156 module = importlib.import_module(self.arguments[0]) 157 fname = module.__file__ 158 if fname.endswith('.pyc'): 159 fname = fname[0:-1] 160 161 self.state.document.settings.record_dependencies.add(fname) 162 163 # We simply format out the documentation as rst then feed it back 164 # into the parser for conversion. We don't even emit ourselves, so 165 # there's no record of us. 166 self.state_machine.insert_input(format_module(module), fname) 167 168 return [] 169 170 171def setup(app): 172 app.add_directive('mozbuildsymbols', MozbuildSymbols) 173 174 # Unlike typical Sphinx installs, our documentation is assembled from 175 # many sources and staged in a common location. This arguably isn't a best 176 # practice, but it was the easiest to implement at the time. 177 # 178 # Here, we invoke our custom code for staging/generating all our 179 # documentation. 180 from moztreedocs import SphinxManager 181 182 topsrcdir = app.config._raw_config['topsrcdir'] 183 manager = SphinxManager(topsrcdir, 184 os.path.join(topsrcdir, 'tools', 'docs'), 185 app.outdir) 186 manager.generate_docs(app) 187 188 app.srcdir = os.path.join(app.outdir, '_staging') 189 190 # We need to adjust sys.path in order for Python API docs to get generated 191 # properly. We leverage the in-tree virtualenv for this. 192 from mozbuild.virtualenv import VirtualenvManager 193 194 ve = VirtualenvManager(topsrcdir, 195 os.path.join(topsrcdir, 'dummy-objdir'), 196 os.path.join(app.outdir, '_venv'), 197 sys.stderr, 198 os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt')) 199 ve.ensure() 200 ve.activate() 201