OLD | NEW |
1 """SCons.Scanner.LaTeX | 1 """SCons.Scanner.LaTeX |
2 | 2 |
3 This module implements the dependency scanner for LaTeX code. | 3 This module implements the dependency scanner for LaTeX code. |
4 | 4 |
5 """ | 5 """ |
6 | 6 |
7 # | 7 # |
8 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundat
ion | 8 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundat
ion |
9 # | 9 # |
10 # Permission is hereby granted, free of charge, to any person obtaining | 10 # Permission is hereby granted, free of charge, to any person obtaining |
11 # a copy of this software and associated documentation files (the | 11 # a copy of this software and associated documentation files (the |
12 # "Software"), to deal in the Software without restriction, including | 12 # "Software"), to deal in the Software without restriction, including |
13 # without limitation the rights to use, copy, modify, merge, publish, | 13 # without limitation the rights to use, copy, modify, merge, publish, |
14 # distribute, sublicense, and/or sell copies of the Software, and to | 14 # distribute, sublicense, and/or sell copies of the Software, and to |
15 # permit persons to whom the Software is furnished to do so, subject to | 15 # permit persons to whom the Software is furnished to do so, subject to |
16 # the following conditions: | 16 # the following conditions: |
17 # | 17 # |
18 # The above copyright notice and this permission notice shall be included | 18 # The above copyright notice and this permission notice shall be included |
19 # in all copies or substantial portions of the Software. | 19 # in all copies or substantial portions of the Software. |
20 # | 20 # |
21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | 21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
22 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 22 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
23 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 23 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
24 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | 24 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
25 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | 25 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
26 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | 26 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
28 # | 28 # |
29 | 29 |
30 __revision__ = "src/engine/SCons/Scanner/LaTeX.py 3603 2008/10/10 05:46:45 scons
" | 30 __revision__ = "src/engine/SCons/Scanner/LaTeX.py 3842 2008/12/20 22:59:52 scons
" |
31 | 31 |
32 import os.path | 32 import os.path |
33 import string | 33 import string |
34 import re | 34 import re |
35 | 35 |
36 import SCons.Scanner | 36 import SCons.Scanner |
| 37 import SCons.Util |
| 38 |
| 39 # list of graphics file extensions for TeX and LaTeX |
| 40 TexGraphics = ['.eps', '.ps'] |
| 41 LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] |
| 42 |
| 43 # Used as a return value of modify_env_var if the variable is not set. |
| 44 class _Null: |
| 45 pass |
| 46 _null = _Null |
| 47 |
| 48 # The user specifies the paths in env[variable], similar to other builders. |
| 49 # They may be relative and must be converted to absolute, as expected |
| 50 # by LaTeX and Co. The environment may already have some paths in |
| 51 # env['ENV'][var]. These paths are honored, but the env[var] paths have |
| 52 # higher precedence. All changes are un-done on exit. |
| 53 def modify_env_var(env, var, abspath): |
| 54 try: |
| 55 save = env['ENV'][var] |
| 56 except KeyError: |
| 57 save = _null |
| 58 env.PrependENVPath(var, abspath) |
| 59 try: |
| 60 if SCons.Util.is_List(env[var]): |
| 61 #TODO(1.5) |
| 62 #env.PrependENVPath(var, [os.path.abspath(str(p)) for p in env[var]]
) |
| 63 env.PrependENVPath(var, map(lambda p: os.path.abspath(str(p)), env[v
ar])) |
| 64 else: |
| 65 # Split at os.pathsep to convert into absolute path |
| 66 #TODO(1.5) env.PrependENVPath(var, [os.path.abspath(p) for p in str(
env[var]).split(os.pathsep)]) |
| 67 env.PrependENVPath(var, map(lambda p: os.path.abspath(p), string.spl
it(str(env[var]), os.pathsep))) |
| 68 except KeyError: |
| 69 pass |
| 70 |
| 71 # Convert into a string explicitly to append ":" (without which it won't sea
rch system |
| 72 # paths as well). The problem is that env.AppendENVPath(var, ":") |
| 73 # does not work, refuses to append ":" (os.pathsep). |
| 74 |
| 75 if SCons.Util.is_List(env['ENV'][var]): |
| 76 # TODO(1.5) |
| 77 #env['ENV'][var] = os.pathsep.join(env['ENV'][var]) |
| 78 env['ENV'][var] = string.join(env['ENV'][var], os.pathsep) |
| 79 # Append the trailing os.pathsep character here to catch the case with no en
v[var] |
| 80 env['ENV'][var] = env['ENV'][var] + os.pathsep |
| 81 |
| 82 return save |
| 83 |
| 84 class FindENVPathDirs: |
| 85 """A class to bind a specific *PATH variable name to a function that |
| 86 will return all of the *path directories.""" |
| 87 def __init__(self, variable): |
| 88 self.variable = variable |
| 89 def __call__(self, env, dir=None, target=None, source=None, argument=None): |
| 90 import SCons.PathList |
| 91 try: |
| 92 path = env['ENV'][self.variable] |
| 93 except KeyError: |
| 94 return () |
| 95 |
| 96 dir = dir or env.fs._cwd |
| 97 path = SCons.PathList.PathList(path).subst_path(env, target, source) |
| 98 return tuple(dir.Rfindalldirs(path)) |
| 99 |
| 100 |
37 | 101 |
38 def LaTeXScanner(): | 102 def LaTeXScanner(): |
39 """Return a prototype Scanner instance for scanning LaTeX source files | 103 """Return a prototype Scanner instance for scanning LaTeX source files |
40 when built with latex. | 104 when built with latex. |
41 """ | 105 """ |
42 ds = LaTeX(name = "LaTeXScanner", | 106 ds = LaTeX(name = "LaTeXScanner", |
43 suffixes = '$LATEXSUFFIXES', | 107 suffixes = '$LATEXSUFFIXES', |
44 # in the search order, see below in LaTeX class docstring | 108 # in the search order, see below in LaTeX class docstring |
45 graphics_extensions = ['.eps', '.ps'], | 109 graphics_extensions = TexGraphics, |
46 recursive = 0) | 110 recursive = 0) |
47 return ds | 111 return ds |
48 | 112 |
49 def PDFLaTeXScanner(): | 113 def PDFLaTeXScanner(): |
50 """Return a prototype Scanner instance for scanning LaTeX source files | 114 """Return a prototype Scanner instance for scanning LaTeX source files |
51 when built with pdflatex. | 115 when built with pdflatex. |
52 """ | 116 """ |
53 ds = LaTeX(name = "PDFLaTeXScanner", | 117 ds = LaTeX(name = "PDFLaTeXScanner", |
54 suffixes = '$LATEXSUFFIXES', | 118 suffixes = '$LATEXSUFFIXES', |
55 # in the search order, see below in LaTeX class docstring | 119 # in the search order, see below in LaTeX class docstring |
56 graphics_extensions = ['.pdf', '.png', '.jpg', '.gif', '.tif'], | 120 graphics_extensions = LatexGraphics, |
57 recursive = 0) | 121 recursive = 0) |
58 return ds | 122 return ds |
59 | 123 |
60 class LaTeX(SCons.Scanner.Base): | 124 class LaTeX(SCons.Scanner.Base): |
61 """Class for scanning LaTeX files for included files. | 125 """Class for scanning LaTeX files for included files. |
62 | 126 |
63 Unlike most scanners, which use regular expressions that just | 127 Unlike most scanners, which use regular expressions that just |
64 return the included file name, this returns a tuple consisting | 128 return the included file name, this returns a tuple consisting |
65 of the keyword for the inclusion ("include", "includegraphics", | 129 of the keyword for the inclusion ("include", "includegraphics", |
66 "input", or "bibliography"), and then the file name itself. | 130 "input", or "bibliography"), and then the file name itself. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 hides multiple instances of FindPathDirs, one per the LaTeX path | 189 hides multiple instances of FindPathDirs, one per the LaTeX path |
126 variable in the environment. When invoked, the function calculates | 190 variable in the environment. When invoked, the function calculates |
127 and returns all the required paths as a dictionary (converted into | 191 and returns all the required paths as a dictionary (converted into |
128 a tuple to become hashable). Then the scan function converts it | 192 a tuple to become hashable). Then the scan function converts it |
129 back and uses a dictionary of tuples rather than a single tuple | 193 back and uses a dictionary of tuples rather than a single tuple |
130 of paths. | 194 of paths. |
131 """ | 195 """ |
132 def __init__(self, dictionary): | 196 def __init__(self, dictionary): |
133 self.dictionary = {} | 197 self.dictionary = {} |
134 for k,n in dictionary.items(): | 198 for k,n in dictionary.items(): |
135 self.dictionary[k] = SCons.Scanner.FindPathDirs(n) | 199 self.dictionary[k] = ( SCons.Scanner.FindPathDirs(n), |
| 200 FindENVPathDirs(n) ) |
136 | 201 |
137 def __call__(self, env, dir=None, target=None, source=None, | 202 def __call__(self, env, dir=None, target=None, source=None, |
138 argument=None): | 203 argument=None): |
139 di = {} | 204 di = {} |
140 for k,c in self.dictionary.items(): | 205 for k,(c,cENV) in self.dictionary.items(): |
141 di[k] = c(env, dir=None, target=None, source=None, | 206 di[k] = ( c(env, dir=None, target=None, source=None, |
142 argument=None) | 207 argument=None) , |
| 208 cENV(env, dir=None, target=None, source=None, |
| 209 argument=None) ) |
143 # To prevent "dict is not hashable error" | 210 # To prevent "dict is not hashable error" |
144 return tuple(di.items()) | 211 return tuple(di.items()) |
145 | 212 |
146 class LaTeXScanCheck: | 213 class LaTeXScanCheck: |
147 """Skip all but LaTeX source files, i.e., do not scan *.eps, | 214 """Skip all but LaTeX source files, i.e., do not scan *.eps, |
148 *.pdf, *.jpg, etc. | 215 *.pdf, *.jpg, etc. |
149 """ | 216 """ |
150 def __init__(self, suffixes): | 217 def __init__(self, suffixes): |
151 self.suffixes = suffixes | 218 self.suffixes = suffixes |
152 def __call__(self, node, env): | 219 def __call__(self, node, env): |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 def sort_key(self, include): | 257 def sort_key(self, include): |
191 return SCons.Node.FS._my_normcase(str(include)) | 258 return SCons.Node.FS._my_normcase(str(include)) |
192 | 259 |
193 def find_include(self, include, source_dir, path): | 260 def find_include(self, include, source_dir, path): |
194 try: | 261 try: |
195 sub_path = path[include[0]] | 262 sub_path = path[include[0]] |
196 except (IndexError, KeyError): | 263 except (IndexError, KeyError): |
197 sub_path = () | 264 sub_path = () |
198 try_names = self._latex_names(include) | 265 try_names = self._latex_names(include) |
199 for n in try_names: | 266 for n in try_names: |
200 i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path) | 267 # see if we find it using the path in env[var] |
| 268 i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[0]) |
| 269 if i: |
| 270 return i, include |
| 271 # see if we find it using the path in env['ENV'][var] |
| 272 i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[1]) |
201 if i: | 273 if i: |
202 return i, include | 274 return i, include |
203 return i, include | 275 return i, include |
204 | 276 |
205 def scan(self, node, path=()): | 277 def scan(self, node, path=()): |
206 # Modify the default scan function to allow for the regular | 278 # Modify the default scan function to allow for the regular |
207 # expression to return a comma separated list of file names | 279 # expression to return a comma separated list of file names |
208 # as can be the case with the bibliography keyword. | 280 # as can be the case with the bibliography keyword. |
209 | 281 |
210 # Cache the includes list in node so we only scan it once: | 282 # Cache the includes list in node so we only scan it once: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 if include[0] != 'usepackage': | 325 if include[0] != 'usepackage': |
254 SCons.Warnings.warn(SCons.Warnings.DependencyWarning, | 326 SCons.Warnings.warn(SCons.Warnings.DependencyWarning, |
255 "No dependency generated for file: %s (i
ncluded from: %s) -- file not found" % (i, node)) | 327 "No dependency generated for file: %s (i
ncluded from: %s) -- file not found" % (i, node)) |
256 else: | 328 else: |
257 sortkey = self.sort_key(n) | 329 sortkey = self.sort_key(n) |
258 nodes.append((sortkey, n)) | 330 nodes.append((sortkey, n)) |
259 # | 331 # |
260 nodes.sort() | 332 nodes.sort() |
261 nodes = map(lambda pair: pair[1], nodes) | 333 nodes = map(lambda pair: pair[1], nodes) |
262 return nodes | 334 return nodes |
OLD | NEW |