comparison piecrust/page.py @ 49:fce061f8c2ed

Fix cache validation issue with rendered segments, limit disk access.
author Ludovic Chabant <ludovic@chabant.com>
date Fri, 22 Aug 2014 20:26:05 -0700
parents 343d08ef5668
children 563ce5dd02af
comparison
equal deleted inserted replaced
48:002fa58f54dc 49:fce061f8c2ed
5 import os.path 5 import os.path
6 import hashlib 6 import hashlib
7 import logging 7 import logging
8 import datetime 8 import datetime
9 import dateutil.parser 9 import dateutil.parser
10 from werkzeug.utils import cached_property
10 from piecrust.configuration import (Configuration, ConfigurationError, 11 from piecrust.configuration import (Configuration, ConfigurationError,
11 parse_config_header) 12 parse_config_header)
12 from piecrust.environment import PHASE_PAGE_PARSING 13 from piecrust.environment import PHASE_PAGE_PARSING
13 14
14 15
34 class Page(object): 35 class Page(object):
35 def __init__(self, source, source_metadata, rel_path): 36 def __init__(self, source, source_metadata, rel_path):
36 self.source = source 37 self.source = source
37 self.source_metadata = source_metadata 38 self.source_metadata = source_metadata
38 self.rel_path = rel_path 39 self.rel_path = rel_path
39 self.path = source.resolveRef(rel_path)
40 self._config = None 40 self._config = None
41 self._raw_content = None 41 self._raw_content = None
42 self._datetime = None 42 self._datetime = None
43 43
44 @property 44 @property
46 return self.source.app 46 return self.source.app
47 47
48 @property 48 @property
49 def ref_spec(self): 49 def ref_spec(self):
50 return '%s:%s' % (self.source.name, self.rel_path) 50 return '%s:%s' % (self.source.name, self.rel_path)
51
52 @cached_property
53 def path(self):
54 return self.source.resolveRef(self.rel_path)
55
56 @cached_property
57 def path_mtime(self):
58 return os.path.getmtime(self.path)
51 59
52 @property 60 @property
53 def config(self): 61 def config(self):
54 self._load() 62 self._load()
55 return self._config 63 return self._config
77 page_time = datetime.time(time_dt.hour, time_dt.minute, time_dt.second) 85 page_time = datetime.time(time_dt.hour, time_dt.minute, time_dt.second)
78 else: 86 else:
79 page_time = datetime.time(0, 0, 0) 87 page_time = datetime.time(0, 0, 0)
80 self._datetime = datetime.datetime.combine(page_date, page_time) 88 self._datetime = datetime.datetime.combine(page_date, page_time)
81 else: 89 else:
82 self._datetime = datetime.datetime.fromtimestamp(os.path.getmtime(self.path)) 90 self._datetime = datetime.datetime.fromtimestamp(self.path_mtime)
83 return self._datetime 91 return self._datetime
84 92
85 @datetime.setter 93 @datetime.setter
86 def datetime(self, value): 94 def datetime(self, value):
87 self._datetime = value 95 self._datetime = value
94 return 102 return
95 103
96 eis = self.app.env.exec_info_stack 104 eis = self.app.env.exec_info_stack
97 eis.pushPage(self, PHASE_PAGE_PARSING, None) 105 eis.pushPage(self, PHASE_PAGE_PARSING, None)
98 try: 106 try:
99 config, content = load_page(self.app, self.path) 107 config, content = load_page(self.app, self.path, self.path_mtime)
100 self._config = config 108 self._config = config
101 self._raw_content = content 109 self._raw_content = content
102 finally: 110 finally:
103 eis.popPage() 111 eis.popPage()
104 112
152 seg_data.append(p_data) 160 seg_data.append(p_data)
153 data[key] = seg_data 161 data[key] = seg_data
154 return data 162 return data
155 163
156 164
157 def load_page(app, path): 165 def load_page(app, path, path_mtime=None):
158 try: 166 try:
159 return _do_load_page(app, path) 167 return _do_load_page(app, path, path_mtime)
160 except Exception as e: 168 except Exception as e:
161 logger.exception("Error loading page: %s" % 169 logger.exception("Error loading page: %s" %
162 os.path.relpath(path, app.root_dir)) 170 os.path.relpath(path, app.root_dir))
163 _, __, traceback = sys.exc_info() 171 _, __, traceback = sys.exc_info()
164 raise PageLoadingError(path, e).with_traceback(traceback) 172 raise PageLoadingError(path, e).with_traceback(traceback)
165 173
166 174
167 def _do_load_page(app, path): 175 def _do_load_page(app, path, path_mtime):
168 exec_info = app.env.exec_info_stack.current_page_info 176 exec_info = app.env.exec_info_stack.current_page_info
169 if exec_info is None: 177 if exec_info is None:
170 raise Exception("Loading page '%s' but not execution context has " 178 raise Exception("Loading page '%s' but not execution context has "
171 "been created for it." % path) 179 "been created for it." % path)
172 180
173 # Check the cache first. 181 # Check the cache first.
174 cache = app.cache.getCache('pages') 182 cache = app.cache.getCache('pages')
175 cache_path = "%s.json" % hashlib.md5(path.encode('utf8')).hexdigest() 183 cache_path = "%s.json" % hashlib.md5(path.encode('utf8')).hexdigest()
176 page_time = os.path.getmtime(path) 184 page_time = path_mtime or os.path.getmtime(path)
177 if cache.isValid(cache_path, page_time): 185 if cache.isValid(cache_path, page_time):
178 exec_info.was_cache_valid = True 186 exec_info.was_cache_valid = True
179 cache_data = json.loads(cache.read(cache_path)) 187 cache_data = json.loads(cache.read(cache_path))
180 config = PageConfiguration(values=cache_data['config'], 188 config = PageConfiguration(values=cache_data['config'],
181 validate=False) 189 validate=False)