# coding: utf8 from __future__ import unicode_literals import livereload import fabric.colors as colors import fabric.contrib.project as project import fabric.contrib.files as files import fabric.api as fabric import jinja2 import path import pelican.utils as utils import collections import datetime import logging import logging.handlers import mimetypes import sys # Local path configuration (can be absolute or relative to fabfile) fabric.env.deploy_path = path.path('output') fabric.env.content_path = path.path('content') fabric.env.theme_path = path.path('../theme') fabric.env.jinja = jinja2.Environment( loader=jinja2.PackageLoader('fabfile', 'templates') ) MESSAGE_FORMAT = '%(levelname)s %(message)s' LEVELS = { 'WARNING': colors.yellow('WARN', bold=True), 'INFO': colors.blue('INFO', bold=True), 'DEBUG': colors.green('DEBUG', bold=True), 'CRITICAL': colors.magenta('CRIT', bold=True), 'ERROR': colors.red('ERROR', bold=True), } class FabricFormatter(logging.Formatter): def format(self, record): record.levelname = LEVELS.get(record.levelname) + ':' return super(FabricFormatter, self).format(record) class Server(livereload.Server): def _setup_logging(self): super(Server, self)._setup_logging() server_handler = logging.getLogger('livereload').handlers[0] server_handler.setFormatter(FabricFormatter(MESSAGE_FORMAT)) def application(env, start_response): chunk_size = 64 * 1024 def not_found(sr): sr('404 NOT FOUND', [('Content-Type', 'text/plain')]) return ['Not Found'] def serve_file(f, sr): mime = mimetypes.guess_type(f) sr('200 OK', [('Content-Type', mime[0])]) return f.chunks(chunk_size, 'rb') def list_dir(d, sr): sr('200 OK', [('Content-Type', 'text/html')]) context = { 'directory': d.relpath(fabric.env.deploy_path), 'links': [ f.relpath(d) for f in d.listdir() ] } return (fabric.env.jinja.get_template('list_dir.tplt') .stream(**context)) path = fabric.env.deploy_path + env.get('PATH_INFO') path_index = path + 'index.html' if not path.exists(): return not_found(start_response) if path.isfile(): return serve_file(path, start_response) if path_index.exists(): return serve_file(path_index, start_response) return list_dir(path, start_response) @fabric.task def clean(): if fabric.env.deploy_path.isdir(): fabric.local('rm -rf {deploy_path}'.format(**fabric.env)) fabric.local('mkdir {deploy_path}'.format(**fabric.env)) @fabric.task def build(): fabric.local('pelican -s pelicanconf.py') @fabric.task def rebuild(): clean() build() @fabric.task def regenerate(): fabric.local('pelican -r -s pelicanconf.py') @fabric.task def serve(*args): port = args[0] if len(args) > 0 else 8000 if not isinstance(port, int) or port < 1024 or port > 65535: print(colors.red('Port must be an integer between 1024 and 65535...')) return build() server = Server(application) server.watch(fabric.env.content_path, build) server.watch(fabric.env.theme_path, build) server.serve(port=port, debug=True) @fabric.task def reserve(): build() serve() @fabric.task def new_post(*args): title = args[0] if len(args) > 0 else fabric.prompt('New post title?') title = unicode(title, 'utf8') date = datetime.date.today().isoformat() filename = '.'.join([date, utils.slugify(title), 'md']) filename = fabric.env.content_path / filename print(' '.join([LEVELS['INFO'], 'Create new post:', filename])) (fabric.env.jinja.get_template('new_post.tplt') .stream(title=title) .dump(filename, 'utf8')) @fabric.task def publish(): build() fabric.local('ghp-import {0}'.format(fabric.env.deploy_path)) fabric.local('git push origin -f gh-pages:master')