diff --git a/pelican/__init__.py b/pelican/__init__.py index e1636149..1b73fc97 100755 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -7,6 +7,7 @@ from pelican.generators import (ArticlesGenerator, PagesGenerator, from pelican.settings import read_settings from pelican.utils import clean_output_dir, files_changed from pelican.writers import Writer +from pelican import log VERSION = "2.6.0" @@ -103,6 +104,12 @@ def main(): action='store_true', help='Keep the output directory and just update all the generated files.' 'Default is to delete the output directory.') + 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') parser.add_argument('--version', action='version', version=VERSION, help='Print the pelican version and exit') parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true', @@ -110,6 +117,7 @@ def main(): "files") args = parser.parse_args() + log.init(args.verbosity) # 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 @@ -134,7 +142,10 @@ def main(): except KeyboardInterrupt: break else: - pelican.run() + try: + pelican.run() + except Exception, e: + log.critical(str(e)) if __name__ == '__main__': diff --git a/pelican/contents.py b/pelican/contents.py index 7097e946..dc6bfceb 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from pelican.utils import slugify, truncate_html_words - +from pelican.log import * class Page(object): """Represents a page @@ -91,5 +91,5 @@ def is_valid_content(content, f): content.check_properties() return True except NameError as e: - print u" [info] Skipping %s: impossible to find informations about '%s'" % (f, e) + error(u"Skipping %s: impossible to find informations about '%s'" % (f, e)) return False diff --git a/pelican/generators.py b/pelican/generators.py index e87f7cea..5a1f71b7 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -14,6 +14,7 @@ from jinja2.exceptions import TemplateNotFound from pelican.utils import copytree, get_relative_path, process_translations, open from pelican.contents import Article, Page, is_valid_content from pelican.readers import read_file +from pelican.log import * class Generator(object): @@ -321,7 +322,7 @@ class PdfGenerator(Generator): output_pdf=os.path.join(output_path, filename) # print "Generating pdf for", obj.filename, " in ", output_pdf self.pdfcreator.createPdf(text=open(obj.filename), output=output_pdf) - print u' [ok] writing %s' % output_pdf + info(u' [ok] writing %s' % output_pdf) def generate_context(self): pass @@ -329,12 +330,12 @@ class PdfGenerator(Generator): def generate_output(self, writer=None): # we don't use the writer passed as argument here # since we write our own files - print u' Generating PDF files...' + info(u' Generating PDF files...') pdf_path = os.path.join(self.output_path, 'pdf') try: os.mkdir(pdf_path) except OSError: - print "Couldn't create the pdf output folder in ", pdf_path + error("Couldn't create the pdf output folder in " + pdf_path) pass for article in self.context['articles']: diff --git a/pelican/log.py b/pelican/log.py new file mode 100644 index 00000000..ebe1df5b --- /dev/null +++ b/pelican/log.py @@ -0,0 +1,97 @@ +import logging +import sys +import os + +global ANSI +ANSI = { + 'gray' : lambda(text) : '\033[1;30m' + unicode(text) + '\033[1;m', + 'red' : lambda(text) : '\033[1;31m' + unicode(text) + '\033[1;m', + 'green' : lambda(text) : '\033[1;32m' + unicode(text) + '\033[1;m', + 'yellow' : lambda(text) : '\033[1;33m' + unicode(text) + '\033[1;m', + 'blue' : lambda(text) : '\033[1;34m' + unicode(text) + '\033[1;m', + 'magenta' : lambda(text) : '\033[1;35m' + unicode(text) + '\033[1;m', + 'cyan' : lambda(text) : '\033[1;36m' + unicode(text) + '\033[1;m', + 'white' : lambda(text) : '\033[1;37m' + unicode(text) + '\033[1;m', + 'crimson' : lambda(text) : '\033[1;38m' + unicode(text) + '\033[1;m', + 'bgred' : lambda(text) : '\033[1;41m' + unicode(text) + '\033[1;m', + 'bggreen' : lambda(text) : '\033[1;42m' + unicode(text) + '\033[1;m', + 'bgbrown' : lambda(text) : '\033[1;43m' + unicode(text) + '\033[1;m', + 'bgblue' : lambda(text) : '\033[1;44m' + unicode(text) + '\033[1;m', + 'bgmagenta' : lambda(text) : '\033[1;45m' + unicode(text) + '\033[1;m', + 'bgcyan' : lambda(text) : '\033[1;46m' + unicode(text) + '\033[1;m', + 'bggray' : lambda(text) : '\033[1;47m' + unicode(text) + '\033[1;m', + 'bgcrimson' : lambda(text) : '\033[1;48m' + unicode(text) + '\033[1;m' +} + +class ANSIFormatter(logging.Formatter): + """ + Convert a `logging.LogReport' object into colored text, using ANSI escape sequences. + """ + ## colors: + + def format(self, record): + if not record.levelname or record.levelname is 'INFO': + return ANSI['white'](record.msg) + elif record.levelname is 'WARNING': + return ANSI['yellow'](record.levelname) + ': ' + record.msg + elif record.levelname is 'ERROR': + return ANSI['red'](record.levelname) + ': ' + record.msg + elif record.levelname is 'CRITICAL': + return ANSI['bgred'](record.levelname) + ': ' + record.msg + + +class TextFormatter(logging.Formatter): + """ + Convert a `logging.LogReport' object into text. + """ + + def format(self, record): + if not record.levelname or record.levelname is 'INFO': + return record.msg + else: + return record.levelname + ': ' + record.msg + + +class Formatter(object): + """ + A dummy class. + Return an instance of the appropriate formatter (ANSIFormatter if sys.stdout.isatty() is True, else TextFormatter) + """ + + def __new__(cls, *args, **kwargs): + if os.isatty(sys.stdout.fileno()): # thanks to http://stackoverflow.com/questions/2086961/how-can-i-determine-if-a-python-script-is-executed-from-crontab/2087031#2087031 + return ANSIFormatter(*args, **kwargs) + else: + return TextFormatter( *args, **kwargs) + + + +# shortcuts +debug, info, warn, error, critical = (logging.debug, + logging.info, + logging.warn, + logging.error, + logging.critical) +DEBUG, INFO, WARN, ERROR, CRITICAL = (logging.DEBUG, + logging.INFO, + logging.WARN, + logging.ERROR, + logging.CRITICAL) + + +def init(level=None, logger=logging.getLogger(), handler=logging.StreamHandler()): + fmt = Formatter() + handler.setFormatter(fmt) + logger.addHandler(handler) + if level: logger.setLevel(level) + + +if __name__ == '__main__': + init() + logging.basicConfig(filename='example.log',level=logging.DEBUG) + logging.debug('Logging test') + logging.info('info') + logging.warning('warning') + logging.error('error') + logging.critical('critical') + diff --git a/pelican/utils.py b/pelican/utils.py index 4fe9820f..732b1830 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -6,6 +6,7 @@ from datetime import datetime from codecs import open as _open from itertools import groupby from operator import attrgetter +from pelican.log import * def get_date(string): @@ -50,7 +51,7 @@ def copytree(path, origin, destination, topath=None): fromp = os.path.expanduser(os.path.join(origin, path)) to = os.path.expanduser(os.path.join(destination, topath)) shutil.copytree(fromp, to) - print u' [ok] copying %s to %s' % (fromp, to) + info('copying %s to %s' % (fromp, to)) except OSError: pass @@ -162,7 +163,7 @@ def process_translations(content_list): ) len_ = len(default_lang_items) if len_ > 1: - print u' [warning] there are %s variants of "%s"' % (len_, slug) + warning(u'there are %s variants of "%s"' % (len_, slug)) elif len_ == 0: default_lang_items = items[:1] diff --git a/pelican/writers.py b/pelican/writers.py index 2b168bcb..ae407743 100644 --- a/pelican/writers.py +++ b/pelican/writers.py @@ -8,6 +8,7 @@ import locale from feedgenerator import Atom1Feed, Rss201rev2Feed from pelican.utils import get_relative_path from pelican.paginator import Paginator +from pelican.log import * class Writer(object): @@ -68,7 +69,7 @@ class Writer(object): pass fp = open(complete_path, 'w') feed.write(fp, 'utf-8') - print u' [ok] writing %s' % complete_path + info('writing %s' % complete_path) fp.close() return feed @@ -103,7 +104,7 @@ class Writer(object): pass with open(filename, 'w', encoding='utf-8') as f: f.write(output) - print u' [ok] writing %s' % filename + info(u'writing %s' % filename) localcontext = context.copy() if relative_urls: