comparison piecrust/sources/pageref.py @ 411:e7b865f8f335

bake: Enable multiprocess baking. Baking is now done by running a worker per CPU, and sending jobs to them. This changes several things across the codebase: * Ability to not cache things related to pages other than the 'main' page (i.e. the page at the bottom of the execution stack). * Decouple the baking process from the bake records, so only the main process keeps track (and modifies) the bake record. * Remove the need for 'batch page getters' and loading a page directly from the page factories. There are various smaller changes too included here, including support for scope performance timers that are saved with the bake record and can be printed out to the console. Yes I got carried away. For testing, the in-memory 'mock' file-system doesn't work anymore, since we're spawning processes, so this is replaced by a 'tmpfs' file-system which is saved in temporary files on disk and deleted after tests have run.
author Ludovic Chabant <ludovic@chabant.com>
date Fri, 12 Jun 2015 17:09:19 -0700
parents 4b1019bb2533
children ab5c6a8ae90a
comparison
equal deleted inserted replaced
410:d1a472464e57 411:e7b865f8f335
40 except PageNotFoundError: 40 except PageNotFoundError:
41 return False 41 return False
42 42
43 @property 43 @property
44 def source_name(self): 44 def source_name(self):
45 self._checkHits()
46 return self._first_valid_hit.source_name 45 return self._first_valid_hit.source_name
47 46
48 @property 47 @property
49 def source(self): 48 def source(self):
50 return self.app.getSource(self.source_name) 49 return self.app.getSource(self.source_name)
51 50
52 @property 51 @property
53 def rel_path(self): 52 def rel_path(self):
54 self._checkHits()
55 return self._first_valid_hit.rel_path 53 return self._first_valid_hit.rel_path
56 54
57 @property 55 @property
58 def path(self): 56 def path(self):
59 self._checkHits()
60 return self._first_valid_hit.path 57 return self._first_valid_hit.path
61 58
62 @property 59 @property
63 def metadata(self): 60 def metadata(self):
64 self._checkHits()
65 return self._first_valid_hit.metadata 61 return self._first_valid_hit.metadata
66 62
67 @property 63 @property
68 def possible_rel_paths(self): 64 def possible_ref_specs(self):
69 self._load() 65 self._load()
70 return [h.rel_path for h in self._hits] 66 return ['%s:%s' % (h.source_name, h.rel_path) for h in self._hits]
67
68 @property
69 def possible_split_ref_specs(self):
70 self._load()
71 return [(h.source_name, h.rel_path) for h in self._hits]
71 72
72 @property 73 @property
73 def possible_paths(self): 74 def possible_paths(self):
74 self._load() 75 self._load()
75 return [h.path for h in self._hits] 76 return [h.path for h in self._hits]
78 return PageFactory(self.source, self.rel_path, 79 return PageFactory(self.source, self.rel_path,
79 copy.deepcopy(self.metadata)) 80 copy.deepcopy(self.metadata))
80 81
81 @property 82 @property
82 def _first_valid_hit(self): 83 def _first_valid_hit(self):
84 self._checkHits()
83 return self._hits[self._first_valid_hit_index] 85 return self._hits[self._first_valid_hit_index]
84 86
85 def _load(self): 87 def _load(self):
86 if self._hits is not None: 88 if self._hits is not None:
87 return 89 return
88 90
91 self._hits = []
92
93 if self._page_ref is None:
94 self._first_valid_hit_index = self._INDEX_NOT_FOUND
95 return
96
89 it = list(page_ref_pattern.finditer(self._page_ref)) 97 it = list(page_ref_pattern.finditer(self._page_ref))
90 if len(it) == 0: 98 if len(it) == 0:
91 raise Exception("Invalid page ref: %s" % self._page_ref) 99 raise Exception("Invalid page ref: %s" % self._page_ref)
92 100
93 self._hits = []
94 for m in it: 101 for m in it:
95 source_name = m.group('src') 102 source_name = m.group('src')
96 source = self.app.getSource(source_name) 103 source = self.app.getSource(source_name)
97 if source is None: 104 if source is None:
98 raise Exception("No such source: %s" % source_name) 105 raise Exception("No such source: %s" % source_name)
109 self._HitInfo(source_name, rel_path, path, metadata)) 116 self._HitInfo(source_name, rel_path, path, metadata))
110 117
111 def _checkHits(self): 118 def _checkHits(self):
112 if self._first_valid_hit_index >= 0: 119 if self._first_valid_hit_index >= 0:
113 return 120 return
121
122 if self._first_valid_hit_index == self._INDEX_NEEDS_LOADING:
123 self._load()
124 self._first_valid_hit_index = self._INDEX_NOT_FOUND
125 for i, hit in enumerate(self._hits):
126 if os.path.isfile(hit.path):
127 self._first_valid_hit_index = i
128 break
129
114 if self._first_valid_hit_index == self._INDEX_NOT_FOUND: 130 if self._first_valid_hit_index == self._INDEX_NOT_FOUND:
115 raise PageNotFoundError( 131 raise PageNotFoundError(
116 "No valid paths were found for page reference: %s" % 132 "No valid paths were found for page reference: %s" %
117 self._page_ref) 133 self._page_ref)
118 134
119 self._load()
120 self._first_valid_hit_index = self._INDEX_NOT_FOUND
121 for i, hit in enumerate(self._hits):
122 if os.path.isfile(hit.path):
123 self._first_valid_hit_index = i
124 break
125