From 0dd58b97c669f175ba57a80af87f9d4f5e73c981 Mon Sep 17 00:00:00 2001 From: Nik Cubrilovic Date: Wed, 29 Feb 2012 00:50:49 +1100 Subject: [PATCH] implementation now uses markdown meta for post data --- floyd/main.py | 145 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 112 insertions(+), 33 deletions(-) diff --git a/floyd/main.py b/floyd/main.py index c5f1991..9791e12 100644 --- a/floyd/main.py +++ b/floyd/main.py @@ -28,10 +28,13 @@ import os import sys +import re import getopt import logging - +import datetime +import yaml import floyd +import markdown from .templating import jinja @@ -45,13 +48,27 @@ ARG_OUTPUT_DIR: 'site', } +# register markdown extension dir +sys.path = sys.path + [os.path.join(os.path.dirname(__file__), 'parsers')] + +_MARKDOWN = markdown.Markdown( + output_format='html4', + extensions = ['footnotes', 'codehilite', 'microdata', 'headerid(forceid=False)', 'meta', 'time', 'floyd'], + extension_configs= {'footnotes': [('PLACE_MARKER','++footnotes++')]}, +) -from optparse import OptionParser +# @TODO this can be a lot better +_TITLE_MATCH = re.compile('

(.*)

') + +from optparse import OptionParser, NO_DEFAULT parser = OptionParser(usage="%prog [options] ", prog=floyd.__clsname__, version="floyd v%s" % (floyd.__version__)) # parser = argparse.ArgumentParser(description='Static website generator for cloud hosting platforms', epilog='Report any issues to [Github url]') parser.add_option('-s','--src', dest='src', type='string', default='sources', help='Project source ("src" by default)') parser.add_option('-d','--dir', dest='out', type='string', default='site', help='The directory in which to create site (creates in "site" by default)') +# @TODO +parser.add_option('-w','--watch', dest='out', type='string', default='site', help='Watch contents and automatically render and deploy') +# @TODO local server def ParseArguments(argv): user_options = DEFAULT_ARGS.copy() @@ -76,54 +93,116 @@ def TemplateVars(vars): } return dict(zip(additional.keys() + vars.keys(), additional.values() + vars.values())) -def ParsePost(path): +def ParsePost(path, name): """Takes a post path and returns a dictionary of variables""" - import datetime - post_vars = {} - post = { - 'title': 'post title', - 'content': 'post content', - 'pubdate': datetime.datetime.now() - } - post_vars['post'] = post - return TemplateVars(post_vars) + if not os.path.isfile(path): + return None + + print "Parsing: %s" % name + + post = {} + fh = open(path, 'r') + fc = fh.read() + + try: + post_content = _MARKDOWN.convert(fc) + except Exception, e: + print ' - markdown error: %s' % str(e) + + if _MARKDOWN.Meta: + for key in _MARKDOWN.Meta: + print "\t meta: %s: %s (%s)" % (key, _MARKDOWN.Meta[key][0], type(_MARKDOWN.Meta[key][0])) + if key == 'pubdate': + post[key] = datetime.datetime.fromtimestamp(float(_MARKDOWN.Meta[key][0])) + else: + post[key] = _MARKDOWN.Meta[key][0] + + post['content'] = post_content + post['stub'] = name.split('.')[0] + + if not 'pubdate' in post: + print ' - setting default pubdate' + post['pubdate'] = datetime.datetime.now() + + # print "Parsed %s output:" % (name) + # for key in post: + # print "\t %s: %s" % (key, post[key]) + + return post + +def GetPosts(path): + if not os.path.isdir(path): + raise Exception('Not a valid posts directory: %s' % path) + + posts = [] + for postfile in os.listdir(path): + if postfile.startswith('.'): + continue + if postfile.endswith('.md'): + post = ParsePost(os.path.join(path, postfile), postfile) + if post: + posts.append(post) + return posts +def FindModels(sources_dir): + data_files = [] + packages = [] + for dirpath, dirnames, filenames in os.walk(sources_dir): + print 'walking: %s - %s - %s' % (dirpath, dirnames, filenames) + for i, dirname in enumerate(dirnames): + if dirname.startswith('.'): + del dirnames[i] + if '__init__.py' in filenames: + packages.append('.'.join(floyd.util.path.split(dirpath))) + elif filenames: + data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) + + +def RenderPosts(posts, outputdir): + for post in posts: + print 'rendering -- %s' % post['stub'] + template_vars = {} + template_vars['posts'] = posts[:5] + template_vars['post'] = post + template_vars = TemplateVars(template_vars) + + render = jinja.render('single', template_vars) + post_output_path = os.path.join(outputdir, post['stub']) + print 'render: %s ' % post_output_path + fp = open(post_output_path, 'w') + fp.write(render) + fp.close() + def Main(argv): (options, args) = parser.parse_args() curdir = os.getcwd() try: path_source = os.path.join(curdir, options.src) path_output = os.path.join(curdir, options.out) - path_templates = os.path.join(path_source, 'templates') - example_post = os.path.join(path_source, 'posts', 'test-post') - example_output = os.path.join(path_output, 'test-post.html') + path_templates = os.path.join(path_source, 'templates', 'default') if not os.path.isdir(path_source): parser.error('Not a valid source directory: %s' % path_source) if not os.path.isdir(path_output): parser.error('Not a valid output directory: %s' % path_output) - if not os.path.isdir(path_templates): parser.error('Not a valid template directory: %s' % path_templates) - if not os.path.isfile(example_post): - parser.error('Not a valid blog post') + + jinja.setup(path_templates) + + # FindModels(path_source) + + posts = GetPosts(os.path.join(path_source, 'posts')) + RenderPosts(posts, path_output) - except IOError as (errno, strerror): - print "Error" + except ArgumentError as (errno, strerror): + print "Error: %s" % strerror return -1 - except Exception as errstr: - print "Error: %s" % errstr - return -1 - - - template_sets = {'site': path_templates} - jinja.setup(template_sets) - - post_vars = ParsePost(example_post) - render = jinja.render('single', post_vars, 'site', 'default') - fp = open(example_output, 'w') - fp.write(render) - fp.close() + + + +class ArgumentError(Exception): + pass if __name__ == '__main__': print sys.argv