fabfile.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # coding: utf8
  2. from __future__ import unicode_literals
  3. import livereload
  4. import fabric.colors as colors
  5. import fabric.contrib.project as project
  6. import fabric.contrib.files as files
  7. import fabric.api as fabric
  8. import jinja2
  9. import path
  10. import pelican.utils as utils
  11. import collections
  12. import datetime
  13. import logging
  14. import logging.handlers
  15. import mimetypes
  16. import sys
  17. # Local path configuration (can be absolute or relative to fabfile)
  18. fabric.env.deploy_path = path.path('output')
  19. fabric.env.content_path = path.path('content')
  20. fabric.env.theme_path = path.path('../theme')
  21. fabric.env.jinja = jinja2.Environment(
  22. loader=jinja2.PackageLoader('fabfile', 'templates')
  23. )
  24. MESSAGE_FORMAT = '%(levelname)s %(message)s'
  25. LEVELS = {
  26. 'WARNING': colors.yellow('WARN', bold=True),
  27. 'INFO': colors.blue('INFO', bold=True),
  28. 'DEBUG': colors.green('DEBUG', bold=True),
  29. 'CRITICAL': colors.magenta('CRIT', bold=True),
  30. 'ERROR': colors.red('ERROR', bold=True),
  31. }
  32. class FabricFormatter(logging.Formatter):
  33. def format(self, record):
  34. record.levelname = LEVELS.get(record.levelname) + ':'
  35. return super(FabricFormatter, self).format(record)
  36. class Server(livereload.Server):
  37. def _setup_logging(self):
  38. super(Server, self)._setup_logging()
  39. server_handler = logging.getLogger('livereload').handlers[0]
  40. server_handler.setFormatter(FabricFormatter(MESSAGE_FORMAT))
  41. def application(env, start_response):
  42. chunk_size = 64 * 1024
  43. def not_found(sr):
  44. sr('404 NOT FOUND', [('Content-Type', 'text/plain')])
  45. return ['Not Found']
  46. def serve_file(f, sr):
  47. mime = mimetypes.guess_type(f)
  48. sr('200 OK', [('Content-Type', mime[0])])
  49. return f.chunks(chunk_size, 'rb')
  50. def list_dir(d, sr):
  51. sr('200 OK', [('Content-Type', 'text/html')])
  52. context = {
  53. 'directory': d.relpath(fabric.env.deploy_path),
  54. 'links': [ f.relpath(d) for f in d.listdir() ]
  55. }
  56. return (fabric.env.jinja.get_template('list_dir.tplt')
  57. .stream(**context))
  58. path = fabric.env.deploy_path + env.get('PATH_INFO')
  59. path_index = path + 'index.html'
  60. if not path.exists():
  61. return not_found(start_response)
  62. if path.isfile():
  63. return serve_file(path, start_response)
  64. if path_index.exists():
  65. return serve_file(path_index, start_response)
  66. return list_dir(path, start_response)
  67. @fabric.task
  68. def clean():
  69. if fabric.env.deploy_path.isdir():
  70. fabric.local('rm -rf {deploy_path}'.format(**fabric.env))
  71. fabric.local('mkdir {deploy_path}'.format(**fabric.env))
  72. @fabric.task
  73. def build():
  74. fabric.local('pelican -s pelicanconf.py')
  75. @fabric.task
  76. def rebuild():
  77. clean()
  78. build()
  79. @fabric.task
  80. def regenerate():
  81. fabric.local('pelican -r -s pelicanconf.py')
  82. @fabric.task
  83. def serve(*args):
  84. port = args[0] if len(args) > 0 else 8000
  85. if not isinstance(port, int) or port < 1024 or port > 65535:
  86. print(colors.red('Port must be an integer between 1024 and 65535...'))
  87. return
  88. build()
  89. server = Server(application)
  90. server.watch(fabric.env.content_path, build)
  91. server.watch(fabric.env.theme_path, build)
  92. server.serve(port=port, debug=True)
  93. @fabric.task
  94. def reserve():
  95. build()
  96. serve()
  97. @fabric.task
  98. def new_post(*args):
  99. title = args[0] if len(args) > 0 else fabric.prompt('New post title?')
  100. title = unicode(title, 'utf8')
  101. date = datetime.date.today().isoformat()
  102. filename = '.'.join([date, utils.slugify(title), 'md'])
  103. filename = fabric.env.content_path / filename
  104. print(' '.join([LEVELS['INFO'], 'Create new post:', filename]))
  105. (fabric.env.jinja.get_template('new_post.tplt')
  106. .stream(title=title)
  107. .dump(filename, 'utf8'))
  108. @fabric.task
  109. def publish():
  110. build()
  111. fabric.local('ghp-import {0}'.format(fabric.env.deploy_path))
  112. fabric.local('git push origin -f gh-pages:master')