~rodrigo-gadea-percona/percona-server/ps-docs-domfixes

« back to all changes in this revision

Viewing changes to doc/source/ext/psdom.py

  • Committer: Rodrigo Gadea
  • Date: 2011-08-17 03:14:53 UTC
  • Revision ID: rodrigo.gadea@percona.com-20110817031453-1touqrhgt1kg96p4
Initial port of documentation to Sphinx

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
    sphinx.domains.python
 
4
    ~~~~~~~~~~~~~~~~~~~~~
 
5
 
 
6
    The Percona Server domain.
 
7
 
 
8
    :copyright: Copyright 2011 by Percona Inc.
 
9
    :license: GPL3, see LICENSE for details.
 
10
"""
 
11
 
 
12
import re
 
13
import string
 
14
 
 
15
from docutils import nodes
 
16
from docutils.parsers.rst import directives
 
17
 
 
18
from sphinx import addnodes
 
19
from sphinx.roles import XRefRole
 
20
from sphinx.locale import l_, _
 
21
from sphinx.domains import Domain, ObjType, Index
 
22
from sphinx.directives import ObjectDescription
 
23
from sphinx.util.nodes import make_refnode
 
24
from sphinx.util.compat import Directive
 
25
from sphinx.util.docfields import Field, GroupedField, TypedField
 
26
 
 
27
 
 
28
# RE to split at word boundaries
 
29
wsplit_re = re.compile(r'\W+')
 
30
tern_re = re.compile(r'.*(\.|\:\:).*(\.).*')
 
31
 
 
32
class PSschemaObject(ObjectDescription):
 
33
    """
 
34
    Description of a general PS object.
 
35
    """
 
36
    option_spec = {
 
37
        'noindex': directives.flag,
 
38
    }
 
39
 
 
40
 
 
41
    def handle_signature(self, sig, signode):
 
42
        """Transform a PSschema signature into RST nodes."""
 
43
        # first try the function pointer signature regex, it's more specific
 
44
 
 
45
        name = sig
 
46
 
 
47
#        signode += addnodes.desc_name('', '')
 
48
 
 
49
        objectname = self.env.temp_data.get('psdom:object')
 
50
        ot = self.objtype
 
51
        ws = wsplit_re.split(sig)
 
52
 
 
53
        if ot == 'db':
 
54
            sig_prefix = "database "
 
55
        else:
 
56
            sig_prefix =  ot + " "
 
57
 
 
58
        signode += addnodes.desc_annotation(sig_prefix, sig_prefix)
 
59
 
 
60
        # for part in filter(None, ws):
 
61
        #     tnode = nodes.Text(part, part)
 
62
        #     pnode = addnodes.pending_xref(
 
63
        #         '', refdomain='psdom', reftype='type', reftarget=part,
 
64
        #         modname=None, classname=None)
 
65
        #     pnode = tnode
 
66
        #     signode += pnode
 
67
        
 
68
        if len(ws) > 2:
 
69
            dbname, tablename, columnname = ws
 
70
            name = columnname
 
71
            fullname = tablename + "." + columnname
 
72
        elif len(ws) == 2:
 
73
            if ot == 'table':
 
74
                dbname, tablename = ws
 
75
                dbname += "."
 
76
                name = tablename
 
77
                signode['table'] = tablename
 
78
                signode += addnodes.desc_addname(dbname, dbname)
 
79
                signode += addnodes.desc_name(tablename, tablename)
 
80
                fullname = dbname + "." + tablename
 
81
            if ot == 'column':
 
82
                tablename, columnname = ws
 
83
                tablename += " "
 
84
                signode += addnodes.desc_addname(tablename, tablename)
 
85
                signode += addnodes.desc_name(columnname, columnname)
 
86
                signode['table'] = tablename
 
87
                fullname = tablename + "." + columnname
 
88
        else:
 
89
            if ot == 'table':
 
90
                tablename = ws[0]
 
91
                signode['table'] = tablename
 
92
                dbname = self.options.get(
 
93
                    'db', self.env.temp_data.get('psdom:db'))
 
94
                dbname += "."
 
95
                self.env.temp_data['psdom:table'] = tablename
 
96
                signode += addnodes.desc_addname(dbname, dbname)
 
97
                signode += addnodes.desc_name(tablename, tablename)
 
98
                signode['table'] = tablename
 
99
            if ot == 'column':
 
100
                columnname = ws[0]
 
101
                signode['column'] = columnname
 
102
                tablename = self.options.get(
 
103
                    'table', self.env.temp_data.get('psdom:table'))
 
104
                tablename += "."
 
105
                signode += addnodes.desc_addname(tablename, tablename)
 
106
                signode += addnodes.desc_name(columnname, columnname)
 
107
            if ot == 'db':
 
108
                dbname = ws[0]
 
109
                signode['db'] = dbname
 
110
                name = dbname
 
111
                self.env.temp_data['psdom:db'] = dbname
 
112
                signode += addnodes.desc_name(dbname, dbname)
 
113
            fullname = ws[0]
 
114
 
 
115
        signode['fullname'] = fullname
 
116
 
 
117
 
 
118
        return fullname
 
119
 
 
120
    def get_index_text(self, name):
 
121
        if self.objtype == 'db':
 
122
            return _('%s (database)') % name
 
123
        elif self.objtype == 'table':
 
124
            return _('%s (table)') % name
 
125
        elif self.objtype == 'column':
 
126
            return _('%s (column)') % name
 
127
        else:
 
128
            return ''
 
129
 
 
130
    def add_target_and_index(self, name, sig, signode):
 
131
        # note target
 
132
        if name not in self.state.document.ids:
 
133
            signode['names'].append(name)
 
134
            signode['ids'].append(name)
 
135
            signode['first'] = (not self.names)
 
136
            self.state.document.note_explicit_target(signode)
 
137
            inv = self.env.domaindata['c']['objects']
 
138
            if name in inv:
 
139
                self.env.warn(
 
140
                    self.env.docname,
 
141
                    'duplicate C object description of %s, ' % name +
 
142
                    'other instance in ' + self.env.doc2path(inv[name][0]),
 
143
                    self.lineno)
 
144
            inv[name] = (self.env.docname, self.objtype)
 
145
 
 
146
        indextext = self.get_index_text(name)
 
147
        if indextext:
 
148
            self.indexnode['entries'].append(('single', indextext, name, ''))
 
149
 
 
150
 
 
151
class PSconfigObject(ObjectDescription):
 
152
    """
 
