Revision 5ce58234 lib/build/sphinx_ext.py
b/lib/build/sphinx_ext.py | ||
---|---|---|
23 | 23 |
|
24 | 24 |
""" |
25 | 25 |
|
26 |
import re |
|
26 | 27 |
from cStringIO import StringIO |
27 | 28 |
|
28 | 29 |
import docutils.statemachine |
29 | 30 |
import docutils.nodes |
30 | 31 |
import docutils.utils |
32 |
import docutils.parsers.rst |
|
31 | 33 |
|
32 | 34 |
import sphinx.errors |
33 | 35 |
import sphinx.util.compat |
36 |
import sphinx.roles |
|
37 |
import sphinx.addnodes |
|
34 | 38 |
|
35 | 39 |
s_compat = sphinx.util.compat |
36 | 40 |
|
41 |
try: |
|
42 |
# Access to a protected member of a client class |
|
43 |
# pylint: disable=W0212 |
|
44 |
orig_manpage_role = docutils.parsers.rst.roles._roles["manpage"] |
|
45 |
except (AttributeError, ValueError, KeyError), err: |
|
46 |
# Normally the "manpage" role is registered by sphinx/roles.py |
|
47 |
raise Exception("Can't find reST role named 'manpage': %s" % err) |
|
48 |
|
|
37 | 49 |
from ganeti import constants |
38 | 50 |
from ganeti import compat |
39 | 51 |
from ganeti import errors |
... | ... | |
42 | 54 |
from ganeti import ht |
43 | 55 |
from ganeti import rapi |
44 | 56 |
from ganeti import luxi |
57 |
from ganeti import _autoconf |
|
45 | 58 |
|
46 | 59 |
import ganeti.rapi.rlib2 # pylint: disable=W0611 |
47 | 60 |
|
48 | 61 |
|
62 |
#: Regular expression for man page names |
|
63 |
_MAN_RE = re.compile(r"^(?P<name>[-\w_]+)\((?P<section>\d+)\)$") |
|
64 |
|
|
65 |
|
|
66 |
class ReSTError(Exception): |
|
67 |
"""Custom class for generating errors in Sphinx. |
|
68 |
|
|
69 |
""" |
|
70 |
|
|
71 |
|
|
49 | 72 |
def _GetCommonParamNames(): |
50 | 73 |
"""Builds a list of parameters common to all opcodes. |
51 | 74 |
|
... | ... | |
310 | 333 |
yield " %s" % doc |
311 | 334 |
|
312 | 335 |
|
313 |
# TODO: Implement Sphinx directive for query fields |
|
336 |
def _ManPageNodeClass(*args, **kwargs): |
|
337 |
"""Generates a pending XRef like a ":doc:`...`" reference. |
|
338 |
|
|
339 |
""" |
|
340 |
# Type for sphinx/environment.py:BuildEnvironment.resolve_references |
|
341 |
kwargs["reftype"] = "doc" |
|
342 |
|
|
343 |
# Force custom title |
|
344 |
kwargs["refexplicit"] = True |
|
345 |
|
|
346 |
return sphinx.addnodes.pending_xref(*args, **kwargs) |
|
347 |
|
|
348 |
|
|
349 |
class _ManPageXRefRole(sphinx.roles.XRefRole): |
|
350 |
def __init__(self): |
|
351 |
"""Initializes this class. |
|
352 |
|
|
353 |
""" |
|
354 |
sphinx.roles.XRefRole.__init__(self, nodeclass=_ManPageNodeClass, |
|
355 |
warn_dangling=True) |
|
356 |
|
|
357 |
assert not hasattr(self, "converted"), \ |
|
358 |
"Sphinx base class gained an attribute named 'converted'" |
|
359 |
|
|
360 |
self.converted = None |
|
361 |
|
|
362 |
def process_link(self, env, refnode, has_explicit_title, title, target): |
|
363 |
"""Specialization for man page links. |
|
364 |
|
|
365 |
""" |
|
366 |
if has_explicit_title: |
|
367 |
raise ReSTError("Setting explicit title is not allowed for man pages") |
|
368 |
|
|
369 |
# Check format and extract name and section |
|
370 |
m = _MAN_RE.match(title) |
|
371 |
if not m: |
|
372 |
raise ReSTError("Man page reference '%s' does not match regular" |
|
373 |
" expression '%s'" % (title, _MAN_RE.pattern)) |
|
374 |
|
|
375 |
name = m.group("name") |
|
376 |
section = int(m.group("section")) |
|
377 |
|
|
378 |
wanted_section = _autoconf.MAN_PAGES.get(name, None) |
|
379 |
|
|
380 |
if not (wanted_section is None or wanted_section == section): |
|
381 |
raise ReSTError("Referenced man page '%s' has section number %s, but the" |
|
382 |
" reference uses section %s" % |
|
383 |
(name, wanted_section, section)) |
|
384 |
|
|
385 |
self.converted = bool(wanted_section is not None and |
|
386 |
env.app.config.enable_manpages) |
|
387 |
|
|
388 |
if self.converted: |
|
389 |
# Create link to known man page |
|
390 |
return (title, "man-%s" % name) |
|
391 |
else: |
|
392 |
# No changes |
|
393 |
return (title, target) |
|
394 |
|
|
395 |
|
|
396 |
def _ManPageRole(typ, rawtext, text, lineno, inliner, # pylint: disable=W0102 |
|
397 |
options={}, content=[]): |
|
398 |
"""Custom role for man page references. |
|
399 |
|
|
400 |
Converts man pages to links if enabled during the build. |
|
401 |
|
|
402 |
""" |
|
403 |
xref = _ManPageXRefRole() |
|
404 |
|
|
405 |
assert ht.TNone(xref.converted) |
|
406 |
|
|
407 |
# Check if it's a known man page |
|
408 |
try: |
|
409 |
result = xref(typ, rawtext, text, lineno, inliner, |
|
410 |
options=options, content=content) |
|
411 |
except ReSTError, err: |
|
412 |
msg = inliner.reporter.error(str(err), line=lineno) |
|
413 |
return ([inliner.problematic(rawtext, rawtext, msg)], [msg]) |
|
414 |
|
|
415 |
assert ht.TBool(xref.converted) |
|
416 |
|
|
417 |
# Return if the conversion was successful (i.e. the man page was known and |
|
418 |
# conversion was enabled) |
|
419 |
if xref.converted: |
|
420 |
return result |
|
421 |
|
|
422 |
# Fallback if man page links are disabled or an unknown page is referenced |
|
423 |
return orig_manpage_role(typ, rawtext, text, lineno, inliner, |
|
424 |
options=options, content=content) |
|
314 | 425 |
|
315 | 426 |
|
316 | 427 |
def setup(app): |
317 | 428 |
"""Sphinx extension callback. |
318 | 429 |
|
319 | 430 |
""" |
431 |
# TODO: Implement Sphinx directive for query fields |
|
320 | 432 |
app.add_directive("opcode_params", OpcodeParams) |
321 | 433 |
app.add_directive("opcode_result", OpcodeResult) |
322 | 434 |
app.add_directive("pyassert", PythonAssert) |
323 | 435 |
app.add_role("pyeval", PythonEvalRole) |
436 |
|
|
437 |
app.add_config_value("enable_manpages", False, True) |
|
438 |
app.add_role("manpage", _ManPageRole) |
Also available in: Unified diff