Mercurial > piecrust2
changeset 642:79aefe82c6b6
cm: Move all scripts into a `garcon` package with `invoke` support.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 14 Feb 2016 22:11:24 -0800 |
parents | 35221f5fe0dd |
children | 81a30a63c431 |
files | dev-requirements.txt garcon/__init__.py garcon/benchsite.py garcon/changelog.py garcon/changelog/category_title.rst garcon/changelog/header.rst garcon/changelog/version_title.rst garcon/documentation.py garcon/messages.py garcon/messages/config.yml garcon/messages/pages/_index.html garcon/messages/pages/critical.html garcon/messages/pages/error.html garcon/messages/pages/error404.html garcon/messages/templates/default.html garcon/messages/templates/error.html garcon/pypi.py tasks.py util/changelog/category_title.rst util/changelog/header.rst util/changelog/version_title.rst util/generate_benchsite.py util/generate_changelog.py util/generate_docs.sh util/generate_messages.cmd util/generate_messages.sh util/messages/config.yml util/messages/pages/_index.html util/messages/pages/critical.html util/messages/pages/error.html util/messages/pages/error404.html util/messages/templates/default.html util/messages/templates/error.html |
diffstat | 32 files changed, 647 insertions(+), 634 deletions(-) [+] |
line wrap: on
line diff
--- a/dev-requirements.txt Sun Feb 14 22:10:05 2016 -0800 +++ b/dev-requirements.txt Sun Feb 14 22:11:24 2016 -0800 @@ -1,5 +1,6 @@ cov-core==1.15.0 coverage==3.7.1 +invoke==0.12.2 mock==1.0.1 pytest==2.7.0 pytest-cov==1.8.1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/benchsite.py Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,227 @@ +import io +import os +import os.path +import string +import random +import datetime +import argparse + + +def generateWord(min_len=1, max_len=10): + length = random.randint(min_len, max_len) + word = ''.join(random.choice(string.ascii_letters) for _ in range(length)) + return word + + +def generateSentence(words): + return ' '.join([generateWord() for i in range(words)]) + + +def generateDate(): + year = random.choice(range(1995, 2015)) + month = random.choice(range(1, 13)) + day = random.choice(range(1, 29)) + hours = random.choice(range(0, 24)) + minutes = random.choice(range(0, 60)) + seconds = random.choice(range(0, 60)) + return datetime.datetime( + year, month, day, hours, minutes, seconds) + + +def generateTitleAndSlug(): + title = generateSentence(8) + slug = title.replace(' ', '-').lower() + slug = ''.join(c for c in slug if c.isalnum() or c == '-') + return title, slug + + +class BenchmarkSiteGenerator(object): + def __init__(self, out_dir): + self.out_dir = out_dir + self.all_tags = [] + + def generatePost(self): + post_info = {} + title, slug = generateTitleAndSlug() + post_info.update({ + 'title': title, + 'slug': slug}) + post_info['description'] = generateSentence(20) + post_info['tags'] = random.choice(self.all_tags) + post_info['datetime'] = generateDate() + + buf = io.StringIO() + with buf: + para_count = random.randint(5, 10) + for i in range(para_count): + buf.write(generateSentence(random.randint(50, 100))) + buf.write('\n\n') + post_info['text'] = buf.getvalue() + + self.writePost(post_info) + + def initialize(self): + pass + + def writePost(self, post_info): + raise NotImplementedError() + + +class PieCrustBechmarkSiteGenerator(BenchmarkSiteGenerator): + def initialize(self): + posts_dir = os.path.join(self.out_dir, 'posts') + if not os.path.isdir(posts_dir): + os.makedirs(posts_dir) + + def writePost(self, post_info): + out_dir = os.path.join(self.out_dir, 'posts') + slug = post_info['slug'] + dtstr = post_info['datetime'].strftime('%Y-%m-%d') + with open('%s/%s_%s.md' % (out_dir, dtstr, slug), 'w', + encoding='utf8') as f: + f.write('---\n') + f.write('title: %s\n' % post_info['title']) + f.write('description: %s\n' % post_info['description']) + f.write('tags: [%s]\n' % post_info['tags']) + f.write('---\n') + + para_count = random.randint(5, 10) + for i in range(para_count): + f.write(generateSentence(random.randint(50, 100))) + f.write('\n\n') + + +class OctopressBenchmarkSiteGenerator(BenchmarkSiteGenerator): + def initialize(self): + posts_dir = os.path.join(self.out_dir, 'source', '_posts') + if not os.path.isdir(posts_dir): + os.makedirs(posts_dir) + + def writePost(self, post_info): + out_dir = os.path.join(self.out_dir, 'source', '_posts') + slug = post_info['slug'] + dtstr = post_info['datetime'].strftime('%Y-%m-%d') + with open('%s/%s-%s.markdown' % (out_dir, dtstr, slug), 'w', + encoding='utf8') as f: + f.write('---\n') + f.write('layout: post\n') + f.write('title: %s\n' % post_info['title']) + f.write('date: %s 12:00\n' % dtstr) + f.write('comments: false\n') + f.write('categories: [%s]\n' % post_info['tags']) + f.write('---\n') + + para_count = random.randint(5, 10) + for i in range(para_count): + f.write(generateSentence(random.randint(50, 100))) + f.write('\n\n') + + +class MiddlemanBenchmarkSiteGenerator(BenchmarkSiteGenerator): + def initialize(self): + posts_dir = os.path.join(self.out_dir, 'source') + if not os.path.isdir(posts_dir): + os.makedirs(posts_dir) + + def writePost(self, post_info): + out_dir = os.path.join(self.out_dir, 'source') + slug = post_info['slug'] + dtstr = post_info['datetime'].strftime('%Y-%m-%d') + with open('%s/%s-%s.html.markdown' % (out_dir, dtstr, slug), 'w', + encoding='utf8') as f: + f.write('---\n') + f.write('title: %s\n' % post_info['title']) + f.write('date: %s\n' % post_info['datetime'].strftime('%Y/%m/%d')) + f.write('tags: %s\n' % post_info['tags']) + f.write('---\n') + + para_count = random.randint(5, 10) + for i in range(para_count): + f.write(generateSentence(random.randint(50, 100))) + f.write('\n\n') + + +class HugoBenchmarkSiteGenerator(BenchmarkSiteGenerator): + def initialize(self): + posts_dir = os.path.join(self.out_dir, 'content', 'post') + if not os.path.isdir(posts_dir): + os.makedirs(posts_dir) + + def writePost(self, post_info): + out_dir = os.path.join(self.out_dir, 'content', 'post') + dtstr = post_info['datetime'].strftime('%Y-%m-%d_%H-%M-%S') + post_path = os.path.join(out_dir, '%s.md' % dtstr) + with open(post_path, 'w', encoding='utf8') as f: + f.write('+++\n') + f.write('title = "%s"\n' % post_info['title']) + f.write('description = "%s"\n' % post_info['description']) + f.write('categories = [\n "%s"\n]\n' % post_info['tags']) + f.write('date = "%s"\n' % post_info['datetime'].strftime( + "%Y-%m-%d %H:%M:%S-00:00")) + f.write('slug ="%s"\n' % post_info['slug']) + f.write('+++\n') + f.write(post_info['text']) + + +generators = { + 'piecrust': PieCrustBechmarkSiteGenerator, + 'octopress': OctopressBenchmarkSiteGenerator, + 'middleman': MiddlemanBenchmarkSiteGenerator, + 'hugo': HugoBenchmarkSiteGenerator + } + + +def main(): + parser = argparse.ArgumentParser( + prog='generate_benchsite', + description=("Generates a benchmark website with placeholder " + "content suitable for testing.")) + parser.add_argument( + 'engine', + help="The engine to generate the site for.", + choices=list(generators.keys())) + parser.add_argument( + 'out_dir', + help="The target directory for the website.") + parser.add_argument( + '-c', '--post-count', + help="The number of posts to create.", + type=int, + default=100) + parser.add_argument( + '--tag-count', + help="The number of tags to use.", + type=int, + default=30) + + result = parser.parse_args() + generate(result.engine, result.out_dir, + post_count=result.post_count, + tag_count=result.tag_count) + + +def generate(engine, out_dir, post_count=100, tag_count=10): + print("Generating %d posts in %s..." % (post_count, out_dir)) + + if not os.path.exists(out_dir): + os.makedirs(out_dir) + + gen = generators[engine](out_dir) + gen.all_tags = [generateWord(3, 12) for _ in range(tag_count)] + gen.initialize() + + for i in range(post_count): + gen.generatePost() + + +if __name__ == '__main__': + main() +else: + from invoke import task + + @task + def genbenchsite(engine, out_dir, post_count=100, tag_count=10): + generate(engine, out_dir, + post_count=post_count, + tag_count=tag_count) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/changelog.py Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,183 @@ +import os +import os.path +import re +import time +import argparse +import subprocess + + +hg_log_template = ("{if(tags, '>>{tags};{date|shortdate}\n')}" + "{desc|firstline}\n\n") + +re_add_tag_changeset = re.compile('^Added tag [^\s]+ for changeset [\w\d]+$') +re_merge_pr_changeset = re.compile('^Merge pull request') +re_tag = re.compile('^\d+\.\d+\.\d+([ab]\d+)?(rc\d+)?$') +re_change = re.compile('^(\w+):') +re_clean_code_span = re.compile('([^\s])``([^\s]+)') + +category_commands = [ + 'chef', 'bake', 'find', 'help', 'import', 'init', 'paths', 'plugin', + 'plugins', 'prepare', 'purge', 'root', 'routes', 'serve', + 'showconfig', 'showrecord', 'sources', 'theme', 'themes', 'admin', + 'publish'] +category_core = [ + 'internal', 'bug', 'templating', 'formatting', 'performance', + 'data', 'config', 'rendering', 'render', 'debug', 'reporting', + 'linker', 'pagination', 'routing', 'caching', 'cli'] +category_project = ['build', 'cm', 'docs', 'tests', 'setup'] +categories = [ + ('commands', category_commands), + ('core', category_core), + ('project', category_project), + ('miscellaneous', None)] +category_names = list(map(lambda i: i[0], categories)) + + +def generate(out_file, last=None): + print("Generating %s" % out_file) + + if not os.path.exists('.hg'): + raise Exception("You must run this script from the root of a " + "Mercurial clone of the PieCrust repository.") + hglog = subprocess.check_output([ + 'hg', 'log', + '--rev', 'reverse(::master)', + '--template', hg_log_template]) + hglog = hglog.decode('utf8') + + templates = _get_templates() + + with open(out_file, 'w') as fp: + fp.write(templates['header']) + + skip = False + in_desc = False + current_version = 0 + current_version_info = None + current_changes = None + + if last: + current_version = 1 + cur_date = time.strftime('%Y-%m-%d') + current_version_info = last, cur_date + current_changes = {} + + for line in hglog.splitlines(): + if line == '': + skip = False + in_desc = False + continue + + if not in_desc and line.startswith('>>'): + tags, tag_date = line[2:].split(';') + if re_tag.match(tags): + if current_version > 0: + _write_version_changes( + templates, + current_version, current_version_info, + current_changes, fp) + + current_version += 1 + current_version_info = tags, tag_date + current_changes = {} + in_desc = True + else: + skip = True + continue + + if skip or current_version == 0: + continue + + if re_add_tag_changeset.match(line): + continue + if re_merge_pr_changeset.match(line): + continue + + m = re_change.match(line) + if m: + ch_type = m.group(1) + for cat_name, ch_types in categories: + if ch_types is None or ch_type in ch_types: + msgs = current_changes.setdefault(cat_name, []) + msgs.append(line) + break + else: + assert False, ("Change '%s' should have gone in the " + "misc. bucket." % line) + else: + msgs = current_changes.setdefault('miscellaneous', []) + msgs.append(line) + + if current_version > 0: + _write_version_changes( + templates, + current_version, current_version_info, + current_changes, fp) + + +def _write_version_changes(templates, version, version_info, changes, fp): + tokens = { + 'num': str(version), + 'version': version_info[0], + 'date': version_info[1]} + tpl = _multi_replace(templates['version_title'], tokens) + fp.write(tpl) + + for i, cat_name in enumerate(category_names): + msgs = changes.get(cat_name) + if not msgs: + continue + + tokens = { + 'sub_num': str(i), + 'category': cat_name.title()} + tpl = _multi_replace(templates['category_title'], tokens) + fp.write(tpl) + + for msg in msgs: + msg = msg.replace('`', '``').rstrip('\n') + msg = re_clean_code_span.sub(r'\1`` \2', msg) + fp.write('* ' + msg + '\n') + + +def _multi_replace(s, tokens): + for token in tokens: + s = s.replace('%%%s%%' % token, tokens[token]) + return s + + +def _get_templates(): + tpl_dir = os.path.join(os.path.dirname(__file__), 'changelog') + tpls = {} + for name in os.listdir(tpl_dir): + tpl = _get_template(os.path.join(tpl_dir, name)) + name_no_ext, _ = os.path.splitext(name) + tpls[name_no_ext] = tpl + return tpls + + +def _get_template(filename): + with open(filename, 'r', encoding='utf8') as fp: + return fp.read() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Generate CHANGELOG file.') + parser.add_argument( + 'out_file', + nargs='?', + default='CHANGELOG.rst', + help='The output file.') + parser.add_argument( + '--last', + help="The version for the last few untagged changes.") + args = parser.parse_args() + + generate(args.out_file, last=args.last) +else: + from invoke import task + + @task + def genchangelog(out_file='CHANGELOG.rst', last=None): + generate(out_file, last) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/changelog/category_title.rst Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,4 @@ + +1.%sub_num% %category% +---------------------- +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/changelog/header.rst Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,10 @@ + +######### +CHANGELOG +######### + +This is the changelog for PieCrust_. + +.. _PieCrust: http://bolt80.com/piecrust/ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/changelog/version_title.rst Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,5 @@ + +================================== +%num%. PieCrust %version% (%date%) +================================== +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/documentation.py Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,41 @@ +import os +import os.path +from invoke import task, run + + +@task +def gendocs(tmp_dir=None, out_dir=None): + if not tmp_dir: + tmp_dir = '_docs-counter' + + print("Updating virtual environment") + run("pip install -r requirements.txt --upgrade") + + print("Update Bower packages") + run("bower update") + + print("Generate PieCrust version") + run('python setup.py version') + from piecrust.__version__ import APP_VERSION + version = APP_VERSION + + print("Baking documentation for version: %s" % version) + args = [ + 'python', 'chef.py', + '--root', 'docs', + '--config', 'dist', + '--config-set', 'site/root', '/piecrust/en/%s' % version, + 'bake', + '-o', tmp_dir + ] + run(' '.join(args)) + + if out_dir: + print("Synchronizing %s" % out_dir) + if not os.path.isdir(out_dir): + os.makedirs(out_dir) + + tmp_dir = tmp_dir.rstrip('/') + '/' + out_dir = out_dir.rstrip('/') + '/' + run('rsync -av --delete %s %s' % (tmp_dir, out_dir)) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages.py Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,11 @@ +import os +from invoke import task, run + + +@task +def genmessages(): + root_dir = 'garcon/messages' + out_dir = 'piecrust/resources/messages' + run('python chef.py --root %s bake -o %s' % (root_dir, out_dir)) + os.unlink('piecrust/resources/messages/index.html') +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages/config.yml Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,2 @@ +site: + title: PieCrust System Messages
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages/pages/_index.html Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,12 @@ +--- +title: PieCrust System Messages +--- + +Here are the **PieCrust** system message pages: + +* [Requirements Not Met]({{ pcurl('requirements') }}) +* [Error]({{ pcurl('error') }}) +* [Not Found]({{ pcurl('error404') }}) +* [Critical Error]({{ pcurl('critical') }}) + +This very page you're reading, however, is only here for convenience.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages/pages/critical.html Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,6 @@ +--- +title: The Whole Kitchen Burned Down! +layout: error +--- +Something critically bad happened, and **PieCrust** needs to shut down. It's probably our fault. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages/pages/error.html Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,5 @@ +--- +title: The Cake Just Burned! +layout: error +--- +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages/pages/error404.html Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,6 @@ +--- +title: Can't find the sugar! +layout: error +--- +It looks like the page you were trying to access does not exist around here. Try going somewhere else. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages/templates/default.html Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,70 @@ +<!doctype html> +<html> +<head> + <title>{{ page.title }}</title> + <meta name="generator" content="PieCrust" /> + <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Lobster"> + <style> + body { + margin: 0; + padding: 1em; + background: #eee; + color: #000; + font-family: Georgia, serif; + } + h1 { + font-size: 4.5em; + font-family: Lobster, 'Trebuchet MS', Verdana, sans-serif; + text-align: center; + font-weight: bold; + margin-top: 0; + color: #333; + text-shadow: 0px 2px 5px rgba(0,0,0,0.3); + } + h2 { + font-size: 2.5em; + font-family: 'Lobster', 'Trebuchet MS', Verdana, sans-serif; + } + code { + background: #ddd; + padding: 0 0.2em; + } + #preamble { + font-size: 1.2em; + font-style: italic; + text-align: center; + margin-bottom: 0; + } + #container { + margin: 0 20%; + } + #content { + margin: 2em 1em; + } + .error-details { + color: #d11; + } + .note { + margin: 3em; + color: #888; + font-style: italic; + } + </style> +</head> +<body> + <div id="container"> + <div id="header"> + <p id="preamble">A Message From The Kitchen:</p> + <h1>{{ page.title }}</h1> + </div> + <hr /> + <div id="content"> + {% block content %} + {{ content|safe }} + {% endblock %} + </div> + <hr /> + {% block footer %}{% endblock %} + </div> +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/messages/templates/error.html Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,27 @@ +{% extends "default.html" %} + +{% block content %} +{{content|safe}} + +{# The following is `raw` because we want it to be in the + produced page, so it can then be templated on the fly + with the error messages #} +{% raw %} +{% if details %} +<div class="error-details"> + <p>Error details:</p> + <ul> + {% for desc in details %} + <li>{{ desc }}</li> + {% endfor %} + </ul> +</div> +{% endif %} +{% endraw %} +{% endblock %} + +{% block footer %} +{% pcformat 'textile' %} +p(note). You're seeing this because something wrong happend. To see detailed errors with callstacks, run chef with the @--debug@ parameter, append @?!debug@ to the URL, or initialize the @PieCrust@ object with @{'debug': true}@. On the other hand, to see you custom error pages, set the @site/display_errors@ setting to @false@. +{% endpcformat %} +{% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/garcon/pypi.py Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,22 @@ +from invoke import task, run + + +@task +def makerelease(version, notag=False, noupload=False): + if not version: + raise Exception("You must specify a version!") + + # FoodTruck assets. + run("gulp") + + # CHANGELOG.rst + run("invoke changelog --last %s" % version) + + # Tag in Mercurial, which will then be used for PyPi version. + if not notag: + run("hg tag %s" % version) + + # PyPi upload. + if not noupload: + run("python setup.py sdist upload") +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tasks.py Sun Feb 14 22:11:24 2016 -0800 @@ -0,0 +1,15 @@ +from invoke import Collection, task, run +from garcon.benchsite import genbenchsite +from garcon.changelog import genchangelog +from garcon.documentation import gendocs +from garcon.messages import genmessages +from garcon.pypi import makerelease + + +ns = Collection() +ns.add_task(genbenchsite, name='benchsite') +ns.add_task(genchangelog, name='changelog') +ns.add_task(gendocs, name='docs') +ns.add_task(genmessages, name='messages') +ns.add_task(makerelease, name='release') +
--- a/util/changelog/category_title.rst Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ - -1.%sub_num% %category% ----------------------- -
--- a/util/changelog/header.rst Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ - -######### -CHANGELOG -######### - -This is the changelog for PieCrust_. - -.. _PieCrust: http://bolt80.com/piecrust/ - -
--- a/util/changelog/version_title.rst Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ - -================================== -%num%. PieCrust %version% (%date%) -================================== -
--- a/util/generate_benchsite.py Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +0,0 @@ -import io -import os -import os.path -import string -import random -import datetime -import argparse - - -def generateWord(min_len=1, max_len=10): - length = random.randint(min_len, max_len) - word = ''.join(random.choice(string.ascii_letters) for _ in range(length)) - return word - - -def generateSentence(words): - return ' '.join([generateWord() for i in range(words)]) - - -def generateDate(): - year = random.choice(range(1995, 2015)) - month = random.choice(range(1, 13)) - day = random.choice(range(1, 29)) - hours = random.choice(range(0, 24)) - minutes = random.choice(range(0, 60)) - seconds = random.choice(range(0, 60)) - return datetime.datetime( - year, month, day, hours, minutes, seconds) - - -def generateTitleAndSlug(): - title = generateSentence(8) - slug = title.replace(' ', '-').lower() - slug = ''.join(c for c in slug if c.isalnum() or c == '-') - return title, slug - - -class BenchmarkSiteGenerator(object): - def __init__(self, out_dir): - self.out_dir = out_dir - self.all_tags = [] - - def generatePost(self): - post_info = {} - title, slug = generateTitleAndSlug() - post_info.update({ - 'title': title, - 'slug': slug}) - post_info['description'] = generateSentence(20) - post_info['tags'] = random.choice(self.all_tags) - post_info['datetime'] = generateDate() - - buf = io.StringIO() - with buf: - para_count = random.randint(5, 10) - for i in range(para_count): - buf.write(generateSentence(random.randint(50, 100))) - buf.write('\n\n') - post_info['text'] = buf.getvalue() - - self.writePost(post_info) - - def initialize(self): - pass - - def writePost(self, post_info): - raise NotImplementedError() - - -class PieCrustBechmarkSiteGenerator(BenchmarkSiteGenerator): - def initialize(self): - posts_dir = os.path.join(self.out_dir, 'posts') - if not os.path.isdir(posts_dir): - os.makedirs(posts_dir) - - def writePost(self, post_info): - out_dir = os.path.join(self.out_dir, 'posts') - slug = post_info['slug'] - dtstr = post_info['datetime'].strftime('%Y-%m-%d') - with open('%s/%s_%s.md' % (out_dir, dtstr, slug), 'w', - encoding='utf8') as f: - f.write('---\n') - f.write('title: %s\n' % post_info['title']) - f.write('description: %s\n' % post_info['description']) - f.write('tags: [%s]\n' % post_info['tags']) - f.write('---\n') - - para_count = random.randint(5, 10) - for i in range(para_count): - f.write(generateSentence(random.randint(50, 100))) - f.write('\n\n') - - -class OctopressBenchmarkSiteGenerator(BenchmarkSiteGenerator): - def initialize(self): - posts_dir = os.path.join(self.out_dir, 'source', '_posts') - if not os.path.isdir(posts_dir): - os.makedirs(posts_dir) - - def writePost(self, post_info): - out_dir = os.path.join(self.out_dir, 'source', '_posts') - slug = post_info['slug'] - dtstr = post_info['datetime'].strftime('%Y-%m-%d') - with open('%s/%s-%s.markdown' % (out_dir, dtstr, slug), 'w', - encoding='utf8') as f: - f.write('---\n') - f.write('layout: post\n') - f.write('title: %s\n' % post_info['title']) - f.write('date: %s 12:00\n' % dtstr) - f.write('comments: false\n') - f.write('categories: [%s]\n' % post_info['tags']) - f.write('---\n') - - para_count = random.randint(5, 10) - for i in range(para_count): - f.write(generateSentence(random.randint(50, 100))) - f.write('\n\n') - - -class MiddlemanBenchmarkSiteGenerator(BenchmarkSiteGenerator): - def initialize(self): - posts_dir = os.path.join(self.out_dir, 'source') - if not os.path.isdir(posts_dir): - os.makedirs(posts_dir) - - def writePost(self, post_info): - out_dir = os.path.join(self.out_dir, 'source') - slug = post_info['slug'] - dtstr = post_info['datetime'].strftime('%Y-%m-%d') - with open('%s/%s-%s.html.markdown' % (out_dir, dtstr, slug), 'w', - encoding='utf8') as f: - f.write('---\n') - f.write('title: %s\n' % post_info['title']) - f.write('date: %s\n' % post_info['datetime'].strftime('%Y/%m/%d')) - f.write('tags: %s\n' % post_info['tags']) - f.write('---\n') - - para_count = random.randint(5, 10) - for i in range(para_count): - f.write(generateSentence(random.randint(50, 100))) - f.write('\n\n') - - -class HugoBenchmarkSiteGenerator(BenchmarkSiteGenerator): - def initialize(self): - posts_dir = os.path.join(self.out_dir, 'content', 'post') - if not os.path.isdir(posts_dir): - os.makedirs(posts_dir) - - def writePost(self, post_info): - out_dir = os.path.join(self.out_dir, 'content', 'post') - dtstr = post_info['datetime'].strftime('%Y-%m-%d_%H-%M-%S') - post_path = os.path.join(out_dir, '%s.md' % dtstr) - with open(post_path, 'w', encoding='utf8') as f: - f.write('+++\n') - f.write('title = "%s"\n' % post_info['title']) - f.write('description = "%s"\n' % post_info['description']) - f.write('categories = [\n "%s"\n]\n' % post_info['tags']) - f.write('date = "%s"\n' % post_info['datetime'].strftime( - "%Y-%m-%d %H:%M:%S-00:00")) - f.write('slug ="%s"\n' % post_info['slug']) - f.write('+++\n') - f.write(post_info['text']) - - -generators = { - 'piecrust': PieCrustBechmarkSiteGenerator, - 'octopress': OctopressBenchmarkSiteGenerator, - 'middleman': MiddlemanBenchmarkSiteGenerator, - 'hugo': HugoBenchmarkSiteGenerator - } - - -def main(): - parser = argparse.ArgumentParser( - prog='generate_benchsite', - description=("Generates a benchmark website with placeholder " - "content suitable for testing.")) - parser.add_argument( - 'engine', - help="The engine to generate the site for.", - choices=list(generators.keys())) - parser.add_argument( - 'out_dir', - help="The target directory for the website.") - parser.add_argument( - '-c', '--post-count', - help="The number of posts to create.", - type=int, - default=100) - parser.add_argument( - '--tag-count', - help="The number of tags to use.", - type=int, - default=30) - - result = parser.parse_args() - - print("Generating %d posts in %s..." % ( - result.post_count, result.out_dir)) - - if not os.path.exists(result.out_dir): - os.makedirs(result.out_dir) - - gen = generators[result.engine](result.out_dir) - gen.all_tags = [generateWord(3, 12) for _ in range(result.tag_count)] - gen.initialize() - - for i in range(result.post_count): - gen.generatePost() - - -if __name__ == '__main__': - main() -
--- a/util/generate_changelog.py Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -import os -import os.path -import re -import time -import argparse -import subprocess - - -hg_log_template = ("{if(tags, '>>{tags};{date|shortdate}\n')}" - "{desc|firstline}\n\n") - -re_add_tag_changeset = re.compile('^Added tag [^\s]+ for changeset [\w\d]+$') -re_merge_pr_changeset = re.compile('^Merge pull request') -re_tag = re.compile('^\d+\.\d+\.\d+([ab]\d+)?(rc\d+)?$') -re_change = re.compile('^(\w+):') -re_clean_code_span = re.compile('([^\s])``([^\s]+)') - -category_commands = [ - 'chef', 'bake', 'find', 'help', 'import', 'init', 'paths', 'plugin', - 'plugins', 'prepare', 'purge', 'root', 'routes', 'serve', - 'showconfig', 'showrecord', 'sources', 'theme', 'themes', 'admin', - 'publish'] -category_core = [ - 'internal', 'bug', 'templating', 'formatting', 'performance', - 'data', 'config', 'rendering', 'render', 'debug', 'reporting', - 'linker', 'pagination', 'routing', 'caching', 'cli'] -category_project = ['build', 'cm', 'docs', 'tests', 'setup'] -categories = [ - ('commands', category_commands), - ('core', category_core), - ('project', category_project), - ('miscellaneous', None)] -category_names = list(map(lambda i: i[0], categories)) - - -def generate(): - parser = argparse.ArgumentParser(description='Generate CHANGELOG file.') - parser.add_argument( - 'out_file', - nargs='?', - default='CHANGELOG.rst', - help='The output file.') - parser.add_argument( - '--last', - help="The version for the last few untagged changes.") - args = parser.parse_args() - - print("Generating %s" % args.out_file) - - if not os.path.exists('.hg'): - raise Exception("You must run this script from the root of a " - "Mercurial clone of the PieCrust repository.") - hglog = subprocess.check_output([ - 'hg', 'log', - '--rev', 'reverse(::master)', - '--template', hg_log_template]) - hglog = hglog.decode('utf8') - - templates = _get_templates() - - with open(args.out_file, 'w') as fp: - fp.write(templates['header']) - - skip = False - in_desc = False - current_version = 0 - current_version_info = None - current_changes = None - - if args.last: - current_version = 1 - cur_date = time.strftime('%Y-%m-%d') - current_version_info = args.last, cur_date - current_changes = {} - - for line in hglog.splitlines(): - if line == '': - skip = False - in_desc = False - continue - - if not in_desc and line.startswith('>>'): - tags, tag_date = line[2:].split(';') - if re_tag.match(tags): - if current_version > 0: - _write_version_changes( - templates, - current_version, current_version_info, - current_changes, fp) - - current_version += 1 - current_version_info = tags, tag_date - current_changes = {} - in_desc = True - else: - skip = True - continue - - if skip or current_version == 0: - continue - - if re_add_tag_changeset.match(line): - continue - if re_merge_pr_changeset.match(line): - continue - - m = re_change.match(line) - if m: - ch_type = m.group(1) - for cat_name, ch_types in categories: - if ch_types is None or ch_type in ch_types: - msgs = current_changes.setdefault(cat_name, []) - msgs.append(line) - break - else: - assert False, ("Change '%s' should have gone in the " - "misc. bucket." % line) - else: - msgs = current_changes.setdefault('miscellaneous', []) - msgs.append(line) - - if current_version > 0: - _write_version_changes( - templates, - current_version, current_version_info, - current_changes, fp) - - -def _write_version_changes(templates, version, version_info, changes, fp): - tokens = { - 'num': str(version), - 'version': version_info[0], - 'date': version_info[1]} - tpl = _multi_replace(templates['version_title'], tokens) - fp.write(tpl) - - for i, cat_name in enumerate(category_names): - msgs = changes.get(cat_name) - if not msgs: - continue - - tokens = { - 'sub_num': str(i), - 'category': cat_name.title()} - tpl = _multi_replace(templates['category_title'], tokens) - fp.write(tpl) - - for msg in msgs: - msg = msg.replace('`', '``').rstrip('\n') - msg = re_clean_code_span.sub(r'\1`` \2', msg) - fp.write('* ' + msg + '\n') - - -def _multi_replace(s, tokens): - for token in tokens: - s = s.replace('%%%s%%' % token, tokens[token]) - return s - - -def _get_templates(): - tpl_dir = os.path.join(os.path.dirname(__file__), 'changelog') - tpls = {} - for name in os.listdir(tpl_dir): - tpl = _get_template(os.path.join(tpl_dir, name)) - name_no_ext, _ = os.path.splitext(name) - tpls[name_no_ext] = tpl - return tpls - - -def _get_template(filename): - with open(filename, 'r', encoding='utf8') as fp: - return fp.read() - - -if __name__ == '__main__': - generate() -
--- a/util/generate_docs.sh Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -#!/bin/sh - -set -e - -VERSION= -ROOT_URL= -TEMP_DIR= -OUTPUT_DIR= - -ShowUsage() { - echo "Usage:" - echo " $PROG_NAME <options>" - echo "" - echo " -v [version]" - echo " -r [root_url]" - echo " -t [tmp_dir]" - echo " -o [out_dir]" - echo "" -} - -while getopts "h?v:r:t:o:" opt; do - case $opt in - h|\?) - ShowUsage - exit 0 - ;; - v) - VERSION=$OPTARG - ;; - r) - ROOT_URL=$OPTARG - ;; - t) - TEMP_DIR=$OPTARG - ;; - o) - OUTPUT_DIR=$OPTARG - ;; - esac -done - -if [ "$VERSION" = "" ]; then - echo "You need to specify a version number or label." - exit 1 -fi -if [ "$OUTPUT_DIR" = "" ]; then - echo "You need to specify an output directory." - exit 1 -fi -if [ "$TEMP_DIR" = "" ]; then - TEMP_DIR=_counter-docs -fi - -echo "Updating virtual environment..." -venv/bin/pip install -r requirements.txt --upgrade - -echo "Generate PieCrust version..." -venv/bin/python3 setup.py version - -echo "Update Bower packages..." -bower update - -echo "Baking documentation for version $VERSION..." -CHEF_ARGS="--root docs --config dist" -if [ ! "$ROOT_URL" = "" ]; then - CHEF_ARGS="$CHEF_ARGS --config-set site/root $ROOT_URL" -fi -venv/bin/python3 chef.py $CHEF_ARGS bake -o $TEMP_DIR - -echo "Synchronizing $OUTPUT_DIR" -if [ ! -d $OUTPUT_DIR ]; then - mkdir -p $OUTPUT_DIR -fi -rsync -av --delete-after $TEMP_DIR/ $OUTPUT_DIR/ -
--- a/util/generate_messages.cmd Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -@echo off -setlocal - -set CUR_DIR=%~dp0 -set CHEF=%CUR_DIR%..\bin\chef -set OUT_DIR=%CUR_DIR%..\piecrust\resources\messages -set ROOT_DIR=%CUR_DIR%messages - -%CHEF% --root=%ROOT_DIR% bake -o %OUT_DIR% -del %OUT_DIR%\index.html -
--- a/util/generate_messages.sh Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -#!/bin/sh - -CUR_DIR="$( cd "$( dirname "$0" )" && pwd )" -CHEF=${CUR_DIR}/../bin/chef -OUT_DIR=${CUR_DIR}/../piecrust/resources/messages -ROOT_DIR=${CUR_DIR}/messages - -$CHEF --root=$ROOT_DIR bake -o $OUT_DIR -rm ${OUT_DIR}/index.html
--- a/util/messages/config.yml Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -site: - title: PieCrust System Messages
--- a/util/messages/pages/_index.html Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ ---- -title: PieCrust System Messages ---- - -Here are the **PieCrust** system message pages: - -* [Requirements Not Met]({{ pcurl('requirements') }}) -* [Error]({{ pcurl('error') }}) -* [Not Found]({{ pcurl('error404') }}) -* [Critical Error]({{ pcurl('critical') }}) - -This very page you're reading, however, is only here for convenience.
--- a/util/messages/pages/critical.html Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ ---- -title: The Whole Kitchen Burned Down! -layout: error ---- -Something critically bad happened, and **PieCrust** needs to shut down. It's probably our fault. -
--- a/util/messages/pages/error.html Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ ---- -title: The Cake Just Burned! -layout: error ---- -
--- a/util/messages/pages/error404.html Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ ---- -title: Can't find the sugar! -layout: error ---- -It looks like the page you were trying to access does not exist around here. Try going somewhere else. -
--- a/util/messages/templates/default.html Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -<!doctype html> -<html> -<head> - <title>{{ page.title }}</title> - <meta name="generator" content="PieCrust" /> - <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Lobster"> - <style> - body { - margin: 0; - padding: 1em; - background: #eee; - color: #000; - font-family: Georgia, serif; - } - h1 { - font-size: 4.5em; - font-family: Lobster, 'Trebuchet MS', Verdana, sans-serif; - text-align: center; - font-weight: bold; - margin-top: 0; - color: #333; - text-shadow: 0px 2px 5px rgba(0,0,0,0.3); - } - h2 { - font-size: 2.5em; - font-family: 'Lobster', 'Trebuchet MS', Verdana, sans-serif; - } - code { - background: #ddd; - padding: 0 0.2em; - } - #preamble { - font-size: 1.2em; - font-style: italic; - text-align: center; - margin-bottom: 0; - } - #container { - margin: 0 20%; - } - #content { - margin: 2em 1em; - } - .error-details { - color: #d11; - } - .note { - margin: 3em; - color: #888; - font-style: italic; - } - </style> -</head> -<body> - <div id="container"> - <div id="header"> - <p id="preamble">A Message From The Kitchen:</p> - <h1>{{ page.title }}</h1> - </div> - <hr /> - <div id="content"> - {% block content %} - {{ content|safe }} - {% endblock %} - </div> - <hr /> - {% block footer %}{% endblock %} - </div> -</body> -</html>
--- a/util/messages/templates/error.html Sun Feb 14 22:10:05 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -{% extends "default.html" %} - -{% block content %} -{{content|safe}} - -{# The following is `raw` because we want it to be in the - produced page, so it can then be templated on the fly - with the error messages #} -{% raw %} -{% if details %} -<div class="error-details"> - <p>Error details:</p> - <ul> - {% for desc in details %} - <li>{{ desc }}</li> - {% endfor %} - </ul> -</div> -{% endif %} -{% endraw %} -{% endblock %} - -{% block footer %} -{% pcformat 'textile' %} -p(note). You're seeing this because something wrong happend. To see detailed errors with callstacks, run chef with the @--debug@ parameter, append @?!debug@ to the URL, or initialize the @PieCrust@ object with @{'debug': true}@. On the other hand, to see you custom error pages, set the @site/display_errors@ setting to @false@. -{% endpcformat %} -{% endblock %}