ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / third_party / waf / waflib / extras / rst.py
blobf3c3a5eba426a37dc5f4f1275a9d859b7601b579
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Jérôme Carretero, 2013 (zougloub)
5 """
6 reStructuredText support (experimental)
8 Example::
10 def configure(conf):
11 conf.load('rst')
12 if not conf.env.RST2HTML:
13 conf.fatal('The program rst2html is required')
15 def build(bld):
16 bld(
17 features = 'rst',
18 type = 'rst2html', # rst2html, rst2pdf, ...
19 source = 'index.rst', # mandatory, the source
20 deps = 'image.png', # to give additional non-trivial dependencies
23 By default the tool looks for a set of programs in PATH.
24 The tools are defined in `rst_progs`.
25 To configure with a special program use::
27 $ RST2HTML=/path/to/rst2html waf configure
29 This tool is experimental; don't hesitate to contribute to it.
31 """
33 import re
34 from waflib import Node, Utils, Task, Errors, Logs
35 from waflib.TaskGen import feature, before_method
37 rst_progs = "rst2html rst2xetex rst2latex rst2xml rst2pdf rst2s5 rst2man rst2odt rst2rtf".split()
39 def parse_rst_node(task, node, nodes, names, seen, dirs=None):
40 # TODO add extensibility, to handle custom rst include tags...
41 if dirs is None:
42 dirs = (node.parent,node.get_bld().parent)
44 if node in seen:
45 return
46 seen.append(node)
47 code = node.read()
48 re_rst = re.compile(r'^\s*.. ((?P<subst>\|\S+\|) )?(?P<type>include|image|figure):: (?P<file>.*)$', re.M)
49 for match in re_rst.finditer(code):
50 ipath = match.group('file')
51 itype = match.group('type')
52 Logs.debug('rst: visiting %s: %s', itype, ipath)
53 found = False
54 for d in dirs:
55 Logs.debug('rst: looking for %s in %s', ipath, d.abspath())
56 found = d.find_node(ipath)
57 if found:
58 Logs.debug('rst: found %s as %s', ipath, found.abspath())
59 nodes.append((itype, found))
60 if itype == 'include':
61 parse_rst_node(task, found, nodes, names, seen)
62 break
63 if not found:
64 names.append((itype, ipath))
66 class docutils(Task.Task):
67 """
68 Compile a rst file.
69 """
71 def scan(self):
72 """
73 A recursive regex-based scanner that finds rst dependencies.
74 """
76 nodes = []
77 names = []
78 seen = []
80 node = self.inputs[0]
82 if not node:
83 return (nodes, names)
85 parse_rst_node(self, node, nodes, names, seen)
87 Logs.debug('rst: %r: found the following file deps: %r', self, nodes)
88 if names:
89 Logs.warn('rst: %r: could not find the following file deps: %r', self, names)
91 return ([v for (t,v) in nodes], [v for (t,v) in names])
93 def check_status(self, msg, retcode):
94 """
95 Check an exit status and raise an error with a particular message
97 :param msg: message to display if the code is non-zero
98 :type msg: string
99 :param retcode: condition
100 :type retcode: boolean
102 if retcode != 0:
103 raise Errors.WafError('%r command exit status %r' % (msg, retcode))
105 def run(self):
107 Runs the rst compilation using docutils
109 raise NotImplementedError()
111 class rst2html(docutils):
112 color = 'BLUE'
114 def __init__(self, *args, **kw):
115 docutils.__init__(self, *args, **kw)
116 self.command = self.generator.env.RST2HTML
117 self.attributes = ['stylesheet']
119 def scan(self):
120 nodes, names = docutils.scan(self)
122 for attribute in self.attributes:
123 stylesheet = getattr(self.generator, attribute, None)
124 if stylesheet is not None:
125 ssnode = self.generator.to_nodes(stylesheet)[0]
126 nodes.append(ssnode)
127 Logs.debug('rst: adding dep to %s %s', attribute, stylesheet)
129 return nodes, names
131 def run(self):
132 cwdn = self.outputs[0].parent
133 src = self.inputs[0].path_from(cwdn)
134 dst = self.outputs[0].path_from(cwdn)
136 cmd = self.command + [src, dst]
137 cmd += Utils.to_list(getattr(self.generator, 'options', []))
138 for attribute in self.attributes:
139 stylesheet = getattr(self.generator, attribute, None)
140 if stylesheet is not None:
141 stylesheet = self.generator.to_nodes(stylesheet)[0]
142 cmd += ['--%s' % attribute, stylesheet.path_from(cwdn)]
144 return self.exec_command(cmd, cwd=cwdn.abspath())
146 class rst2s5(rst2html):
147 def __init__(self, *args, **kw):
148 rst2html.__init__(self, *args, **kw)
149 self.command = self.generator.env.RST2S5
150 self.attributes = ['stylesheet']
152 class rst2latex(rst2html):
153 def __init__(self, *args, **kw):
154 rst2html.__init__(self, *args, **kw)
155 self.command = self.generator.env.RST2LATEX
156 self.attributes = ['stylesheet']
158 class rst2xetex(rst2html):
159 def __init__(self, *args, **kw):
160 rst2html.__init__(self, *args, **kw)
161 self.command = self.generator.env.RST2XETEX
162 self.attributes = ['stylesheet']
164 class rst2pdf(docutils):
165 color = 'BLUE'
166 def run(self):
167 cwdn = self.outputs[0].parent
168 src = self.inputs[0].path_from(cwdn)
169 dst = self.outputs[0].path_from(cwdn)
171 cmd = self.generator.env.RST2PDF + [src, '-o', dst]
172 cmd += Utils.to_list(getattr(self.generator, 'options', []))
174 return self.exec_command(cmd, cwd=cwdn.abspath())
177 @feature('rst')
178 @before_method('process_source')
179 def apply_rst(self):
181 Create :py:class:`rst` or other rst-related task objects
184 if self.target:
185 if isinstance(self.target, Node.Node):
186 tgt = self.target
187 elif isinstance(self.target, str):
188 tgt = self.path.get_bld().make_node(self.target)
189 else:
190 self.bld.fatal("rst: Don't know how to build target name %s which is not a string or Node for %s" % (self.target, self))
191 else:
192 tgt = None
194 tsk_type = getattr(self, 'type', None)
196 src = self.to_nodes(self.source)
197 assert len(src) == 1
198 src = src[0]
200 if tsk_type is not None and tgt is None:
201 if tsk_type.startswith('rst2'):
202 ext = tsk_type[4:]
203 else:
204 self.bld.fatal("rst: Could not detect the output file extension for %s" % self)
205 tgt = src.change_ext('.%s' % ext)
206 elif tsk_type is None and tgt is not None:
207 out = tgt.name
208 ext = out[out.rfind('.')+1:]
209 self.type = 'rst2' + ext
210 elif tsk_type is not None and tgt is not None:
211 # the user knows what he wants
212 pass
213 else:
214 self.bld.fatal("rst: Need to indicate task type or target name for %s" % self)
216 deps_lst = []
218 if getattr(self, 'deps', None):
219 deps = self.to_list(self.deps)
220 for filename in deps:
221 n = self.path.find_resource(filename)
222 if not n:
223 self.bld.fatal('Could not find %r for %r' % (filename, self))
224 if not n in deps_lst:
225 deps_lst.append(n)
227 try:
228 task = self.create_task(self.type, src, tgt)
229 except KeyError:
230 self.bld.fatal("rst: Task of type %s not implemented (created by %s)" % (self.type, self))
232 task.env = self.env
234 # add the manual dependencies
235 if deps_lst:
236 try:
237 lst = self.bld.node_deps[task.uid()]
238 for n in deps_lst:
239 if not n in lst:
240 lst.append(n)
241 except KeyError:
242 self.bld.node_deps[task.uid()] = deps_lst
244 inst_to = getattr(self, 'install_path', None)
245 if inst_to:
246 self.install_task = self.add_install_files(install_to=inst_to, install_from=task.outputs[:])
248 self.source = []
250 def configure(self):
252 Try to find the rst programs.
254 Do not raise any error if they are not found.
255 You'll have to use additional code in configure() to die
256 if programs were not found.
258 for p in rst_progs:
259 self.find_program(p, mandatory=False)