rant/build.py
from io import open
import os
import re
import yaml
import time
import logging
from datetime import datetime
from fnmatch import fnmatch
from jinja2 import Environment, FileSystemLoader
from rant.parse import Parser
from distutils.dir_util import copy_tree
class Builder(object):
"""Generate web-ready static files from templates/data/config"""
def __init__(self, source_dir='.', dest_dir='./deploy'):
self._source_dir = source_dir
self._dest_dir = dest_dir
with open('%s/config.yml' % source_dir, 'r') as fh:
self.config = yaml.load(fh)
fh.close()
self._page_files = self._find_source_files('page')
self._post_files = self._find_source_files('post')
self._per_page = self.config['paginate']
self._navigation = self._get_navigation()
self._env = Environment(
loader=FileSystemLoader('%s/layouts/' % self._source_dir)
)
def _find_source_files(self, layout):
source_files = []
file_names = os.listdir('%s/%ss' % (self._source_dir, layout))
for file_name in file_names:
if fnmatch(file_name, '*.md'):
full_filename = '%s/%ss/%s' % (self._source_dir,
layout,
file_name)
source_files.append(full_filename)
return source_files
def _get_navigation(self):
navigation = ['blog']
for filepath in self._page_files:
filename = os.path.split(filepath)[1]
nav_item = filename.split('.')[0].replace('_', ' ').lower()
navigation.append(nav_item)
return navigation
def _render_html(self, context):
template = self._env.get_template('%s.html' % context['layout'])
current_page = context['permalink']
if context['layout'] == 'post':
current_page = 'blog'
context['config'] = self.config
context['navigation'] = self._navigation
context['current_page'] = current_page
return template.render(context)
def _write_file(self, content, permalink, filename='index.html'):
save_folder = '%s/%s' % (self._dest_dir, permalink)
if not os.path.isdir(save_folder):
os.makedirs(save_folder)
filepath = "%s/%s" % (save_folder, filename)
with open(filepath, 'w', 1) as save_fh:
save_fh.write(content)
save_fh.close()
logging.info("-> '%s'" % filepath)
def _gen_contexts(self, filenames):
contexts = []
for filename in filenames:
context = Parser(filename).parse()
if context is None:
break
context['rendered_html'] = self._render_html(context)
contexts.append(context)
contexts.sort(key=lambda c: c['date'])
return contexts
def _write_contexts(self, contexts):
for context in contexts:
self._write_file(context['rendered_html'], context['permalink'])
def _render_blog_index_page(self, page_posts, page_num):
post_count = len(self._post_files)
total_index_pages = int(round(post_count / self._per_page, 0))
index_template = self._env.get_template('blog_index.html')
rendered_page = index_template.render(
config=self.config,
page_posts=page_posts,
total_pages=total_index_pages,
page_num=page_num,
navigation=self._navigation,
current_page='blog',
)
return rendered_page
def _write_blog_index_page(self, page_posts, page_num):
rendered_page = self._render_blog_index_page(page_posts, page_num)
if page_num == 1:
self._write_file(rendered_page, '')
self._write_file(rendered_page, 'blog')
self._write_file(
rendered_page,
'blog/pages/%s' % page_num
)
def _write_blog_index(self, posts):
index_posts = []
processed = 0
page_num = 1
for post in posts:
index_posts.append(post)
processed += 1
if len(index_posts) == self._per_page or processed == len(posts):
self._write_blog_index_page(index_posts, page_num)
page_num += 1
index_posts = []
def _write_feed(self, schema, posts):
template = self._env.get_template('%s.xml' % schema)
rendered_feed = template.render(
config=self.config,
posts=posts,
current_date=datetime.fromtimestamp(time.time()),
)
self._write_file(rendered_feed, 'blog', '%s.xml' % schema)
def _write_sitemap(self, posts, pages):
template = self._env.get_template('sitemap.xml')
rendered_feed = template.render(
config=self.config,
posts=posts,
pages=pages,
current_date=datetime.fromtimestamp(time.time()),
)
self._write_file(rendered_feed, '', 'sitemap.xml')
def _copy_static(self):
copy_tree("%s/static" % self._source_dir, self._dest_dir)
def build(self):
start_time = time.time()
logging.info("\nGenerating Pages...")
logging.info(("="*50))
page_contexts = self._gen_contexts(self._page_files)
self._write_contexts(page_contexts)
logging.info("\nGenerating Posts...")
logging.info(("="*50))
post_contexts = self._gen_contexts(self._post_files)
self._write_contexts(post_contexts)
logging.info("\nGenerating Blog Index...")
logging.info(("="*50))
self._write_blog_index(post_contexts)
logging.info("\nGenerating Feeds...")
logging.info(("="*50))
self._write_feed('atom', post_contexts)
self._write_feed('rss', post_contexts)
logging.info("\nGenerating Sitemap...")
logging.info(("="*50))
self._write_sitemap(post_contexts, page_contexts)
logging.info("\nCopying Static Files...")
logging.info(("="*50))
total_time = round(time.time() - start_time, 2)
logging.info("\nGeneration Completed in %s seconds" % total_time)
self._copy_static()