Mercurial > piecrust2
comparison piecrust/serving/procloop.py @ 570:7dabfdd056a1
serve: Fix corner cases where the pipeline doesn't run correctly.
* When `chef serve` is run before the `assets` folder is created, monitor that
folder suddenly appearing and rebuild the pipeline.
* Do the same when the `config.yml` file has changed.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 31 Oct 2015 00:03:32 -0700 |
parents | ff714d7f074d |
children | 3ceeca7bb71c |
comparison
equal
deleted
inserted
replaced
569:34e57d4b97e2 | 570:7dabfdd056a1 |
---|---|
75 | 75 |
76 class ProcessingLoop(threading.Thread): | 76 class ProcessingLoop(threading.Thread): |
77 def __init__(self, root_dir, out_dir, sub_cache_dir=None, debug=False): | 77 def __init__(self, root_dir, out_dir, sub_cache_dir=None, debug=False): |
78 super(ProcessingLoop, self).__init__( | 78 super(ProcessingLoop, self).__init__( |
79 name='pipeline-reloader', daemon=True) | 79 name='pipeline-reloader', daemon=True) |
80 # TODO: re-create the app when `config.yml` is changed. | 80 self.root_dir = root_dir |
81 self.app = PieCrust(root_dir=root_dir, debug=debug) | 81 self.out_dir = out_dir |
82 if sub_cache_dir: | 82 self.sub_cache_dir = sub_cache_dir |
83 self.app._useSubCacheDir(sub_cache_dir) | 83 self.debug = debug |
84 self.pipeline = ProcessorPipeline(self.app, out_dir) | |
85 self.last_status_id = 0 | 84 self.last_status_id = 0 |
86 self.interval = 1 | 85 self.interval = 1 |
86 self.app = None | |
87 self._roots = [] | |
88 self._monitor_assets_root = False | |
87 self._paths = set() | 89 self._paths = set() |
90 self._config_path = os.path.join(root_dir, 'config.yml') | |
88 self._record = None | 91 self._record = None |
89 self._last_bake = 0 | 92 self._last_bake = 0 |
93 self._last_config_mtime = 0 | |
90 self._obs = [] | 94 self._obs = [] |
91 self._obs_lock = threading.Lock() | 95 self._obs_lock = threading.Lock() |
92 | 96 |
93 def addObserver(self, obs): | 97 def addObserver(self, obs): |
94 with self._obs_lock: | 98 with self._obs_lock: |
97 def removeObserver(self, obs): | 101 def removeObserver(self, obs): |
98 with self._obs_lock: | 102 with self._obs_lock: |
99 self._obs.remove(obs) | 103 self._obs.remove(obs) |
100 | 104 |
101 def run(self): | 105 def run(self): |
102 # Build the first list of known files and run the pipeline once. | 106 self._initPipeline() |
103 roots = [os.path.join(self.app.root_dir, r) | 107 |
104 for r in self.pipeline.mounts.keys()] | |
105 for root in roots: | |
106 for dirpath, dirnames, filenames in os.walk(root): | |
107 self._paths |= set([os.path.join(dirpath, f) | |
108 for f in filenames]) | |
109 self._last_bake = time.time() | 108 self._last_bake = time.time() |
109 self._last_config_mtime = os.path.getmtime(self._config_path) | |
110 self._record = self.pipeline.run() | 110 self._record = self.pipeline.run() |
111 | 111 |
112 while True: | 112 while True: |
113 for root in roots: | 113 cur_config_time = os.path.getmtime(self._config_path) |
114 if self._last_config_mtime < cur_config_time: | |
115 logger.info("Site configuration changed, reloading pipeline.") | |
116 self._last_config_mtime = cur_config_time | |
117 self._initPipeline() | |
118 for root in self._roots: | |
119 self._runPipeline(root) | |
120 continue | |
121 | |
122 if self._monitor_assets_root: | |
123 assets_dir = os.path.join(self.app.root_dir, 'assets') | |
124 if os.path.isdir(assets_dir): | |
125 logger.info("Assets directory was created, reloading " | |
126 "pipeline.") | |
127 self._initPipeline() | |
128 self._runPipeline(assets_dir) | |
129 continue | |
130 | |
131 for root in self._roots: | |
114 # For each mount root we try to find the first new or | 132 # For each mount root we try to find the first new or |
115 # modified file. If any, we just run the pipeline on | 133 # modified file. If any, we just run the pipeline on |
116 # that mount. | 134 # that mount. |
117 found_new_or_modified = False | 135 found_new_or_modified = False |
118 for dirpath, dirnames, filenames in os.walk(root): | 136 for dirpath, dirnames, filenames in os.walk(root): |
134 if found_new_or_modified: | 152 if found_new_or_modified: |
135 self._runPipeline(root) | 153 self._runPipeline(root) |
136 | 154 |
137 time.sleep(self.interval) | 155 time.sleep(self.interval) |
138 | 156 |
157 def _initPipeline(self): | |
158 # Create the app and pipeline. | |
159 self.app = PieCrust(root_dir=self.root_dir, debug=self.debug) | |
160 if self.sub_cache_dir: | |
161 self.app._useSubCacheDir(self.sub_cache_dir) | |
162 self.pipeline = ProcessorPipeline(self.app, self.out_dir) | |
163 | |
164 # Get the list of assets directories. | |
165 self._roots = list(self.pipeline.mounts.keys()) | |
166 | |
167 # The 'assets' folder may not be in the mounts list if it doesn't | |
168 # exist yet, but we want to monitor for when the user creates it. | |
169 default_root = os.path.join(self.app.root_dir, 'assets') | |
170 self._monitor_assets_root = (default_root not in self._roots) | |
171 | |
172 # Build the list of initial asset files. | |
173 self._paths = set() | |
174 for root in self._roots: | |
175 for dirpath, dirnames, filenames in os.walk(root): | |
176 self._paths |= set([os.path.join(dirpath, f) | |
177 for f in filenames]) | |
178 | |
139 def _runPipeline(self, root): | 179 def _runPipeline(self, root): |
140 self._last_bake = time.time() | 180 self._last_bake = time.time() |
141 try: | 181 try: |
142 self._record = self.pipeline.run( | 182 self._record = self.pipeline.run( |
143 root, | 183 root, |