Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: cms/sources.py

Issue 29327966: Issue 3084 - [cms] Show full tracebacks for exceptions passing template code (Closed)
Left Patch Set: Created Sept. 15, 2015, 5:37 p.m.
Right Patch Set: Unpack converter source before calling get_html() Created Sept. 17, 2015, 10 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « cms/converters.py ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # coding: utf-8 1 # coding: utf-8
2 2
3 # This file is part of the Adblock Plus web scripts, 3 # This file is part of the Adblock Plus web scripts,
4 # Copyright (C) 2006-2015 Eyeo GmbH 4 # Copyright (C) 2006-2015 Eyeo GmbH
5 # 5 #
6 # Adblock Plus is free software: you can redistribute it and/or modify 6 # Adblock Plus is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 3 as 7 # it under the terms of the GNU General Public License version 3 as
8 # published by the Free Software Foundation. 8 # published by the Free Software Foundation.
9 # 9 #
10 # Adblock Plus is distributed in the hope that it will be useful, 10 # Adblock Plus is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details. 13 # GNU General Public License for more details.
14 # 14 #
15 # You should have received a copy of the GNU General Public License 15 # You should have received a copy of the GNU General Public License
16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
17 17
18 import codecs 18 import io
19 import collections 19 import collections
20 import ConfigParser 20 import ConfigParser
21 import json 21 import json
22 import os 22 import os
23 from StringIO import StringIO 23 from StringIO import StringIO
24 import subprocess 24 import subprocess
25 import urlparse 25 import urlparse
26 import zipfile 26 import zipfile
27 import logging 27 import logging
28
29 import jinja2
30
31 TEMPLATE_SUFFIX = '.tmpl'
32
33 class SuffixTemplateLoader(jinja2.BaseLoader):
34 def __init__(self, loader, suffix=TEMPLATE_SUFFIX):
35 self.loader = loader
36 self.suffix = suffix
37
38 def get_source(self, environment, template):
39 return self.loader.get_source(environment, template + self.suffix)
40 28
41 class Source: 29 class Source:
42 def resolve_link(self, url, locale): 30 def resolve_link(self, url, locale):
43 parsed = urlparse.urlparse(url) 31 parsed = urlparse.urlparse(url)
44 page = parsed.path 32 page = parsed.path
45 if parsed.scheme != "" or page.startswith("/") or page.startswith("."): 33 if parsed.scheme != "" or page.startswith("/") or page.startswith("."):
46 # Not a page link 34 # Not a page link
47 return None, None 35 return None, None
48 36
49 if page == "" and url != "": 37 if page == "" and url != "":
(...skipping 18 matching lines...) Expand all
68 logging.warning("Link to %s cannot be resolved", page) 56 logging.warning("Link to %s cannot be resolved", page)
69 57
70 parts = page.split("/") 58 parts = page.split("/")
71 if parts[-1] == default_page: 59 if parts[-1] == default_page:
72 page = "/".join(parts[:-1]) 60 page = "/".join(parts[:-1])
73 61
74 path = "/%s/%s" % (locale, page) 62 path = "/%s/%s" % (locale, page)
75 return locale, urlparse.urlunparse(parsed[0:2] + (path,) + parsed[3:]) 63 return locale, urlparse.urlunparse(parsed[0:2] + (path,) + parsed[3:])
76 64
77 def read_config(self): 65 def read_config(self):
78 configdata = self.read_file("settings.ini") 66 configdata = self.read_file("settings.ini")[0]
79 config = ConfigParser.SafeConfigParser() 67 config = ConfigParser.SafeConfigParser()
80 config.readfp(StringIO(configdata)) 68 config.readfp(StringIO(configdata))
81 return config 69 return config
82 70
83 def import_symbol(self, filename, symbol): 71 def exec_file(self, filename):
84 code = self.read_file(filename) 72 source, filename = self.read_file(filename)
73 code = compile(source, filename, "exec")
85 namespace = {} 74 namespace = {}
86 exec code in namespace 75 exec code in namespace
87 76 return namespace
88 try:
89 return namespace[symbol]
90 except KeyError:
91 raise Exception("Expected symbol %s not found in %s" % (symbol, filename))
92 77
93 # 78 #
94 # Page helpers 79 # Page helpers
95 # 80 #
96 81
97 @staticmethod 82 @staticmethod
98 def page_filename(page, format): 83 def page_filename(page, format):
99 return "pages/%s.%s" % (page, format) 84 return "pages/%s.%s" % (page, format)
100 85
101 def list_pages(self): 86 def list_pages(self):
(...skipping 27 matching lines...) Expand all
129 default_locale = self.read_config().get("general", "defaultlocale") 114 default_locale = self.read_config().get("general", "defaultlocale")
130 return filter( 115 return filter(
131 lambda f: os.path.splitext(f)[1].lower() != ".json", 116 lambda f: os.path.splitext(f)[1].lower() != ".json",
132 self.list_files("locales/%s" % default_locale) 117 self.list_files("locales/%s" % default_locale)
133 ) 118 )
134 119
135 def has_localizable_file(self, locale, filename): 120 def has_localizable_file(self, locale, filename):
136 return self.has_file(self.localizable_file_filename(locale, filename)) 121 return self.has_file(self.localizable_file_filename(locale, filename))
137 122
138 def read_localizable_file(self, locale, filename): 123 def read_localizable_file(self, locale, filename):
139 return self.read_file(self.localizable_file_filename(locale, filename), bina ry=True) 124 return self.read_file(self.localizable_file_filename(locale, filename), bina ry=True)[0]
140 125
141 # 126 #
142 # Static file helpers 127 # Static file helpers
143 # 128 #
144 129
145 @staticmethod 130 @staticmethod
146 def static_filename(filename): 131 def static_filename(filename):
147 return "static/%s" % filename 132 return "static/%s" % filename
148 133
149 def list_static(self): 134 def list_static(self):
150 return self.list_files("static") 135 return self.list_files("static")
151 136
152 def has_static(self, filename): 137 def has_static(self, filename):
153 return self.has_file(self.static_filename(filename)) 138 return self.has_file(self.static_filename(filename))
154 139
155 def read_static(self, filename): 140 def read_static(self, filename):
156 return self.read_file(self.static_filename(filename), binary=True) 141 return self.read_file(self.static_filename(filename), binary=True)[0]
157 142
158 # 143 #
159 # Locale helpers 144 # Locale helpers
160 # 145 #
161 146
162 @classmethod 147 @classmethod
163 def locale_filename(cls, locale, page): 148 def locale_filename(cls, locale, page):
164 return cls.localizable_file_filename(locale, page + ".json") 149 return cls.localizable_file_filename(locale, page + ".json")
165 150
166 def list_locales(self): 151 def list_locales(self):
(...skipping 12 matching lines...) Expand all
179 pass 164 pass
180 return self.has_file(self.locale_filename(locale, page)) 165 return self.has_file(self.locale_filename(locale, page))
181 166
182 def read_locale(self, locale, page): 167 def read_locale(self, locale, page):
183 default_locale = self.read_config().get("general", "defaultlocale") 168 default_locale = self.read_config().get("general", "defaultlocale")
184 result = collections.OrderedDict() 169 result = collections.OrderedDict()
185 if locale != default_locale: 170 if locale != default_locale:
186 result.update(self.read_locale(default_locale, page)) 171 result.update(self.read_locale(default_locale, page))
187 172
188 if self.has_locale(locale, page): 173 if self.has_locale(locale, page):
189 filedata = self.read_file(self.locale_filename(locale, page)) 174 filedata = self.read_file(self.locale_filename(locale, page))[0]
190 localedata = json.loads(filedata) 175 localedata = json.loads(filedata)
191 for key, value in localedata.iteritems(): 176 for key, value in localedata.iteritems():
192 result[key] = value["message"] 177 result[key] = value["message"]
193 178
194 return result 179 return result
195 180
196 # 181 #
197 # Template helpers 182 # Template helpers
198 # 183 #
199 184
200 @staticmethod 185 @staticmethod
201 def template_filename(template): 186 def template_filename(template):
202 return "templates/%s%s" % (template, TEMPLATE_SUFFIX) 187 return "templates/%s.tmpl" % template
203 188
204 def read_template(self, template): 189 def read_template(self, template):
205 return self.read_file(self.template_filename(template)) 190 return self.read_file(self.template_filename(template))
206
207 def get_template_loader(self):
208 return SuffixTemplateLoader(jinja2.FunctionLoader(self.read_file))
209 191
210 # 192 #
211 # Include helpers 193 # Include helpers
212 # 194 #
213 195
214 @staticmethod 196 @staticmethod
215 def include_filename(include, format): 197 def include_filename(include, format):
216 return "includes/%s.%s" % (include, format) 198 return "includes/%s.%s" % (include, format)
217 199
218 def has_include(self, include, format): 200 def has_include(self, include, format):
(...skipping 25 matching lines...) Expand all
244 self._archive.close() 226 self._archive.close()
245 227
246 def has_file(self, filename): 228 def has_file(self, filename):
247 try: 229 try:
248 self._archive.getinfo("./%s" % filename) 230 self._archive.getinfo("./%s" % filename)
249 except KeyError: 231 except KeyError:
250 return False 232 return False
251 return True 233 return True
252 234
253 def read_file(self, filename, binary=False): 235 def read_file(self, filename, binary=False):
254 result = self._archive.read("./%s" % filename) 236 data = self._archive.read("./%s" % filename)
255 if not binary: 237 if not binary:
256 result = result.decode("utf-8") 238 data = data.decode("utf-8")
257 return result 239 return (data, "%s!%s" % (self._name, filename))
258 240
259 def list_files(self, subdir): 241 def list_files(self, subdir):
260 prefix = "./%s/" % subdir 242 prefix = "./%s/" % subdir
261 for filename in self._archive.namelist(): 243 for filename in self._archive.namelist():
262 if filename.startswith(prefix): 244 if filename.startswith(prefix):
263 yield filename[len(prefix):] 245 yield filename[len(prefix):]
264 246
265 if os.name == "posix": 247 if os.name == "posix":
266 def get_cache_dir(self): 248 def get_cache_dir(self):
267 return "/var/cache/" + self._name 249 return "/var/cache/" + self._name
(...skipping 11 matching lines...) Expand all
279 def close(self): 261 def close(self):
280 pass 262 pass
281 263
282 def get_path(self, filename): 264 def get_path(self, filename):
283 return os.path.join(self._dir, *filename.split("/")) 265 return os.path.join(self._dir, *filename.split("/"))
284 266
285 def has_file(self, filename): 267 def has_file(self, filename):
286 return os.path.isfile(self.get_path(filename)) 268 return os.path.isfile(self.get_path(filename))
287 269
288 def read_file(self, filename, binary=False): 270 def read_file(self, filename, binary=False):
289 encoding = None if binary else "utf-8" 271 path = self.get_path(filename)
290 with codecs.open(self.get_path(filename), "rb", encoding=encoding) as handle : 272
291 return handle.read() 273 if binary:
274 file = open(path, "rb")
275 else:
276 file = io.open(path, "r", encoding="utf-8")
277
278 with file:
279 return (file.read(), path)
292 280
293 def list_files(self, subdir): 281 def list_files(self, subdir):
294 result = [] 282 result = []
295 def do_list(dir, relpath): 283 def do_list(dir, relpath):
296 try: 284 try:
297 files = os.listdir(dir) 285 files = os.listdir(dir)
298 except OSError: 286 except OSError:
299 return 287 return
300 288
301 for filename in files: 289 for filename in files:
302 path = os.path.join(dir, filename) 290 path = os.path.join(dir, filename)
303 if os.path.isfile(path): 291 if os.path.isfile(path):
304 result.append(relpath + filename) 292 result.append(relpath + filename)
305 elif os.path.isdir(path): 293 elif os.path.isdir(path):
306 do_list(path, relpath + filename + "/") 294 do_list(path, relpath + filename + "/")
307 do_list(self.get_path(subdir), "") 295 do_list(self.get_path(subdir), "")
308 return result 296 return result
309 297
310 def get_cache_dir(self): 298 def get_cache_dir(self):
311 return os.path.join(self._dir, "cache") 299 return os.path.join(self._dir, "cache")
312
313 def get_template_loader(self):
314 return SuffixTemplateLoader(jinja2.FileSystemLoader(self._dir))
Sebastian Noack 2015/09/15 17:48:36 We need a loader that is aware of the filename for
LEFTRIGHT

Powered by Google App Engine
This is Rietveld