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)
|