comparison piecrust/sources/pageref.py @ 363:dd25bd3ce1f9

serve: Refactoring and fixes to be able to serve taxonomy pages. * Page sources' `findPagePath` is renamed to `findPageFactory`, so that it also returns source metadata. * Page refs now store possible hits more properly, and use the previous point to also store metadata. As a result, they can also return a proper factory. * Implement `findPageFactory` correctly in all built-in sources. * When the Chef server matches a taxonomy page, get the source metadata from the page ref in order to make a more proper page. * Make the `getRoute(s)` functions explicitely say if they want taxonomy routes or not.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 26 Apr 2015 15:07:40 -0700
parents f130365568ff
children 4b1019bb2533
comparison
equal deleted inserted replaced
362:ff595828a364 363:dd25bd3ce1f9
1 import re 1 import re
2 import os.path 2 import os.path
3 from piecrust.sources.base import PageFactory
3 4
4 5
5 page_ref_pattern = re.compile(r'(?P<src>[\w]+)\:(?P<path>.*?)(;|$)') 6 page_ref_pattern = re.compile(r'(?P<src>[\w]+)\:(?P<path>.*?)(;|$)')
6 7
7 8
11 12
12 class PageRef(object): 13 class PageRef(object):
13 """ A reference to a page, with support for looking a page in different 14 """ A reference to a page, with support for looking a page in different
14 realms. 15 realms.
15 """ 16 """
17 _INDEX_NEEDS_LOADING = -2
18 _INDEX_NOT_FOUND = -1
19
20 class _HitInfo(object):
21 def __init__(self, source_name, rel_path, path, metadata):
22 self.source_name = source_name
23 self.rel_path = rel_path
24 self.path = path
25 self.metadata = metadata
26
16 def __init__(self, app, page_ref): 27 def __init__(self, app, page_ref):
17 self.app = app 28 self.app = app
18 self._page_ref = page_ref 29 self._page_ref = page_ref
19 self._paths = None 30 self._hits = None
20 self._first_valid_path_index = -2 31 self._first_valid_hit_index = self._INDEX_NEEDS_LOADING
21 self._exts = list(app.config.get('site/auto_formats').keys()) 32 self._exts = list(app.config.get('site/auto_formats').keys())
22 33
23 @property 34 @property
24 def exists(self): 35 def exists(self):
25 try: 36 try:
26 self._checkPaths() 37 self._checkHits()
27 return True 38 return True
28 except PageNotFoundError: 39 except PageNotFoundError:
29 return False 40 return False
30 41
31 @property 42 @property
32 def source_name(self): 43 def source_name(self):
33 self._checkPaths() 44 self._checkHits()
34 return self._paths[self._first_valid_path_index][0] 45 return self._first_valid_hit.source_name
35 46
36 @property 47 @property
37 def source(self): 48 def source(self):
38 return self.app.getSource(self.source_name) 49 return self.app.getSource(self.source_name)
39 50
40 @property 51 @property
41 def rel_path(self): 52 def rel_path(self):
42 self._checkPaths() 53 self._checkHits()
43 return self._paths[self._first_valid_path_index][1] 54 return self._first_valid_hit.rel_path
44 55
45 @property 56 @property
46 def path(self): 57 def path(self):
47 self._checkPaths() 58 self._checkHits()
48 return self._paths[self._first_valid_path_index][2] 59 return self._first_valid_hit.path
60
61 @property
62 def metadata(self):
63 self._checkHits()
64 return self._first_valid_hit.metadata
49 65
50 @property 66 @property
51 def possible_rel_paths(self): 67 def possible_rel_paths(self):
52 self._load() 68 self._load()
53 return [p[1] for p in self._paths] 69 return [h.rel_path for h in self._hits]
54 70
55 @property 71 @property
56 def possible_paths(self): 72 def possible_paths(self):
57 self._load() 73 self._load()
58 return [p[2] for p in self._paths] 74 return [h.path for h in self._hits]
75
76 def getFactory(self):
77 return PageFactory(self.source, self.rel_path, self.metadata)
78
79 @property
80 def _first_valid_hit(self):
81 return self._hits[self._first_valid_hit_index]
59 82
60 def _load(self): 83 def _load(self):
61 if self._paths is not None: 84 if self._hits is not None:
62 return 85 return
63 86
64 it = list(page_ref_pattern.finditer(self._page_ref)) 87 it = list(page_ref_pattern.finditer(self._page_ref))
65 if len(it) == 0: 88 if len(it) == 0:
66 raise Exception("Invalid page ref: %s" % self._page_ref) 89 raise Exception("Invalid page ref: %s" % self._page_ref)
67 90
68 self._paths = [] 91 self._hits = []
69 for m in it: 92 for m in it:
70 source_name = m.group('src') 93 source_name = m.group('src')
71 source = self.app.getSource(source_name) 94 source = self.app.getSource(source_name)
72 if source is None: 95 if source is None:
73 raise Exception("No such source: %s" % source_name) 96 raise Exception("No such source: %s" % source_name)
74 rel_path = m.group('path') 97 rel_path = m.group('path')
75 path = source.resolveRef(rel_path) 98 path, metadata = source.resolveRef(rel_path)
76 if '%ext%' in rel_path: 99 if '%ext%' in rel_path:
77 for e in self._exts: 100 for e in self._exts:
78 self._paths.append( 101 self._hits.append(self._HitInfo(
79 (source_name, 102 source_name,
80 rel_path.replace('%ext%', e), 103 rel_path.replace('%ext%', e),
81 path.replace('%ext%', e))) 104 path.replace('%ext%', e),
105 metadata))
82 else: 106 else:
83 self._paths.append((source_name, rel_path, path)) 107 self._hits.append(
108 self._HitInfo(source_name, rel_path, path, metadata))
84 109
85 def _checkPaths(self): 110 def _checkHits(self):
86 if self._first_valid_path_index >= 0: 111 if self._first_valid_hit_index >= 0:
87 return 112 return
88 if self._first_valid_path_index == -1: 113 if self._first_valid_hit_index == self._INDEX_NOT_FOUND:
89 raise PageNotFoundError( 114 raise PageNotFoundError(
90 "No valid paths were found for page reference: %s" % 115 "No valid paths were found for page reference: %s" %
91 self._page_ref) 116 self._page_ref)
92 117
93 self._load() 118 self._load()
94 self._first_valid_path_index = -1 119 self._first_valid_hit_index = self._INDEX_NOT_FOUND
95 for i, path_info in enumerate(self._paths): 120 for i, hit in enumerate(self._hits):
96 if os.path.isfile(path_info[2]): 121 if os.path.isfile(hit.path):
97 self._first_valid_path_index = i 122 self._first_valid_hit_index = i
98 break 123 break
99 124