Mercurial > piecrust2
changeset 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 | 8703be118430 |
children | d74ae33832ae |
files | piecrust/__init__.py piecrust/commands/builtin/scaffolding.py piecrust/commands/builtin/util.py piecrust/plugins/builtin.py piecrust/resources/prepare/default.html |
diffstat | 5 files changed, 167 insertions(+), 52 deletions(-) [+] |
line wrap: on
line diff
--- a/piecrust/__init__.py Sat Sep 13 14:47:01 2014 -0700 +++ b/piecrust/__init__.py Sat Sep 13 23:31:21 2014 -0700 @@ -22,3 +22,6 @@ except ImportError: APP_VERSION = 'unknown' +import os.path +RESOURCES_DIR = os.path.join(os.path.dirname(__file__), 'resources') +
--- /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 +
--- a/piecrust/commands/builtin/util.py Sat Sep 13 14:47:01 2014 -0700 +++ b/piecrust/commands/builtin/util.py Sat Sep 13 23:31:21 2014 -0700 @@ -6,7 +6,6 @@ import yaml from piecrust.app import CONFIG_PATH from piecrust.commands.base import ChefCommand -from piecrust.sources.base import IPreparingSource, MODE_CREATING logger = logging.getLogger(__name__) @@ -66,55 +65,6 @@ shutil.rmtree(cache_dir) -class PrepareCommand(ChefCommand): - 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) - src.setupPrepareParser(p, app) - 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) - - 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('---\n') - f.write('title: %s\n' % 'Unknown title') - f.write('---\n') - f.write("This is a new page!\n") - - class ImportCommand(ChefCommand): def __init__(self): super(ImportCommand, self).__init__()
--- a/piecrust/plugins/builtin.py Sat Sep 13 14:47:01 2014 -0700 +++ b/piecrust/plugins/builtin.py Sat Sep 13 23:31:21 2014 -0700 @@ -2,9 +2,12 @@ from piecrust.commands.builtin.baking import (BakeCommand, ShowRecordCommand) from piecrust.commands.builtin.info import (RootCommand, ShowConfigCommand, FindCommand, ShowRoutesCommand, ShowPathsCommand) +from piecrust.commands.builtin.scaffolding import (PrepareCommand, + DefaultPrepareTemplatesCommandExtension, + DefaultPrepareTemplatesHelpTopic) from piecrust.commands.builtin.serving import (ServeCommand) from piecrust.commands.builtin.util import (InitCommand, PurgeCommand, - PrepareCommand, ImportCommand) + ImportCommand) from piecrust.data.provider import (IteratorDataProvider, BlogDataProvider) from piecrust.formatting.markdownformatter import MarkdownFormatter from piecrust.formatting.smartypantsformatter import SmartyPantsFormatter @@ -42,7 +45,9 @@ ServeCommand()] def getCommandExtensions(self): - return [] + return [ + DefaultPrepareTemplatesCommandExtension(), + DefaultPrepareTemplatesHelpTopic()] def getSources(self): return [