1
0
Fork 0
forked from github/pelican

Merge pull request #318 from MeirKriheli/master

Generator to compile less css files
This commit is contained in:
Alexis Metaireau 2012-05-05 17:23:55 -07:00
commit 4370b51f02
7 changed files with 128 additions and 3 deletions

View file

@ -23,6 +23,7 @@ Pelican currently supports:
* Publication of articles in multiple languages
* Atom/RSS feeds
* Code syntax highlighting
* Compilation of less css (optional)
* Import from WordPress, Dotclear, or RSS feeds
* Integration with external tools: Twitter, Google Analytics, etc. (optional)

View file

@ -82,10 +82,15 @@ Setting name (default value) What does it do?
generated HTML, using the `Typogrify
<http://static.mintchaos.com/projects/typogrify/>`_
library
`LESS_GENERATOR` (``FALSE``) Set to True or complete path to `lessc` (if not
found in system PATH) to enable compiling less
css files. Requires installation of `less css`_.
================================================ =====================================================
.. [#] Default is the system locale.
.. _less css: http://lesscss.org/
URL settings
------------

View file

@ -6,7 +6,7 @@ import logging
import argparse
from pelican.generators import (ArticlesGenerator, PagesGenerator,
StaticGenerator, PdfGenerator)
StaticGenerator, PdfGenerator, LessCSSGenerator)
from pelican.log import init
from pelican.settings import read_settings, _DEFAULT_CONFIG
from pelican.utils import clean_output_dir, files_changed
@ -134,6 +134,8 @@ class Pelican(object):
generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
if self.settings['PDF_GENERATOR']:
generators.append(PdfGenerator)
if self.settings['LESS_GENERATOR']: # can be True or PATH to lessc
generators.append(LessCSSGenerator)
return generators
def get_writer(self):

View file

@ -4,6 +4,7 @@ import math
import random
import logging
import datetime
import subprocess
from collections import defaultdict
from functools import partial
@ -414,3 +415,50 @@ class PdfGenerator(Generator):
for page in self.context['pages']:
self._create_pdf(page, pdf_path)
class LessCSSGenerator(Generator):
"""Compile less css files."""
def _compile(self, less_file, source_dir, dest_dir):
base = os.path.relpath(less_file, source_dir)
target = os.path.splitext(
os.path.join(dest_dir, base))[0] + '.css'
target_dir = os.path.dirname(target)
if not os.path.exists(target_dir):
try:
os.makedirs(target_dir)
except OSError:
logger.error("Couldn't create the less css output folder in " +
target_dir)
subprocess.call([self._lessc, less_file, target])
logger.info(u' [ok] compiled %s' % base)
def generate_output(self, writer=None):
logger.info(u' Compiling less css')
# store out compiler here, so it won't be evaulted on each run of
# _compile
lg = self.settings['LESS_GENERATOR']
self._lessc = lg if isinstance(lg, basestring) else 'lessc'
# walk static paths
for static_path in self.settings['STATIC_PATHS']:
for f in self.get_files(
os.path.join(self.path, static_path),
extensions=['less']):
self._compile(f, self.path, self.output_path)
# walk theme static paths
theme_output_path = os.path.join(self.output_path, 'theme')
for static_path in self.settings['THEME_STATIC_PATHS']:
theme_static_path = os.path.join(self.theme, static_path)
for f in self.get_files(
theme_static_path,
extensions=['less']):
self._compile(f, theme_static_path, theme_output_path)

View file

@ -67,6 +67,7 @@ _DEFAULT_CONFIG = {'PATH': '.',
'DEFAULT_STATUS': 'published',
'ARTICLE_PERMALINK_STRUCTURE': '',
'TYPOGRIFY': False,
'LESS_GENERATOR': False,
}

View file

@ -4,6 +4,8 @@ __all__ = [
'unittest',
]
import os
import subprocess
from contextlib import contextmanager
from tempfile import mkdtemp
from shutil import rmtree
@ -35,3 +37,21 @@ def get_article(title, slug, content, lang, extra_metadata=None):
if extra_metadata is not None:
metadata.update(extra_metadata)
return Article(content, metadata=metadata)
def skipIfNoExecutable(executable, valid_exit_code=1):
"""Tries to run an executable to make sure it's in the path, Skips the tests
if not found.
"""
# calling with no params the command should exit with 1
with open(os.devnull, 'w') as fnull:
try:
res = subprocess.call(executable, stdout=fnull, stderr=fnull)
except OSError:
res = None
if res != valid_exit_code:
return unittest.skip('{0} compiler not found'.format(executable))
return lambda func: func

View file

@ -2,10 +2,12 @@
from mock import MagicMock
import os
import re
import subprocess
from pelican.generators import ArticlesGenerator
from pelican.generators import ArticlesGenerator, LessCSSGenerator
from pelican.settings import _DEFAULT_CONFIG
from .support import unittest
from .support import unittest, temporary_folder, skipIfNoExecutable
CUR_DIR = os.path.dirname(__file__)
@ -46,3 +48,49 @@ class TestArticlesGenerator(unittest.TestCase):
elif relfilepath == "article_without_category.rst":
self.assertEquals(article.category.name, 'Default')
class TestLessCSSGenerator(unittest.TestCase):
LESS_CONTENT = """
@color: #4D926F;
#header {
color: @color;
}
h2 {
color: @color;
}
"""
@skipIfNoExecutable('lessc')
def test_less_compiler(self):
settings = _DEFAULT_CONFIG.copy()
settings['STATIC_PATHS'] = ['static']
settings['LESS_GENERATOR'] = True
# we'll nest here for py < 2.7 compat
with temporary_folder() as temp_content:
with temporary_folder() as temp_output:
generator = LessCSSGenerator(None, settings, temp_content,
_DEFAULT_CONFIG['THEME'], temp_output, None)
# create a dummy less file
less_dir = os.path.join(temp_content, 'static', 'css')
less_filename = os.path.join(less_dir, 'test.less')
less_output = os.path.join(temp_output, 'static', 'css',
'test.css')
os.makedirs(less_dir)
with open(less_filename, 'w') as less_file:
less_file.write(self.LESS_CONTENT)
generator.generate_output()
# we have the file ?
self.assertTrue(os.path.exists(less_output))
# was it compiled ?
self.assertIsNotNone(re.search(r'^\s+color:\s*#4D926F;$',
open(less_output).read(), re.MULTILINE | re.IGNORECASE))