handle empty pykpathsea results
[PyX/mjg.git] / pyx / filelocator.py
blob1d9f08549861c3bf3633f7b9b06623765b614ec6
1 builtinopen = open
3 import os, cStringIO, warnings
5 import config, pycompat
8 # Locator methods implement a open method similar to the builtin open
9 # function by searching for a file according to a specific rule.
11 locator_classes = {}
13 class local:
14 # locates files in the current directory
16 def opener(self, filename, formats, mode):
17 return lambda: builtinopen(filename, mode)
19 locator_classes["local"] = local
22 class internal:
23 # locates files within the pyx data tree
25 def opener(self, filename, formats, mode):
26 extension = os.path.splitext(filename)[1][1:]
27 if not extension:
28 return None
29 try:
30 import pkgutil
31 raise ImportError
32 except ImportError:
33 return lambda: builtinopen(os.path.join(os.path.dirname(__file__), "data", extension, filename), mode)
34 else:
35 try:
36 data = pkgutil.get_data("pyx", "data/%s/%s" % (extension, filename))
37 except IOError:
38 return None
39 else:
40 if data:
41 # ignoring mode?!
42 return lambda: cStringIO.StringIO(data)
44 locator_classes["internal"] = internal
47 class recursivedir:
48 # locates files by searching recursively in a list of directories
50 def __init__(self):
51 self.dirs = config.getlist("locator", "recursivedir")
52 self.full_filenames = {}
54 def opener(self, filename, formats, mode):
55 if filename in self.full_filenames:
56 return lambda: builtinopen(self.full_filenames[filename], mode)
57 while self.dirs:
58 dir = self.dirs.pop(0)
59 for item in os.listdir(dir):
60 full_item = os.path.join(dir, item)
61 if os.path.isdir(full_item):
62 self.dirs.insert(0, full_item)
63 else:
64 self.full_filenames[item] = full_item
65 if filename in self.full_filenames:
66 return lambda: builtinopen(self.full_filenames[filename], mode)
68 locator_classes["recursivedir"] = recursivedir
71 class ls_R:
72 # locates files by searching a list of ls-R files
74 def __init__(self):
75 self.ls_Rs = config.getlist("locator", "ls-R")
76 self.full_filenames = {}
78 def opener(self, filename, formats, mode):
79 while self.ls_Rs and filename not in self.full_filenames:
80 lsr = self.ls_Rs.pop(0)
81 base_dir = os.path.dirname(lsr)
82 dir = None
83 first = True
84 for line in builtinopen(lsr):
85 line = line.rstrip()
86 if first and line.startswith("%"):
87 continue
88 first = False
89 if line.endswith(":"):
90 dir = os.path.join(base_dir, line[:-1])
91 elif line:
92 self.full_filenames[line] = os.path.join(dir, line)
93 if filename in self.full_filenames:
94 def _opener():
95 try:
96 return builtinopen(self.full_filenames[filename], mode)
97 except IOError:
98 warnings.warn("'%s' should be available at '%s' according to the ls-R file, "
99 "but the file is not available at this location; "
100 "update your ls-R file" % (filename, self.full_filenames[filename]))
101 return _opener
103 locator_classes["ls-R"] = ls_R
106 class pykpathsea:
108 def opener(self, filename, formats, mode):
109 import pykpathsea
110 for format in formats:
111 full_filename = pykpathsea.find_file(filename, format)
112 if full_filename:
113 break
114 else:
115 return
116 return lambda: builtinopen(full_filename, mode)
118 locator_classes["pykpathsea"] = pykpathsea
121 # class libkpathsea:
122 # # locate files by libkpathsea using ctypes
124 # def opener(self, filename, formats, mode):
125 # pass
127 # locator_classes["libpathsea"] = libkpathsea
130 class kpsewhich:
132 def opener(self, filename, formats, mode):
133 for format in formats:
134 try:
135 full_filenames = os.popen('kpsewhich --format="%s" "%s"' % (format, filename)).read()
136 except OSError:
137 return
138 if full_filenames:
139 break
140 else:
141 return
142 full_filename = full_filenames.split("\n")[0]
143 def _opener():
144 try:
145 return builtinopen(full_filename, mode)
146 except IOError:
147 warnings.warn("'%s' should be available at '%s' according to kpsewhich, "
148 "but the file is not available at this location; "
149 "update your kpsewhich database" % (filename, full_filename))
150 return _opener
152 locator_classes["kpsewhich"] = kpsewhich
155 class locate:
157 def opener(self, filename, formats, mode):
158 try:
159 full_filenames = os.popen("locate \"%s\"" % filename).read()
160 except OSError:
161 return
162 if not full_filenames:
163 return
164 full_filename = full_filenames.split("\n")[0]
165 def _opener():
166 try:
167 return builtinopen(full_filenames, mode)
168 except IOError:
169 warnings.warn("'%s' should be available at '%s' according to the locate database, "
170 "but the file is not available at this location; "
171 "update your locate database" % (filename, self.full_filenames[filename]))
172 return _opener
174 locator_classes["locate"] = locate
177 methods = [locator_classes[method]()
178 for method in config.getlist("locator", "methods", "local internal pykpathsea kpsewhich locate")]
180 openers = {}
182 def open(filename, formats, mode="r"):
183 formats = tuple(formats)
184 if (filename, formats) in openers:
185 return openers[(filename, formats)]()
186 for method in methods:
187 opener = method.opener(filename, formats, mode)
188 if opener:
189 try:
190 file = opener()
191 except IOError:
192 file = None
193 if file:
194 openers[(filename, formats)] = opener
195 return file
196 raise IOError("Could not locate the file '%s'." % filename)
199 class format:
200 gf = "gf"
201 pk = "pk"
202 any_glyph = "bitmap font"
203 tfm = "tfm"
204 afm = "afm"
205 base = "base"
206 bib = "bib"
207 bst = "bst"
208 cnf = "cnf"
209 db = "ls-R"
210 fmt = "fmt"
211 fontmap = "map"
212 mem = "mem"
213 mf = "mf"
214 mfpool = "mfpool"
215 mft = "mft"
216 mp = "mp"
217 mppool = "mppool"
218 mpsupport = "MetaPost support"
219 ocp = "ocp"
220 ofm = "ofm"
221 opl = "opl"
222 otp = "otp"
223 ovf = "ovf"
224 ovp = "ovp"
225 pict = "graphics/figure"
226 tex = "tex"
227 texdoc = "TeX system documentation"
228 texpool = "texpool"
229 texsource = "TeX system sources"
230 tex_ps_header = "PostScript header"
231 troff_font = "Troff fonts"
232 type1 = "type1 fonts"
233 vf = "vf"
234 dvips_config = "dvips config"
235 ist = "ist"
236 truetype = "truetype fonts"
237 type42 = "type42 fonts"
238 web2c = "web2c files"
239 program_text = "other text files"
240 program_binary = "other binary files"
241 miscfonts = "misc fonts"
242 web = "web"
243 cweb = "cweb"
244 enc = "enc files"
245 cmap = "cmap files"
246 subfont_definition = "subfont definition files"
247 opentype = "opentype fonts"
248 pdftex_config = "pdftex config"
249 lig = "lig files"
250 texmfscripts = "texmfscripts"
251 lua = "lua"
252 font_feature = "font feature files"
253 cid_maps = "cid maps"
254 mlbib = "mlbib"
255 mlbst = "mlbst"