153
    Description of a general PS object.
 
154
    """
 
155
    option_spec = {
 
156
        'noindex': directives.flag,
 
157
    }
 
158
 
 
159
    def handle_signature(self, sig, signode):
 
160
        """Transform a PSschema signature into RST nodes."""
 
161
        # first try the function pointer signature regex, it's more specific
 
162
 
 
163
        name = sig
 
164
        ot = self.objtype
 
165
 
 
166
        sig_prefix =  ot + " "
 
167
        signode += addnodes.desc_annotation(sig_prefix, sig_prefix)
 
168
 
 
169
        signode += addnodes.desc_name(name, name)
 
170
        signode['fullname'] = name
 
171
 
 
172
        return name
 
173
 
 
174
    def get_index_text(self, name):
 
175
        if self.objtype == 'option':
 
176
            return _('%s (option)') % name
 
177
        elif self.objtype == 'variable':
 
178
            return _('%s (variable)') % name
 
179
        else:
 
180
            return ''
 
181
 
 
182
    def add_target_and_index(self, name, sig, signode):
 
183
        # note target
 
184
        if name not in self.state.document.ids:
 
185
            signode['names'].append(name)
 
186
            signode['ids'].append(name)
 
187
            signode['first'] = (not self.names)
 
188
            self.state.document.note_explicit_target(signode)
 
189
            inv = self.env.domaindata['psdom']['objects']
 
190
            if name in inv:
 
191
                self.env.warn(
 
192
                    self.env.docname,
 
193
                    'duplicate C object description of %s, ' % name +
 
194
                    'other instance in ' + self.env.doc2path(inv[name][0]),
 
195
                    self.lineno)
 
196
            inv[name] = (self.env.docname, self.objtype)
 
197
 
 
198
        indextext = self.get_index_text(name)
 
199
        if indextext:
 
200
            self.indexnode['entries'].append(('single', indextext, name, ''))
 
201
 
 
202
 
 
203
class PSTable(PSschemaObject):
 
204
 
 
205
    doc_field_types = [
 
206
        TypedField('tbl', label=l_('Tables'),
 
207
                   names=('tbl', 'table',),
 
208
                   typerolename='obj', typenames=('paramtype', 'type'),
 
209
                   can_collapse=True),
 
210
        TypedField('variable', label=l_('Variables'), rolename='obj',
 
211
                   names=('var', 'ivar', 'cvar'),
 
212
                   typerolename='obj', typenames=('vartype',),
 
213
                   can_collapse=True),
 
214
        TypedField('column', label=l_('Columns'), rolename='obj',
 
215
                   names=('col', 'column', 'cols'),
 
216
                   typerolename='obj', typenames=('paramtype', 'type'),
 
217
                   can_collapse=True),
 
218
        Field('engine', label=l_('Storage Engine'), has_arg=False,
 
219
              names=('engine')),
 
220
        Field('inpatch', label=l_('Included in Patch'), has_arg=False,
 
221
              names=('inpatch')),
 
222
        TypedField('versioninfo', label=l_('Version Info'), rolename='obj',
 
223
                   names=('version', 'versioninfo'),
 
224
                   typerolename='obj', typenames=('paramtype', 'type'),
 
225
                   can_collapse=True),
 
226
    ]
 
227
 
 
228
class PSDatabase(PSschemaObject):
 
229
 
 
230
    doc_field_types = [
 
231
        TypedField('tbl', label=l_('Tables'),
 
232
                   names=('tbl', 'table',),
 
233
                   typerolename='obj', typenames=('paramtype', 'type'),
 
234
                   can_collapse=True),
 
235
        Field('engine', label=l_('Storage Engine'), has_arg=False,
 
236
              names=('engine')),
 
237
        Field('inpatch', label=l_('Included in Patch'), has_arg=False,
 
238
              names=('inpatch')),
 
239
    ]
 
240
 
 
241
class PSColumn(PSschemaObject):
 
242
 
 
243
    doc_field_types = [
 
244
        TypedField('coltype', label=l_('Type'), rolename='obj',
 
245
                   names=('coltype', 'type'),
 
246
                   typerolename='obj', typenames=('paramtype', 'type'),
 
247
                   can_collapse=True),
 
248
        Field('inpatch', label=l_('Included in Patch'), has_arg=False,
 
249
              names=('inpatch')),
 
250
    ]
 
251
 
 
252
class PSVariable(PSconfigObject):
 
253
 
 
254
    doc_field_types = [
 
255
        Field('scope', label=l_('Scope'), has_arg=False,
 
256
              names=('scope', 'varscope')),
 
257
        Field('cmdline', label=l_('Command Line'), has_arg=False,
 
258
              names=('cmdline', 'cline', 'cli')),
 
259
        Field('configfile', label=l_('Config File'), has_arg=False,
 
260
              names=('conffile', 'configfile', 'conf', 'cfile')),
 
261
        Field('dynamic', label=l_('Dynamic'), has_arg=False,
 
262
              names=('dynvar', 'dyn')),
 
263
        Field('vartype', label=l_('Variable Type'), has_arg=False,
 
264
              names=('vartype', 'vtype')),
 
265
        Field('default', label=l_('Default Value'), has_arg=False,
 
266
              names=('default', 'df')),
 
267
        Field('range', label=l_('Range'), has_arg=False,
 
268
              names=('range', 'range')),
 
269
        Field('allowed', label=l_('Allowed Values'), has_arg=False,
 
270
              names=('allowed', 'av')),
 
271
        Field('unit', label=l_('Units'), has_arg=False,
 
272
              names=('unit', 'un')),
 
273
        Field('inpatch', label=l_('Included in Patch'), has_arg=False,
 
274
              names=('inpatch')),
 
275
        TypedField('versioninfo', label=l_('Version Info'), rolename='obj',
 
276
                   names=('version', 'versioninfo'),
 
277
                   typerolename='obj', typenames=('paramtype', 'type'),
 
278
                   can_collapse=True),
 
279
    ]
 
280
 
 
281
class PSOption(PSconfigObject):
 
282
 
 
283
    doc_field_types = [
 
284
        TypedField('tbl', label=l_('Tables'),
 
285
                   names=('tbl', 'table',),
 
286
                   typerolename='obj', typenames=('paramtype', 'type'),
 
287
                   can_collapse=True),
 
288
        TypedField('variable', label=l_('Variables'), rolename='obj',
 
289
                   names=('var', 'ivar', 'cvar'),
 
290
                   typerolename='obj', typenames=('vartype',),
 
291
                   can_collapse=True),
 
292
        TypedField('column', label=l_('Columns'), rolename='obj',
 
293
                   names=('col', 'column', 'cols'),
 
294
                   typerolename='obj', typenames=('paramtype', 'type'),
 
295
                   can_collapse=True),
 
296
        Field('engine', label=l_('Storage Engine'), has_arg=False,
 
297
              names=('engine')),
 
298
        Field('inpatch', label=l_('Included in Patch'), has_arg=False,
 
299
              names=('inpatch')),
 
300
    ]
 
301
 
 
302
class PSXRefRole(XRefRole):
 
303
    def process_link(self, env, refnode, has_explicit_title, title, target):
 
304
        if not has_explicit_title:
 
305
            target = target.lstrip('~') # only has a meaning for the title
 
306
            # if the first character is a tilde, don't display the module/class
 
307
            # parts of the contents
 
308
            if title[0:1] == '~':
 
309
                title = title[1:]
 
310
                dot = title.rfind('.')
 
311
                if dot != -1:
 
312
                    title = title[dot+1:]
 
313
        return title, target
 
314
 
 
315
 
 
316
class PerconaServerDomain(Domain):
 
317
    """Percona Server domain."""
 
318
    name = 'psdom'
 
319
    label = 'Percona Server'
 
320
    object_types = {
 
321
        'db':        ObjType(l_('db'),       'db'),
 
322
        'table':     ObjType(l_('table'),    'table'),
 
323
        'column':    ObjType(l_('column'),   'column'),
 
324
        'option':    ObjType(l_('option'),   'option'),
 
325
        'variable':  ObjType(l_('variable'), 'data'),
 
326
    }
 
327
 
 
328
    directives = {
 
329
        'db':       PSDatabase,
 
330
        'table':    PSTable,
 
331
        'column':   PSColumn,
 
332
        'option':   PSOption,
 
333
        'variable': PSVariable,
 
334
    }
 
335
    roles = {
 
336
        'db' :      PSXRefRole(),
 
337
        'table':    PSXRefRole(),
 
338
        'column':   PSXRefRole(),
 
339
        'option':   PSXRefRole(),
 
340
        'variable': PSXRefRole(),
 
341
    }
 
342
    initial_data = {
 
343
        'objects': {},  # fullname -> docname, objtype
 
344
    }
 
345
 
 
346
    def clear_doc(self, docname):
 
347
        for fullname, (fn, _) in self.data['objects'].items():
 
348
            if fn == docname:
 
349
                del self.data['objects'][fullname]
 
350
 
 
351
    def resolve_xref(self, env, fromdocname, builder,
 
352
                     typ, target, node, contnode):
 
353
        # strip pointer asterisk
 
354
        target = target.rstrip(' *')
 
355
        if target not in self.data['objects']:
 
356
            return None
 
357
        obj = self.data['objects'][target]
 
358
        return make_refnode(builder, fromdocname, obj[0], target,
 
359
                            contnode, target)
 
360
 
 
361
    def get_objects(self):
 
362
        for refname, (docname, type) in self.data['objects'].iteritems():
 
363
            yield (refname, refname, type, docname, refname, 1)
 
364
 
 
365
    def find_obj(self, env, obj, name, typ, searchorder=0):
 
366
        if name[-2:] == '()':
 
367
            name = name[:-2]
 
368
        objects = self.data['objects']
 
369
        newname = None
 
370
        if searchorder == 1:
 
371
            if obj and obj + '.' + name in objects:
 
372
                newname = obj + '.' + name
 
373
            else:
 
374
                newname = name
 
375
        else:
 
376
            if name in objects:
 
377
                newname = name
 
378
            elif obj and obj + '.' + name in objects:
 
379
                newname = obj + '.' + name
 
380
        return newname, objects.get(newname)
 
381
 
 
382
def setup(app):
 
383
    app.add_config_value('databases', {}, 'env')
 
384
    app.add_domain(PerconaServerDomain)