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/.
6 from pathlib
import Path
8 from docutils
import nodes
9 from docutils
.parsers
.rst
import Directive
10 from mots
.config
import FileConfig
11 from mots
.directory
import Directory
12 from mots
.export
import export_to_format
13 from sphinx
.util
.docstrings
import prepare_docstring
14 from sphinx
.util
.docutils
import ReferenceRole
17 def function_reference(f
, attr
, args
, doc
):
28 docstring
= prepare_docstring(doc
)
40 if isinstance(t
, list):
41 inner_types
= [t2
.__name__
for t2
in t
]
42 arg_types
.append(" | ".join(inner_types
))
45 arg_types
.append(t
.__name
__)
47 arg_s
= "(%s)" % ", ".join(arg_types
)
51 ":Arguments: %s" % arg_s
,
56 lines
.extend(docstring
[1:])
62 def variable_reference(v
, st_type
, in_type
, doc
):
69 docstring
= prepare_docstring(doc
)
80 ":Storage Type: ``%s``" % st_type
.__name
__,
81 ":Input Type: ``%s``" % in_type
.__name
__,
86 lines
.extend(docstring
[1:])
92 def special_reference(v
, func
, typ
, doc
):
99 docstring
= prepare_docstring(doc
)
105 ":Type: ``%s``" % typ
.__name
__,
110 lines
.extend(docstring
[1:])
116 def format_module(m
):
122 " moz.build files' implementation includes a ``Path`` class.",
125 path_docstring_minus_summary
= prepare_docstring(m
.Path
.__doc
__)[2:]
126 lines
.extend([" " + line
for line
in path_docstring_minus_summary
])
128 for subcontext
, cls
in sorted(m
.SUBCONTEXTS
.items()):
131 ".. _mozbuild_subcontext_%s:" % subcontext
,
133 "Sub-Context: %s" % subcontext
,
134 "=============" + "=" * len(subcontext
),
138 lines
.extend(prepare_docstring(cls
.__doc
__))
142 for k
, v
in sorted(cls
.VARIABLES
.items()):
143 lines
.extend(variable_reference(k
, *v
))
153 for v
in sorted(m
.VARIABLES
):
154 lines
.extend(variable_reference(v
, *m
.VARIABLES
[v
]))
164 for func
in sorted(m
.FUNCTIONS
):
165 lines
.extend(function_reference(func
, *m
.FUNCTIONS
[func
]))
175 for v
in sorted(m
.SPECIAL_VARIABLES
):
176 lines
.extend(special_reference(v
, *m
.SPECIAL_VARIABLES
[v
]))
181 def find_mots_config_path(app
):
182 """Find and return mots config path if it exists."""
183 base_path
= Path(app
.srcdir
).parent
184 config_path
= base_path
/ "mots.yaml"
185 if config_path
.exists():
189 def export_mots(config_path
):
190 """Load mots configuration and export it to file."""
191 # Load from disk and initialize configuration and directory.
192 config
= FileConfig(config_path
)
194 directory
= Directory(config
)
197 # Fetch file format (i.e., "rst") and export path.
198 frmt
= config
.config
["export"]["format"]
199 path
= config_path
.parent
/ config
.config
["export"]["path"]
202 output
= export_to_format(directory
, frmt
)
204 # Create export directory if it does not exist.
205 path
.parent
.mkdir(parents
=True, exist_ok
=True)
207 # Write changes to disk.
208 with path
.open("w", encoding
="utf-8") as f
:
212 class MozbuildSymbols(Directive
):
213 """Directive to insert mozbuild sandbox symbol information."""
215 required_arguments
= 1
218 module
= importlib
.import_module(self
.arguments
[0])
219 fname
= module
.__file
__
220 if fname
.endswith(".pyc"):
223 self
.state
.document
.settings
.record_dependencies
.add(fname
)
225 # We simply format out the documentation as rst then feed it back
226 # into the parser for conversion. We don't even emit ourselves, so
227 # there's no record of us.
228 self
.state_machine
.insert_input(format_module(module
), fname
)
233 class Searchfox(ReferenceRole
):
234 """Role which links a relative path from the source to it's searchfox URL.
238 See :searchfox:`browser/base/content/browser-places.js` for more details.
240 Will generate a link to
241 ``https://searchfox.org/mozilla-central/source/browser/base/content/browser-places.js``
243 The example above will use the path as the text, to use custom text:
245 See :searchfox:`this file <browser/base/content/browser-places.js>` for
248 To specify a different source tree:
250 See :searchfox:`mozilla-beta:browser/base/content/browser-places.js`
255 base
= "https://searchfox.org/{source}/source/{path}"
257 if ":" in self
.target
:
258 source
, path
= self
.target
.split(":", 1)
260 source
= "mozilla-central"
263 url
= base
.format(source
=source
, path
=path
)
265 if self
.has_explicit_title
:
270 node
= nodes
.reference(self
.rawtext
, title
, refuri
=url
, **self
.options
)
275 from moztreedocs
import manager
277 app
.add_directive("mozbuildsymbols", MozbuildSymbols
)
278 app
.add_role("searchfox", Searchfox())
280 # Unlike typical Sphinx installs, our documentation is assembled from
281 # many sources and staged in a common location. This arguably isn't a best
282 # practice, but it was the easiest to implement at the time.
284 # Here, we invoke our custom code for staging/generating all our
287 # Export and write "governance" documentation to disk.
288 config_path
= find_mots_config_path(app
)
290 export_mots(config_path
)
292 manager
.generate_docs(app
)
293 app
.srcdir
= manager
.staging_dir