comparison piecrust/main.py @ 666:81d9c3a3a0b5

internal: Get rid of the whole "sub cache" business. * Compute cache keys up front, so the cache directory is only chosen once. * Buffer up config variants to apply before loading the config. Makes it possible to cache variant-resulting configs, too. * Make a factory class to reuse the logic that creates the `PieCrust` object correctly for multi-process workers and such. * Add a test.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 03 Mar 2016 08:22:41 -0800
parents 3ceeca7bb71c
children cd3a00455b87
comparison
equal deleted inserted replaced
665:5dc13c816045 666:81d9c3a3a0b5
1 import os 1 import os
2 import os.path 2 import os.path
3 import io 3 import io
4 import sys 4 import sys
5 import time 5 import time
6 import hashlib
6 import logging 7 import logging
7 import argparse 8 import argparse
8 import colorama 9 import colorama
9 from piecrust import APP_VERSION 10 from piecrust import APP_VERSION
10 from piecrust.app import ( 11 from piecrust.app import (
49 self.cache_dir = None 50 self.cache_dir = None
50 self.config = PieCrustConfiguration() 51 self.config = PieCrustConfiguration()
51 self.plugin_loader = PluginLoader(self) 52 self.plugin_loader = PluginLoader(self)
52 self.env = None 53 self.env = None
53 54
54 def useSubCache(self, cache_name, cache_key):
55 pass
56
57 55
58 def main(): 56 def main():
59 if sys.platform == 'darwin': 57 if sys.platform == 'darwin':
60 # There's a bug on MacOSX that can cause Python to be confused 58 # There's a bug on MacOSX that can cause Python to be confused
61 # about the locale. Let's try to fix that. 59 # about the locale. Let's try to fix that.
133 '--pid-file', 131 '--pid-file',
134 dest='pid_file', 132 dest='pid_file',
135 help="Write a PID file for the current process.") 133 help="Write a PID file for the current process.")
136 134
137 135
136 """ Kinda hacky, but we want the `serve` command to use a different cache
137 so that PieCrust doesn't need to re-render all the pages when going
138 between `serve` and `bake` (or, worse, *not* re-render them all correctly
139 and end up serving or baking the wrong version).
140 """
141 _command_caches = {
142 'serve': 'server'}
143
144
138 def _pre_parse_chef_args(argv): 145 def _pre_parse_chef_args(argv):
139 # We need to parse some arguments before we can build the actual argument 146 # We need to parse some arguments before we can build the actual argument
140 # parser, because it can affect which plugins will be loaded. Also, log- 147 # parser, because it can affect which plugins will be loaded. Also, log-
141 # related arguments must be parsed first because we want to log everything 148 # related arguments must be parsed first because we want to log everything
142 # from the beginning. 149 # from the beginning.
143 parser = argparse.ArgumentParser() 150 parser = argparse.ArgumentParser()
144 _setup_main_parser_arguments(parser) 151 _setup_main_parser_arguments(parser)
145 parser.add_argument('args', nargs=argparse.REMAINDER) 152 parser.add_argument('extra_args', nargs=argparse.REMAINDER)
146 res, _ = parser.parse_known_args(argv) 153 res, _ = parser.parse_known_args(argv)
147 154
148 # Setup the logger. 155 # Setup the logger.
149 if res.debug and res.quiet: 156 if res.debug and res.quiet:
150 raise Exception("You can't specify both --debug and --quiet.") 157 raise Exception("You can't specify both --debug and --quiet.")
194 raise Exception("Can't write PID file: %s" % res.pid_file) from ex 201 raise Exception("Can't write PID file: %s" % res.pid_file) from ex
195 202
196 return res 203 return res
197 204
198 205
206 def _build_cache_key(pre_args):
207 cache_key_str = 'default'
208 if pre_args.extra_args:
209 cmd_name = pre_args.extra_args[0]
210 if cmd_name in _command_caches:
211 cache_key_str = _command_caches[cmd_name]
212 if pre_args.config_variant is not None:
213 cache_key_str += ',variant=%s' % pre_args.config_variant
214 if pre_args.config_values:
215 for name, value in pre_args.config_values:
216 cache_key_str += ',%s=%s' % (name, value)
217
218 logger.debug("Using cache key: %s" % cache_key_str)
219 cache_key = hashlib.md5(cache_key_str.encode('utf8')).hexdigest()
220 return cache_key
221
222
199 def _run_chef(pre_args, argv): 223 def _run_chef(pre_args, argv):
200 # Setup the app. 224 # Setup the app.
201 start_time = time.perf_counter() 225 start_time = time.perf_counter()
202 root = None 226 root = None
203 if pre_args.root: 227 if pre_args.root:
206 try: 230 try:
207 root = find_app_root(theme=pre_args.theme) 231 root = find_app_root(theme=pre_args.theme)
208 except SiteNotFoundError: 232 except SiteNotFoundError:
209 root = None 233 root = None
210 234
211 if not root: 235 # Can't apply custom configuration stuff if there's no website.
212 app = NullPieCrust( 236 if (pre_args.config_variant or pre_args.config_values) and not root:
213 theme_site=pre_args.theme) 237 raise SiteNotFoundError(
214 else: 238 "Can't apply any configuration variant or value overrides, "
239 "there is no website here.")
240
241 if root:
242 cache_key = None
243 if not pre_args.no_cache:
244 cache_key = _build_cache_key(pre_args)
215 app = PieCrust( 245 app = PieCrust(
216 root, 246 root,
217 theme_site=pre_args.theme, 247 theme_site=pre_args.theme,
218 cache=(not pre_args.no_cache), 248 cache=(not pre_args.no_cache),
249 cache_key=cache_key,
219 debug=pre_args.debug) 250 debug=pre_args.debug)
220 251 apply_variant_and_values(
221 # Build a hash for a custom cache directory. 252 app, pre_args.config_variant, pre_args.config_values)
222 cache_key = 'default' 253 else:
223 254 app = NullPieCrust(
224 # Handle custom configurations. 255 theme_site=pre_args.theme)
225 if (pre_args.config_variant or pre_args.config_values) and not root:
226 raise SiteNotFoundError(
227 "Can't apply any configuration variant or value overrides, "
228 "there is no website here.")
229 apply_variant_and_values(app, pre_args.config_variant,
230 pre_args.config_values)
231
232 # Adjust the cache key.
233 if pre_args.config_variant is not None:
234 cache_key += ',variant=%s' % pre_args.config_variant
235 if pre_args.config_values:
236 for name, value in pre_args.config_values:
237 cache_key += ',%s=%s' % (name, value)
238 256
239 # Setup the arg parser. 257 # Setup the arg parser.
240 parser = argparse.ArgumentParser( 258 parser = argparse.ArgumentParser(
241 prog='chef', 259 prog='chef',
242 description="The PieCrust chef manages your website.", 260 description="The PieCrust chef manages your website.",
268 # Print the help if no command was specified. 286 # Print the help if no command was specified.
269 if not hasattr(result, 'func'): 287 if not hasattr(result, 'func'):
270 parser.print_help() 288 parser.print_help()
271 return 0 289 return 0
272 290
273 # Use a customized cache for the command and current config.
274 if result.cache_name != 'default' or cache_key != 'default':
275 app.useSubCache(result.cache_name, cache_key)
276
277 # Run the command! 291 # Run the command!
278 ctx = CommandContext(app, parser, result) 292 ctx = CommandContext(app, parser, result)
279 ctx.config_variant = pre_args.config_variant 293 ctx.config_variant = pre_args.config_variant
280 ctx.config_values = pre_args.config_values 294 ctx.config_values = pre_args.config_values
281 295