comparison piecrust/main.py @ 852:4850f8c21b6e

core: Start of the big refactor for PieCrust 3.0. * Everything is a `ContentSource`, including assets directories. * Most content sources are subclasses of the base file-system source. * A source is processed by a "pipeline", and there are 2 built-in pipelines, one for assets and one for pages. The asset pipeline is vaguely functional, but the page pipeline is completely broken right now. * Rewrite the baking process as just running appropriate pipelines on each content item. This should allow for better parallelization.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 17 May 2017 00:11:48 -0700
parents cd3a00455b87
children eed19a80c00e
comparison
equal deleted inserted replaced
851:2c7e57d80bba 852:4850f8c21b6e
7 import logging 7 import logging
8 import argparse 8 import argparse
9 import colorama 9 import colorama
10 from piecrust import APP_VERSION 10 from piecrust import APP_VERSION
11 from piecrust.app import ( 11 from piecrust.app import (
12 PieCrust, PieCrustConfiguration, apply_variant_and_values) 12 PieCrustFactory, PieCrustConfiguration)
13 from piecrust.chefutil import ( 13 from piecrust.chefutil import (
14 format_timed, log_friendly_exception, print_help_item) 14 format_timed, log_friendly_exception, print_help_item)
15 from piecrust.commands.base import CommandContext 15 from piecrust.commands.base import CommandContext
16 from piecrust.pathutil import SiteNotFoundError, find_app_root 16 from piecrust.pathutil import SiteNotFoundError, find_app_root
17 from piecrust.plugins.base import PluginLoader 17 from piecrust.plugins.base import PluginLoader
18 18
19 19
20 logger = logging.getLogger(__name__) 20 logger = logging.getLogger(__name__)
21 21
22 22
23 class ColoredFormatter(logging.Formatter): 23 class ColoredFormatter(logging.Formatter):
24 COLORS = { 24 COLORS = {
25 'DEBUG': colorama.Fore.BLACK + colorama.Style.BRIGHT, 25 'DEBUG': colorama.Fore.BLACK + colorama.Style.BRIGHT,
26 'INFO': '', 26 'INFO': '',
27 'WARNING': colorama.Fore.YELLOW, 27 'WARNING': colorama.Fore.YELLOW,
28 'ERROR': colorama.Fore.RED, 28 'ERROR': colorama.Fore.RED,
29 'CRITICAL': colorama.Back.RED + colorama.Fore.WHITE 29 'CRITICAL': colorama.Back.RED + colorama.Fore.WHITE
30 } 30 }
31 31
32 def __init__(self, fmt=None, datefmt=None): 32 def __init__(self, fmt=None, datefmt=None):
33 super(ColoredFormatter, self).__init__(fmt, datefmt) 33 super(ColoredFormatter, self).__init__(fmt, datefmt)
34 34
35 def format(self, record): 35 def format(self, record):
77 sys.exit(exit_code) 77 sys.exit(exit_code)
78 78
79 79
80 def _setup_main_parser_arguments(parser): 80 def _setup_main_parser_arguments(parser):
81 parser.add_argument( 81 parser.add_argument(
82 '--version', 82 '--version',
83 action='version', 83 action='version',
84 version=('%(prog)s ' + APP_VERSION)) 84 version=('%(prog)s ' + APP_VERSION))
85 parser.add_argument( 85 parser.add_argument(
86 '--root', 86 '--root',
87 help="The root directory of the website.") 87 help="The root directory of the website.")
88 parser.add_argument( 88 parser.add_argument(
89 '--theme', 89 '--theme',
90 action='store_true', 90 action='store_true',
91 help="Makes the current command apply to a theme website.") 91 help="Makes the current command apply to a theme website.")
92 parser.add_argument( 92 parser.add_argument(
93 '--config', 93 '--config',
94 dest='config_variant', 94 dest='config_variant',
95 help="The configuration variant to use for this command.") 95 help="The configuration variant to use for this command.")
96 parser.add_argument( 96 parser.add_argument(
97 '--config-set', 97 '--config-set',
98 nargs=2, 98 nargs=2,
99 metavar=('NAME', 'VALUE'), 99 metavar=('NAME', 'VALUE'),
100 action='append', 100 action='append',
101 dest='config_values', 101 dest='config_values',
102 help="Sets a specific site configuration setting.") 102 help="Sets a specific site configuration setting.")
103 parser.add_argument( 103 parser.add_argument(
104 '--debug', 104 '--debug',
105 help="Show debug information.", action='store_true') 105 help="Show debug information.", action='store_true')
106 parser.add_argument( 106 parser.add_argument(
107 '--debug-only', 107 '--debug-only',
108 action='append', 108 action='append',
109 help="Only show debug information for the given categories.") 109 help="Only show debug information for the given categories.")
110 parser.add_argument( 110 parser.add_argument(
111 '--no-cache', 111 '--no-cache',
112 help="When applicable, disable caching.", 112 help="When applicable, disable caching.",
113 action='store_true') 113 action='store_true')
114 parser.add_argument( 114 parser.add_argument(
115 '--quiet', 115 '--quiet',
116 help="Print only important information.", 116 help="Print only important information.",
117 action='store_true') 117 action='store_true')
118 parser.add_argument( 118 parser.add_argument(
119 '--log', 119 '--log',
120 dest='log_file', 120 dest='log_file',
121 help="Send log messages to the specified file.") 121 help="Send log messages to the specified file.")
122 parser.add_argument( 122 parser.add_argument(
123 '--log-debug', 123 '--log-debug',
124 help="Log debug messages to the log file.", 124 help="Log debug messages to the log file.",
125 action='store_true') 125 action='store_true')
126 parser.add_argument( 126 parser.add_argument(
127 '--no-color', 127 '--no-color',
128 help="Don't use colorized output.", 128 help="Don't use colorized output.",
129 action='store_true') 129 action='store_true')
130 parser.add_argument( 130 parser.add_argument(
131 '--pid-file', 131 '--pid-file',
132 dest='pid_file', 132 dest='pid_file',
133 help="Write a PID file for the current process.") 133 help="Write a PID file for the current process.")
134 134
135 135
136 """ Kinda hacky, but we want the `serve` command to use a different cache 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 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 138 between `serve` and `bake` (or, worse, *not* re-render them all correctly
139 and end up serving or baking the wrong version). 139 and end up serving or baking the wrong version).
140 """ 140 """
141 _command_caches = { 141 _command_caches = {
142 'serve': 'server'} 142 'serve': 'server'}
143 143
144 144
145 def _pre_parse_chef_args(argv): 145 def _pre_parse_chef_args(argv):
146 # 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
147 # 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-
233 root = None 233 root = None
234 234
235 # Can't apply custom configuration stuff if there's no website. 235 # Can't apply custom configuration stuff if there's no website.
236 if (pre_args.config_variant or pre_args.config_values) and not root: 236 if (pre_args.config_variant or pre_args.config_values) and not root:
237 raise SiteNotFoundError( 237 raise SiteNotFoundError(
238 "Can't apply any configuration variant or value overrides, " 238 "Can't apply any configuration variant or value overrides, "
239 "there is no website here.") 239 "there is no website here.")
240 240
241 if root: 241 if root:
242 cache_key = None 242 cache_key = None
243 if not pre_args.no_cache: 243 if not pre_args.no_cache:
244 cache_key = _build_cache_key(pre_args) 244 cache_key = _build_cache_key(pre_args)
245 app = PieCrust( 245 appfactory = PieCrustFactory(
246 root, 246 root,
247 theme_site=pre_args.theme, 247 theme_site=pre_args.theme,
248 cache=(not pre_args.no_cache), 248 cache=(not pre_args.no_cache),
249 cache_key=cache_key, 249 cache_key=cache_key,
250 debug=pre_args.debug) 250 debug=pre_args.debug,
251 apply_variant_and_values( 251 config_variant=pre_args.config_variant,
252 app, pre_args.config_variant, pre_args.config_values) 252 config_values=pre_args.config_values)
253 app = appfactory.create()
253 else: 254 else:
255 appfactory = None
254 app = NullPieCrust( 256 app = NullPieCrust(
255 theme_site=pre_args.theme) 257 theme_site=pre_args.theme)
256 258
257 # Setup the arg parser. 259 # Setup the arg parser.
258 parser = argparse.ArgumentParser( 260 parser = argparse.ArgumentParser(
259 prog='chef', 261 prog='chef',
260 description="The PieCrust chef manages your website.", 262 description="The PieCrust chef manages your website.",
261 formatter_class=argparse.RawDescriptionHelpFormatter) 263 formatter_class=argparse.RawDescriptionHelpFormatter)
262 _setup_main_parser_arguments(parser) 264 _setup_main_parser_arguments(parser)
263 265
264 commands = sorted(app.plugin_loader.getCommands(), 266 commands = sorted(app.plugin_loader.getCommands(),
265 key=lambda c: c.name) 267 key=lambda c: c.name)
266 subparsers = parser.add_subparsers(title='list of commands') 268 subparsers = parser.add_subparsers(title='list of commands')
287 if not hasattr(result, 'func'): 289 if not hasattr(result, 'func'):
288 parser.print_help() 290 parser.print_help()
289 return 0 291 return 0
290 292
291 # Run the command! 293 # Run the command!
292 ctx = CommandContext(app, parser, result) 294 ctx = CommandContext(appfactory, app, parser, result)
293 ctx.config_variant = pre_args.config_variant
294 ctx.config_values = pre_args.config_values
295
296 exit_code = result.func(ctx) 295 exit_code = result.func(ctx)
297 if exit_code is None: 296 if exit_code is None:
298 return 0 297 return 0
299 if not isinstance(exit_code, int): 298 if not isinstance(exit_code, int):
300 logger.error("Got non-integer exit code: %s" % exit_code) 299 logger.error("Got non-integer exit code: %s" % exit_code)