2010-12-02 03:22:24 +00:00
|
|
|
import argparse
|
|
|
|
|
import os
|
2011-05-06 22:05:13 +02:00
|
|
|
import time
|
2011-04-26 12:23:45 +02:00
|
|
|
import pkgutil
|
|
|
|
|
|
|
|
|
|
from blinker import signal
|
2010-12-02 03:22:24 +00:00
|
|
|
|
2011-01-12 23:45:06 +01:00
|
|
|
from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
|
|
|
|
StaticGenerator, PdfGenerator)
|
2010-12-02 03:22:24 +00:00
|
|
|
from pelican.settings import read_settings
|
2011-01-12 23:45:06 +01:00
|
|
|
from pelican.utils import clean_output_dir, files_changed
|
2010-12-02 03:22:24 +00:00
|
|
|
from pelican.writers import Writer
|
2011-04-19 14:49:46 +02:00
|
|
|
from pelican import log
|
2010-12-02 03:22:24 +00:00
|
|
|
|
2011-06-17 19:45:09 +02:00
|
|
|
VERSION = "2.7.2"
|
2010-12-18 20:36:16 +00:00
|
|
|
|
2010-12-02 03:22:24 +00:00
|
|
|
|
2010-12-25 17:26:24 +03:00
|
|
|
class Pelican(object):
|
|
|
|
|
def __init__(self, settings=None, path=None, theme=None, output_path=None,
|
2011-06-17 22:33:54 +02:00
|
|
|
markup=None, delete_outputdir=False, plugin_path=None):
|
2010-12-25 17:26:24 +03:00
|
|
|
"""Read the settings, and performs some checks on the environment
|
|
|
|
|
before doing anything else.
|
|
|
|
|
"""
|
|
|
|
|
self.path = path or settings['PATH']
|
2011-02-14 15:35:17 +01:00
|
|
|
if not self.path:
|
2011-04-20 14:44:25 +02:00
|
|
|
raise Exception('you need to specify a path containing the content'
|
|
|
|
|
' (see pelican --help for more information)')
|
|
|
|
|
|
2011-02-14 15:35:17 +01:00
|
|
|
if self.path.endswith('/'):
|
2011-06-12 18:41:29 +01:00
|
|
|
self.path = self.path[:-1]
|
2010-12-25 17:26:24 +03:00
|
|
|
|
|
|
|
|
# define the default settings
|
|
|
|
|
self.settings = settings
|
|
|
|
|
self.theme = theme or settings['THEME']
|
|
|
|
|
output_path = output_path or settings['OUTPUT_PATH']
|
|
|
|
|
self.output_path = os.path.realpath(output_path)
|
|
|
|
|
self.markup = markup or settings['MARKUP']
|
2011-05-07 19:27:33 +01:00
|
|
|
self.delete_outputdir = delete_outputdir or settings['DELETE_OUTPUT_DIRECTORY']
|
2010-12-25 17:26:24 +03:00
|
|
|
|
|
|
|
|
# find the theme in pelican.theme if the given one does not exists
|
|
|
|
|
if not os.path.exists(self.theme):
|
|
|
|
|
theme_path = os.sep.join([os.path.dirname(
|
|
|
|
|
os.path.abspath(__file__)), "themes/%s" % self.theme])
|
|
|
|
|
if os.path.exists(theme_path):
|
|
|
|
|
self.theme = theme_path
|
|
|
|
|
else:
|
|
|
|
|
raise Exception("Impossible to find the theme %s" % theme)
|
2011-04-26 12:23:45 +02:00
|
|
|
|
|
|
|
|
plugins_path = plugins_path or settings['PLUGINS_PATH']
|
|
|
|
|
if plugins_path:
|
2011-04-27 18:09:55 +02:00
|
|
|
plugins_path = os.path.abspath(os.path.expanduser(plugins_path))
|
2011-04-26 12:23:45 +02:00
|
|
|
self.load_plugins(plugins_path)
|
|
|
|
|
else:
|
|
|
|
|
self.plugins = None
|
|
|
|
|
|
|
|
|
|
signal('pelican_initialized').send(self)
|
2010-12-25 17:26:24 +03:00
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
|
"""Run the generators and return"""
|
|
|
|
|
|
|
|
|
|
context = self.settings.copy()
|
|
|
|
|
generators = [
|
|
|
|
|
cls(
|
|
|
|
|
context,
|
|
|
|
|
self.settings,
|
|
|
|
|
self.path,
|
|
|
|
|
self.theme,
|
|
|
|
|
self.output_path,
|
|
|
|
|
self.markup,
|
2011-05-07 19:27:33 +01:00
|
|
|
self.delete_outputdir
|
2010-12-25 17:26:24 +03:00
|
|
|
) for cls in self.get_generator_classes()
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
for p in generators:
|
|
|
|
|
if hasattr(p, 'generate_context'):
|
|
|
|
|
p.generate_context()
|
|
|
|
|
|
2011-05-07 19:27:33 +01:00
|
|
|
# erase the directory if it is not the source and if that's
|
|
|
|
|
# explicitely asked
|
|
|
|
|
if (self.delete_outputdir and
|
|
|
|
|
os.path.realpath(self.path).startswith(self.output_path)):
|
2010-12-25 17:26:24 +03:00
|
|
|
clean_output_dir(self.output_path)
|
|
|
|
|
|
|
|
|
|
writer = self.get_writer()
|
|
|
|
|
|
|
|
|
|
for p in generators:
|
|
|
|
|
if hasattr(p, 'generate_output'):
|
|
|
|
|
p.generate_output(writer)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_generator_classes(self):
|
|
|
|
|
generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
|
|
|
|
|
if self.settings['PDF_GENERATOR']:
|
|
|
|
|
generators.append(PdfGenerator)
|
|
|
|
|
return generators
|
|
|
|
|
|
|
|
|
|
def get_writer(self):
|
2011-02-15 14:36:55 +01:00
|
|
|
return Writer(self.output_path, settings=self.settings)
|
2011-04-26 12:23:45 +02:00
|
|
|
|
2011-06-17 22:33:54 +02:00
|
|
|
def load_plugins(self, path):
|
2011-04-26 12:23:45 +02:00
|
|
|
loaded = []
|
|
|
|
|
for module_loader, name, ispkg in pkgutil.walk_packages(path=[path,]):
|
2011-06-17 22:33:54 +02:00
|
|
|
loaded.append(module_loader.find_module(name).load_module(name))
|
2011-04-26 12:23:45 +02:00
|
|
|
self.plugins = loaded
|
|
|
|
|
|
2010-12-02 03:22:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
parser = argparse.ArgumentParser(description="""A tool to generate a
|
|
|
|
|
static blog, with restructured text input files.""")
|
|
|
|
|
|
2011-02-11 15:36:51 +01:00
|
|
|
parser.add_argument(dest='path', nargs='?',
|
2010-12-02 03:22:24 +00:00
|
|
|
help='Path where to find the content files')
|
|
|
|
|
parser.add_argument('-t', '--theme-path', dest='theme',
|
2011-04-26 02:37:56 +02:00
|
|
|
help='Path where to find the theme templates. If not specified, it'
|
|
|
|
|
'will use the default one included with pelican.')
|
2010-12-02 03:22:24 +00:00
|
|
|
parser.add_argument('-o', '--output', dest='output',
|
|
|
|
|
help='Where to output the generated files. If not specified, a directory'
|
|
|
|
|
' will be created, named "output" in the current path.')
|
2010-12-18 20:18:48 +00:00
|
|
|
parser.add_argument('-m', '--markup', default=None, dest='markup',
|
2011-04-26 02:39:57 +02:00
|
|
|
help='the list of markup language to use (rst or md). Please indicate '
|
|
|
|
|
'them separated by commas')
|
2011-06-16 12:46:40 +00:00
|
|
|
parser.add_argument('-s', '--settings', dest='settings', default='',
|
2011-06-17 22:33:54 +02:00
|
|
|
help='the settings of the application.')
|
2011-05-07 19:27:33 +01:00
|
|
|
parser.add_argument('-d', '--delete-output-directory', dest='delete_outputdir',
|
|
|
|
|
action='store_true', help='Delete the output directory.')
|
2011-04-19 14:49:46 +02:00
|
|
|
parser.add_argument('-v', '--verbose', action='store_const', const=log.INFO, dest='verbosity',
|
|
|
|
|
help='Show all messages')
|
|
|
|
|
parser.add_argument('-q', '--quiet', action='store_const', const=log.CRITICAL, dest='verbosity',
|
|
|
|
|
help='Show only critical errors')
|
|
|
|
|
parser.add_argument('-D', '--debug', action='store_const', const=log.DEBUG, dest='verbosity',
|
|
|
|
|
help='Show all message, including debug messages')
|
2010-12-18 20:36:16 +00:00
|
|
|
parser.add_argument('--version', action='version', version=VERSION,
|
2011-01-12 23:45:06 +01:00
|
|
|
help='Print the pelican version and exit')
|
|
|
|
|
parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true',
|
|
|
|
|
help="Relaunch pelican each time a modification occurs on the content"
|
|
|
|
|
"files")
|
2011-04-26 12:23:45 +02:00
|
|
|
parser.add_argument('-p', '--plugins', default=None, dest='plugins_path',
|
|
|
|
|
help='the path of plugins to use')
|
2010-12-02 03:22:24 +00:00
|
|
|
args = parser.parse_args()
|
2010-12-18 20:18:48 +00:00
|
|
|
|
2011-04-19 14:49:46 +02:00
|
|
|
log.init(args.verbosity)
|
2010-12-18 20:18:48 +00:00
|
|
|
# Split the markup languages only if some have been given. Otherwise, populate
|
|
|
|
|
# the variable with None.
|
|
|
|
|
markup = [a.strip().lower() for a in args.markup.split(',')] if args.markup else None
|
2010-12-02 03:22:24 +00:00
|
|
|
|
2010-12-25 17:26:24 +03:00
|
|
|
settings = read_settings(args.settings)
|
|
|
|
|
|
|
|
|
|
cls = settings.get('PELICAN_CLASS')
|
|
|
|
|
if isinstance(cls, basestring):
|
|
|
|
|
module, cls_name = cls.rsplit('.', 1)
|
|
|
|
|
module = __import__(module)
|
|
|
|
|
cls = getattr(module, cls_name)
|
|
|
|
|
|
2011-04-20 14:44:25 +02:00
|
|
|
try:
|
2011-05-07 19:27:33 +01:00
|
|
|
pelican = cls(settings, args.path, args.theme, args.output, markup,
|
2011-06-17 22:33:54 +02:00
|
|
|
args.delete_outputdir, args.plugins_path)
|
2011-04-20 14:44:25 +02:00
|
|
|
if args.autoreload:
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
2011-05-15 12:14:03 +02:00
|
|
|
# Check source dir for changed files ending with the given
|
|
|
|
|
# extension in the settings. In the theme dir is no such
|
|
|
|
|
# restriction; all files are recursively checked if they
|
|
|
|
|
# have changed, no matter what extension the filenames
|
|
|
|
|
# have.
|
|
|
|
|
if files_changed(pelican.path, pelican.markup) or \
|
|
|
|
|
files_changed(pelican.theme, ['']):
|
2011-04-20 14:44:25 +02:00
|
|
|
pelican.run()
|
2011-05-06 22:09:49 +02:00
|
|
|
time.sleep(.5) # sleep to avoid cpu load
|
2011-04-20 14:44:25 +02:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
|
break
|
|
|
|
|
else:
|
2011-04-19 14:49:46 +02:00
|
|
|
pelican.run()
|
2011-04-20 14:44:25 +02:00
|
|
|
except Exception, e:
|
|
|
|
|
log.critical(str(e))
|
2010-12-02 03:22:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
main()
|