Mercurial > piecrust2
diff piecrust/commands/builtin/scaffolding.py @ 100:69d5eecfa449
Better `prepare` command, with templates and help topics.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 13 Sep 2014 23:31:21 -0700 |
parents | |
children | 8355eb9dd8fe |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piecrust/commands/builtin/scaffolding.py Sat Sep 13 23:31:21 2014 -0700 @@ -0,0 +1,150 @@ +import os +import os.path +import re +import io +import time +import logging +import textwrap +from piecrust import RESOURCES_DIR +from piecrust.chefutil import print_help_item +from piecrust.commands.base import ExtendableChefCommand, ChefCommandExtension +from piecrust.sources.base import IPreparingSource, MODE_CREATING +from piecrust.uriutil import multi_replace + + +logger = logging.getLogger(__name__) + + +def make_title(slug): + slug = re.sub(r'[\-_]', ' ', slug) + return slug.title() + + +class PrepareCommand(ExtendableChefCommand): + """ Chef command for creating pages with some default content. + """ + def __init__(self): + super(PrepareCommand, self).__init__() + self.name = 'prepare' + self.description = "Prepares new content for your website." + + def setupParser(self, parser, app): + # Don't setup anything if this is a null app + # (for when `chef` is run from outside a website) + if app.root_dir is None: + return + + subparsers = parser.add_subparsers() + for src in app.sources: + if not isinstance(src, IPreparingSource): + logger.debug("Skipping source '%s' because it's not " + "preparable." % src.name) + continue + if src.is_theme_source: + logger.debug("Skipping source '%s' because it's a theme " + "source." % src.name) + continue + p = subparsers.add_parser( + src.item_name, + help="Creates an empty page in the '%s' source." % src.name) + src.setupPrepareParser(p, app) + p.add_argument('-t', '--template', default='default', + help="The template to use, which will change the " + "generated text and header.") + p.set_defaults(source=src) + + def run(self, ctx): + app = ctx.app + source = ctx.args.source + metadata = source.buildMetadata(ctx.args) + rel_path, metadata = source.findPagePath(metadata, MODE_CREATING) + path = source.resolveRef(rel_path) + name, ext = os.path.splitext(path) + if ext == '.*': + path = '%s.%s' % (name, + app.config.get('site/default_auto_format')) + if os.path.exists(path): + raise Exception("'%s' already exists." % path) + + tpl_name = ctx.args.template + extensions = self.getExtensions(app) + ext = next( + filter( + lambda e: tpl_name in e.getTemplateNames(ctx.app), + extensions), + None) + if ext is None: + raise Exception("No such page template: %s" % tpl_name) + + tpl_text = ext.getTemplate(ctx.app, tpl_name) + title = (metadata.get('slug') or metadata.get('path') or + 'Untitled page') + title = make_title(title) + tokens = { + '%title%': title, + '%time.today%': time.strftime('%Y/%m/%d'), + '%time.now%': time.strftime('%H:%M:%S')} + tpl_text = multi_replace(tpl_text, tokens) + + logger.info("Creating page: %s" % os.path.relpath(path, app.root_dir)) + if not os.path.exists(os.path.dirname(path)): + os.makedirs(os.path.dirname(path), 0o755) + + with open(path, 'w') as f: + f.write(tpl_text) + + +class DefaultPrepareTemplatesCommandExtension(ChefCommandExtension): + """ Provides the default scaffolding tempaltes to the `prepare` + command. + """ + def __init__(self): + super(DefaultPrepareTemplatesCommandExtension, self).__init__() + self.command_name = 'prepare' + + def getTemplateNames(self, app): + return ['default', 'rss', 'atom'] + + def getTemplateDescription(self, app, name): + descs = { + 'default': "The default template, for a simple page.", + 'rss': "A fully functional RSS feed.", + 'atom': "A fully functional Atom feed."} + return descs[name] + + def getTemplate(self, app, name): + assert name in ['default', 'rss', 'atom'] + src_path = os.path.join(RESOURCES_DIR, 'prepare', '%s.html' % name) + with open(src_path, 'r', encoding='utf8') as fp: + return fp.read() + + +class DefaultPrepareTemplatesHelpTopic(ChefCommandExtension): + """ Provides help topics for the `prepare` command. + """ + command_name = 'help' + + def getHelpTopics(self): + return [('scaffolding', + "Available templates for the 'prepare' command.")] + + def getHelpTopic(self, topic, app): + with io.StringIO() as tplh: + extensions = app.plugin_loader.getCommandExtensions() + for e in extensions: + if e.command_name == 'prepare' and e.supports(app): + for n in e.getTemplateNames(app): + d = e.getTemplateDescription(app, n) + print_help_item(tplh, n, d) + help_list = tplh.getvalue() + + help_txt = ( + textwrap.fill("Running the 'prepare' command will let " + "PieCrust setup a page for you in the correct place, with " + "some hopefully useful default text.") + + "\n\n" + + textwrap.fill("The following templates are available:") + + "\n\n" + + help_list) + return help_txt +