Move waf into third_party/.
[obnox/samba/samba-obnox.git] / third_party / waf / wafadmin / Tools / tex.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Thomas Nagy, 2006 (ita)
4
5 "TeX/LaTeX/PDFLaTeX support"
6
7 import os, re
8 import Utils, TaskGen, Task, Runner, Build
9 from TaskGen import feature, before
10 from Logs import error, warn, debug
11
12 re_tex = re.compile(r'\\(?P<type>include|input|import|bringin|lstinputlisting){(?P<file>[^{}]*)}', re.M)
13 def scan(self):
14         node = self.inputs[0]
15         env = self.env
16
17         nodes = []
18         names = []
19         if not node: return (nodes, names)
20
21         code = Utils.readf(node.abspath(env))
22
23         curdirnode = self.curdirnode
24         abs = curdirnode.abspath()
25         for match in re_tex.finditer(code):
26                 path = match.group('file')
27                 if path:
28                         for k in ['', '.tex', '.ltx']:
29                                 # add another loop for the tex include paths?
30                                 debug('tex: trying %s%s' % (path, k))
31                                 try:
32                                         os.stat(abs+os.sep+path+k)
33                                 except OSError:
34                                         continue
35                                 found = path+k
36                                 node = curdirnode.find_resource(found)
37                                 if node:
38                                         nodes.append(node)
39                         else:
40                                 debug('tex: could not find %s' % path)
41                                 names.append(path)
42
43         debug("tex: found the following : %s and names %s" % (nodes, names))
44         return (nodes, names)
45
46 latex_fun, _ = Task.compile_fun('latex', '${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False)
47 pdflatex_fun, _ = Task.compile_fun('pdflatex', '${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False)
48 bibtex_fun, _ = Task.compile_fun('bibtex', '${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}', shell=False)
49 makeindex_fun, _ = Task.compile_fun('bibtex', '${MAKEINDEX} ${MAKEINDEXFLAGS} ${SRCFILE}', shell=False)
50
51 g_bibtex_re = re.compile('bibdata', re.M)
52 def tex_build(task, command='LATEX'):
53         env = task.env
54         bld = task.generator.bld
55
56         if not env['PROMPT_LATEX']:
57                 env.append_value('LATEXFLAGS', '-interaction=batchmode')
58                 env.append_value('PDFLATEXFLAGS', '-interaction=batchmode')
59
60         fun = latex_fun
61         if command == 'PDFLATEX':
62                 fun = pdflatex_fun
63
64         node = task.inputs[0]
65         reldir  = node.bld_dir(env)
66
67         #lst = []
68         #for c in Utils.split_path(reldir):
69         #       if c: lst.append('..')
70         #srcfile = os.path.join(*(lst + [node.srcpath(env)]))
71         #sr2 = os.path.join(*(lst + [node.parent.srcpath(env)]))
72         srcfile = node.abspath(env)
73         sr2 = node.parent.abspath() + os.pathsep + node.parent.abspath(env) + os.pathsep
74
75         aux_node = node.change_ext('.aux')
76         idx_node = node.change_ext('.idx')
77
78         nm = aux_node.name
79         docuname = nm[ : len(nm) - 4 ] # 4 is the size of ".aux"
80
81         # important, set the cwd for everybody
82         task.cwd = task.inputs[0].parent.abspath(task.env)
83
84
85         warn('first pass on %s' % command)
86
87         task.env.env = {'TEXINPUTS': sr2}
88         task.env.SRCFILE = srcfile
89         ret = fun(task)
90         if ret:
91                 return ret
92
93         # look in the .aux file if there is a bibfile to process
94         try:
95                 ct = Utils.readf(aux_node.abspath(env))
96         except (OSError, IOError):
97                 error('error bibtex scan')
98         else:
99                 fo = g_bibtex_re.findall(ct)
100
101                 # there is a .aux file to process
102                 if fo:
103                         warn('calling bibtex')
104
105                         task.env.env = {'BIBINPUTS': sr2, 'BSTINPUTS': sr2}
106                         task.env.SRCFILE = docuname
107                         ret = bibtex_fun(task)
108                         if ret:
109                                 error('error when calling bibtex %s' % docuname)
110                                 return ret
111
112         # look on the filesystem if there is a .idx file to process
113         try:
114                 idx_path = idx_node.abspath(env)
115                 os.stat(idx_path)
116         except OSError:
117                 error('error file.idx scan')
118         else:
119                 warn('calling makeindex')
120
121                 task.env.SRCFILE = idx_node.name
122                 task.env.env = {}
123                 ret = makeindex_fun(task)
124                 if ret:
125                         error('error when calling makeindex %s' % idx_path)
126                         return ret
127
128
129         hash = ''
130         i = 0
131         while i < 10:
132                 # prevent against infinite loops - one never knows
133                 i += 1
134
135                 # watch the contents of file.aux
136                 prev_hash = hash
137                 try:
138                         hash = Utils.h_file(aux_node.abspath(env))
139                 except KeyError:
140                         error('could not read aux.h -> %s' % aux_node.abspath(env))
141                         pass
142
143                 # debug
144                 #print "hash is, ", hash, " ", old_hash
145
146                 # stop if file.aux does not change anymore
147                 if hash and hash == prev_hash:
148                         break
149
150                 # run the command
151                 warn('calling %s' % command)
152
153                 task.env.env = {'TEXINPUTS': sr2 + os.pathsep}
154                 task.env.SRCFILE = srcfile
155                 ret = fun(task)
156                 if ret:
157                         error('error when calling %s %s' % (command, latex_fun))
158                         return ret
159
160         return None # ok
161
162 latex_vardeps  = ['LATEX', 'LATEXFLAGS']
163 def latex_build(task):
164         return tex_build(task, 'LATEX')
165
166 pdflatex_vardeps  = ['PDFLATEX', 'PDFLATEXFLAGS']
167 def pdflatex_build(task):
168         return tex_build(task, 'PDFLATEX')
169
170 class tex_taskgen(TaskGen.task_gen):
171         def __init__(self, *k, **kw):
172                 TaskGen.task_gen.__init__(self, *k, **kw)
173
174 @feature('tex')
175 @before('apply_core')
176 def apply_tex(self):
177         if not getattr(self, 'type', None) in ['latex', 'pdflatex']:
178                 self.type = 'pdflatex'
179
180         tree = self.bld
181         outs = Utils.to_list(getattr(self, 'outs', []))
182
183         # prompt for incomplete files (else the batchmode is used)
184         self.env['PROMPT_LATEX'] = getattr(self, 'prompt', 1)
185
186         deps_lst = []
187
188         if getattr(self, 'deps', None):
189                 deps = self.to_list(self.deps)
190                 for filename in deps:
191                         n = self.path.find_resource(filename)
192                         if not n in deps_lst: deps_lst.append(n)
193
194         self.source = self.to_list(self.source)
195         for filename in self.source:
196                 base, ext = os.path.splitext(filename)
197
198                 node = self.path.find_resource(filename)
199                 if not node: raise Utils.WafError('cannot find %s' % filename)
200
201                 if self.type == 'latex':
202                         task = self.create_task('latex', node, node.change_ext('.dvi'))
203                 elif self.type == 'pdflatex':
204                         task = self.create_task('pdflatex', node, node.change_ext('.pdf'))
205
206                 task.env = self.env
207                 task.curdirnode = self.path
208
209                 # add the manual dependencies
210                 if deps_lst:
211                         variant = node.variant(self.env)
212                         try:
213                                 lst = tree.node_deps[task.unique_id()]
214                                 for n in deps_lst:
215                                         if not n in lst:
216                                                 lst.append(n)
217                         except KeyError:
218                                 tree.node_deps[task.unique_id()] = deps_lst
219
220                 if self.type == 'latex':
221                         if 'ps' in outs:
222                                 tsk = self.create_task('dvips', task.outputs, node.change_ext('.ps'))
223                                 tsk.env.env = {'TEXINPUTS' : node.parent.abspath() + os.pathsep + self.path.abspath() + os.pathsep + self.path.abspath(self.env)}
224                         if 'pdf' in outs:
225                                 tsk = self.create_task('dvipdf', task.outputs, node.change_ext('.pdf'))
226                                 tsk.env.env = {'TEXINPUTS' : node.parent.abspath() + os.pathsep + self.path.abspath() + os.pathsep + self.path.abspath(self.env)}
227                 elif self.type == 'pdflatex':
228                         if 'ps' in outs:
229                                 self.create_task('pdf2ps', task.outputs, node.change_ext('.ps'))
230         self.source = []
231
232 def detect(conf):
233         v = conf.env
234         for p in 'tex latex pdflatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split():
235                 conf.find_program(p, var=p.upper())
236                 v[p.upper()+'FLAGS'] = ''
237         v['DVIPSFLAGS'] = '-Ppdf'
238
239 b = Task.simple_task_type
240 b('tex', '${TEX} ${TEXFLAGS} ${SRC}', color='BLUE', shell=False) # not used anywhere
241 b('bibtex', '${BIBTEX} ${BIBTEXFLAGS} ${SRC}', color='BLUE', shell=False) # not used anywhere
242 b('dvips', '${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}', color='BLUE', after="latex pdflatex tex bibtex", shell=False)
243 b('dvipdf', '${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}', color='BLUE', after="latex pdflatex tex bibtex", shell=False)
244 b('pdf2ps', '${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}', color='BLUE', after="dvipdf pdflatex", shell=False)
245
246 b = Task.task_type_from_func
247 cls = b('latex', latex_build, vars=latex_vardeps)
248 cls.scan = scan
249 cls = b('pdflatex', pdflatex_build, vars=pdflatex_vardeps)
250 cls.scan = scan