Statistics
| Branch: | Tag: | Revision:

root / lib / build / sphinx_ext.py @ dac59ac5

History | View | Annotate | Download (4 kB)

1
#
2
#
3

    
4
# Copyright (C) 2011 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Sphinx extension for building opcode documentation.
23

24
"""
25

    
26
import operator
27
from cStringIO import StringIO
28

    
29
import docutils.statemachine
30

    
31
import sphinx.errors
32
import sphinx.util.compat
33

    
34
from ganeti import utils
35
from ganeti import opcodes
36
from ganeti import ht
37

    
38

    
39
COMMON_PARAM_NAMES = map(operator.itemgetter(0), opcodes.OpCode.OP_PARAMS)
40

    
41

    
42
class OpcodeError(sphinx.errors.SphinxError):
43
  category = "Opcode error"
44

    
45

    
46
def _SplitOption(text):
47
  """Split simple option list.
48

49
  @type text: string
50
  @param text: Options, e.g. "foo, bar, baz"
51

52
  """
53
  return [i.strip(",").strip() for i in text.split()]
54

    
55

    
56
def _ParseAlias(text):
57
  """Parse simple assignment option.
58

59
  @type text: string
60
  @param text: Assignments, e.g. "foo=bar, hello=world"
61
  @rtype: dict
62

63
  """
64
  result = {}
65

    
66
  for part in _SplitOption(text):
67
    if "=" not in part:
68
      raise OpcodeError("Invalid option format, missing equal sign")
69

    
70
    (name, value) = part.split("=", 1)
71

    
72
    result[name.strip()] = value.strip()
73

    
74
  return result
75

    
76

    
77
def _BuildOpcodeParams(op_id, include, exclude, alias):
78
  """Build opcode parameter documentation.
79

80
  @type op_id: string
81
  @param op_id: Opcode ID
82

83
  """
84
  op_cls = opcodes.OP_MAPPING[op_id]
85

    
86
  params_with_alias = \
87
    utils.NiceSort([(alias.get(name, name), name, default, test, doc)
88
                    for (name, default, test, doc) in op_cls.GetAllParams()],
89
                   key=operator.itemgetter(0))
90

    
91
  for (rapi_name, name, default, test, doc) in params_with_alias:
92
    # Hide common parameters if not explicitely included
93
    if (name in COMMON_PARAM_NAMES and
94
        (not include or name not in include)):
95
      continue
96
    if exclude is not None and name in exclude:
97
      continue
98
    if include is not None and name not in include:
99
      continue
100

    
101
    has_default = default is not ht.NoDefault
102
    has_test = not (test is None or test is ht.NoType)
103

    
104
    buf = StringIO()
105
    buf.write("``%s``" % rapi_name)
106
    if has_default or has_test:
107
      buf.write(" (")
108
      if has_default:
109
        buf.write("defaults to ``%s``" % default)
110
        if has_test:
111
          buf.write(", ")
112
      if has_test:
113
        buf.write("must be ``%s``" % test)
114
      buf.write(")")
115
    yield buf.getvalue()
116

    
117
    # Add text
118
    for line in doc.splitlines():
119
      yield "  %s" % line
120

    
121

    
122
class OpcodeParams(sphinx.util.compat.Directive):
123
  """Custom directive for opcode parameters.
124

125
  See also <http://docutils.sourceforge.net/docs/howto/rst-directives.html>.
126

127
  """
128
  has_content = False
129
  required_arguments = 1
130
  optional_arguments = 0
131
  final_argument_whitespace = False
132
  option_spec = dict(include=_SplitOption, exclude=_SplitOption,
133
                     alias=_ParseAlias)
134

    
135
  def run(self):
136
    op_id = self.arguments[0]
137
    include = self.options.get("include", None)
138
    exclude = self.options.get("exclude", None)
139
    alias = self.options.get("alias", {})
140

    
141
    tab_width = 2
142
    path = op_id
143
    include_text = "\n".join(_BuildOpcodeParams(op_id, include, exclude, alias))
144

    
145
    # Inject into state machine
146
    include_lines = docutils.statemachine.string2lines(include_text, tab_width,
147
                                                       convert_whitespace=1)
148
    self.state_machine.insert_input(include_lines, path)
149

    
150
    return []
151

    
152

    
153
def setup(app):
154
  """Sphinx extension callback.
155

156
  """
157
  app.add_directive("opcode_params", OpcodeParams)