1
0
Fork 0
forked from github/pelican

Add Multi-theme support

Adds multi-theme support using the new THEMES setting.
You can specify all the themes that you will be using in python
dicionary form. You can then inherit from the themes specified
in THEMES using the corresponding key in the dictionary.
This commit is contained in:
th3aftermath 2014-04-23 23:39:12 -04:00 committed by Ondrej Grover
commit b00d9ef6d1
8 changed files with 119 additions and 41 deletions

View file

@ -47,6 +47,7 @@ class Pelican(object):
self.path = settings['PATH']
self.theme = settings['THEME']
self.themes = settings['THEMES']
self.output_path = settings['OUTPUT_PATH']
self.ignore_files = settings['IGNORE_FILES']
self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY']
@ -87,6 +88,10 @@ class Pelican(object):
def _handle_deprecation(self):
if self.settings['EXTRA_TEMPLATES_PATHS']:
logger.warning('`EXTRA_TEMPLATES_PATHS` is soon to be deprecated.'
' Use the `THEMES` setting for the same behaviour')
if self.settings.get('CLEAN_URLS', False):
logger.warning('Found deprecated `CLEAN_URLS` in settings.'
' Modifying the following settings for the'
@ -154,6 +159,7 @@ class Pelican(object):
settings=self.settings,
path=self.path,
theme=self.theme,
themes=self.themes,
output_path=self.output_path,
) for cls in self.get_generator_classes()
]
@ -360,9 +366,12 @@ def main():
for static_path in settings.get("STATIC_PATHS", []):
watchers[static_path] = folder_watcher(static_path, [''], pelican.ignore_files)
for theme in pelican.themes:
watchers[theme] = folder_watcher(pelican.themes[theme], [''], pelican.ignore_files)
try:
if args.autoreload:
print(' --- AutoReload Mode: Monitoring `content`, `theme` and'
print(' --- AutoReload Mode: Monitoring `content`, `theme`, and'
' `settings` for changes. ---')
def _ignore_cache(pelican_obj):
@ -372,7 +381,7 @@ def main():
while True:
try:
# Check source dir for changed files ending with the given
# extension in the settings. In the theme dir is no such
# extension in the settings. In the theme dir there is no such
# restriction; all files are recursively checked if they
# have changed, no matter what extension the filenames
# have.

View file

@ -33,12 +33,13 @@ logger = logging.getLogger(__name__)
class Generator(object):
"""Baseclass generator"""
def __init__(self, context, settings, path, theme, output_path,
def __init__(self, context, settings, path, theme, themes, output_path,
readers_cache_name='', **kwargs):
self.context = context
self.settings = settings
self.path = path
self.theme = theme
self.themes = themes
self.output_path = output_path
for arg, value in kwargs.items():
@ -57,14 +58,25 @@ class Generator(object):
simple_loader = FileSystemLoader(os.path.join(theme_path,
"themes", "simple", "templates"))
themes = {}
for theme in self.themes:
templates_path = os.path.join(self.themes[theme], "templates")
logger.debug('Template path for theme %s: %s', theme,
templates_path)
themes[theme] = FileSystemLoader(templates_path)
loader=ChoiceLoader([
FileSystemLoader(self._templates_path),
simple_loader, # implicit inheritance
PrefixLoader({'!simple':simple_loader}),
PrefixLoader(themes) # explicit one
])
self.env = Environment(
trim_blocks=True,
lstrip_blocks=True,
loader=ChoiceLoader([
FileSystemLoader(self._templates_path),
simple_loader, # implicit inheritance
PrefixLoader({'!simple': simple_loader}) # explicit one
]),
loader=loader,
extensions=self.settings['JINJA_EXTENSIONS'],
)
@ -717,6 +729,12 @@ class StaticGenerator(Generator):
self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.theme,
self.settings['THEME_STATIC_DIR'], self.output_path,
os.curdir)
for theme in self.themes:
self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.themes[theme],
self.settings['THEME_STATIC_DIR'], self.output_path,
os.curdir)
# copy all Static files
for sc in self.context['staticfiles']:
source_path = os.path.join(self.path, sc.source_path)

View file

@ -34,6 +34,7 @@ DEFAULT_CONFIG = {
'PAGE_PATHS': ['pages'],
'PAGE_EXCLUDES': [],
'THEME': DEFAULT_THEME,
'THEMES': {},
'OUTPUT_PATH': 'output',
'READERS': {},
'STATIC_PATHS': ['images'],
@ -164,6 +165,13 @@ def read_settings(path=None, override=None):
elif local_settings['PLUGIN_PATHS'] is not None:
local_settings['PLUGIN_PATHS'] = [os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(path), pluginpath)))
if not isabs(pluginpath) else pluginpath for pluginpath in local_settings['PLUGIN_PATHS']]
if 'THEMES' in local_settings and local_settings['THEMES']:
for p in local_settings['THEMES']:
if not isabs(local_settings['THEMES'][p]):
absp = os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(path), local_settings['THEMES'][p])))
if os.path.exists(absp):
local_settings['THEMES'][p] = absp
else:
local_settings = copy.deepcopy(DEFAULT_CONFIG)
@ -223,6 +231,18 @@ def configure_settings(settings):
raise Exception("Could not find the theme %s"
% settings['THEME'])
for theme in settings['THEMES']:
if not os.path.isdir(settings['THEMES'][theme]):
theme_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'themes',
settings['THEMES'][theme])
if os.path.exists(theme_path):
settings['THEMES'][theme] = theme_path
else:
raise Exception("Could not find the theme %s"
% theme)
# make paths selected for writing absolute if necessary
settings['WRITE_SELECTED'] = [
os.path.abspath(path) for path in

View file

@ -28,7 +28,7 @@ class TestGenerator(unittest.TestCase):
self.settings = get_settings()
self.settings['READERS'] = {'asc': None}
self.generator = Generator(self.settings.copy(), self.settings,
CUR_DIR, self.settings['THEME'], None)
CUR_DIR, self.settings['THEME'], self.settings['THEMES'], None)
def tearDown(self):
locale.setlocale(locale.LC_ALL, self.old_locale)
@ -48,7 +48,8 @@ class TestGenerator(unittest.TestCase):
generator = Generator(context=self.settings.copy(),
settings=self.settings,
path=os.path.join(CUR_DIR, 'nested_content'),
theme=self.settings['THEME'], output_path=None)
theme=self.settings['THEME'], themes=self.settings['THEMES'],
output_path=None)
filepaths = generator.get_files(paths=['maindir'])
found_files = {os.path.basename(f) for f in filepaths}
@ -86,7 +87,7 @@ class TestArticlesGenerator(unittest.TestCase):
cls.generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
cls.generator.generate_context()
cls.articles = cls.distill_articles(cls.generator.articles)
@ -106,7 +107,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['CACHE_PATH'] = self.temp_cache
generator = ArticlesGenerator(
context=settings, settings=settings,
path=None, theme=settings['THEME'], output_path=None)
path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
writer = MagicMock()
generator.generate_feeds(writer)
writer.write_feed.assert_called_with([], settings,
@ -114,7 +115,7 @@ class TestArticlesGenerator(unittest.TestCase):
generator = ArticlesGenerator(
context=settings, settings=get_settings(FEED_ALL_ATOM=None),
path=None, theme=settings['THEME'], output_path=None)
path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
writer = MagicMock()
generator.generate_feeds(writer)
self.assertFalse(writer.write_feed.called)
@ -187,7 +188,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['filenames'] = {}
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
# test for name
# categories are grouped by slug; if two categories have the same slug
@ -210,7 +211,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['CACHE_PATH'] = self.temp_cache
generator = ArticlesGenerator(
context=settings, settings=settings,
path=None, theme=settings['THEME'], output_path=None)
path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_with("archives.html",
@ -225,7 +226,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['CACHE_PATH'] = self.temp_cache
generator = ArticlesGenerator(
context=settings, settings=settings,
path=None, theme=settings['THEME'], output_path=None)
path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_with("archives/index.html",
@ -241,7 +242,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['CACHE_PATH'] = self.temp_cache
generator = ArticlesGenerator(
context=settings, settings=settings,
path=None, theme=settings['THEME'], output_path=None)
path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
write = MagicMock()
generator.generate_direct_templates(write)
self.assertEqual(write.call_count, 0)
@ -268,7 +269,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['CACHE_PATH'] = self.temp_cache
generator = ArticlesGenerator(
context=settings, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
write = MagicMock()
generator.generate_period_archives(write)
@ -285,7 +286,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['MONTH_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/{date:%b}/index.html'
generator = ArticlesGenerator(
context=settings, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
write = MagicMock()
generator.generate_period_archives(write)
@ -303,7 +304,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['DAY_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/{date:%b}/{date:%d}/index.html'
generator = ArticlesGenerator(
context=settings, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
write = MagicMock()
generator.generate_period_archives(write)
@ -337,13 +338,13 @@ class TestArticlesGenerator(unittest.TestCase):
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator, '_cache'))
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
generator.readers.read_file.assert_called_count == 0
@ -356,13 +357,13 @@ class TestArticlesGenerator(unittest.TestCase):
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator.readers, '_cache'))
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
readers = generator.readers.readers
for reader in readers.values():
reader.read = MagicMock()
@ -380,7 +381,7 @@ class TestArticlesGenerator(unittest.TestCase):
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
self.assertTrue(hasattr(generator, '_cache_open'))
@ -389,7 +390,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings['LOAD_CONTENT_CACHE'] = False
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
generator.readers.read_file.assert_called_count == orig_call_count
@ -418,7 +419,7 @@ class TestPageGenerator(unittest.TestCase):
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
path=CUR_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
pages = self.distill_pages(generator.pages)
hidden_pages = self.distill_pages(generator.hidden_pages)
@ -449,13 +450,13 @@ class TestPageGenerator(unittest.TestCase):
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator, '_cache'))
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
generator.readers.read_file.assert_called_count == 0
@ -468,13 +469,13 @@ class TestPageGenerator(unittest.TestCase):
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator.readers, '_cache'))
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
readers = generator.readers.readers
for reader in readers.values():
reader.read = MagicMock()
@ -492,7 +493,7 @@ class TestPageGenerator(unittest.TestCase):
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
self.assertTrue(hasattr(generator, '_cache_open'))
@ -501,7 +502,7 @@ class TestPageGenerator(unittest.TestCase):
settings['LOAD_CONTENT_CACHE'] = False
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
generator.readers.read_file.assert_called_count == orig_call_count
@ -522,7 +523,8 @@ class TestPageGenerator(unittest.TestCase):
]
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
path=CUR_DIR, theme=settings['THEME'], themes=settings['THEMES'],
output_path=None)
generator.generate_context()
pages = self.distill_pages(generator.pages)
self.assertEqual(pages_expected_sorted_by_filename, pages)
@ -538,7 +540,8 @@ class TestPageGenerator(unittest.TestCase):
settings['PAGE_ORDER_BY'] = 'title'
generator = PagesGenerator(
context=settings.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
path=CUR_DIR, theme=settings['THEME'], themes=settings['THEMES'],
output_path=None)
generator.generate_context()
pages = self.distill_pages(generator.pages)
self.assertEqual(pages_expected_sorted_by_title, pages)
@ -570,7 +573,7 @@ class TestTemplatePagesGenerator(unittest.TestCase):
generator = TemplatePagesGenerator(
context={'foo': 'bar'}, settings=settings,
path=self.temp_content, theme='', output_path=self.temp_output)
path=self.temp_content, theme='', themes=settings['THEMES'], output_path=self.temp_output)
# create a dummy template file
template_dir = os.path.join(self.temp_content, 'template')
@ -607,6 +610,7 @@ class TestStaticGenerator(unittest.TestCase):
StaticGenerator(context=context, settings=settings,
path=settings['PATH'], output_path=None,
themes=settings['THEMES'],
theme=settings['THEME']).generate_context()
staticnames = [os.path.basename(c.source_path)
@ -631,6 +635,7 @@ class TestStaticGenerator(unittest.TestCase):
for generator_class in (PagesGenerator, StaticGenerator):
generator_class(context=context, settings=settings,
path=settings['PATH'], output_path=None,
themes=settings['THEMES'],
theme=settings['THEME']).generate_context()
staticnames = [os.path.basename(c.source_path)
@ -648,6 +653,7 @@ class TestStaticGenerator(unittest.TestCase):
for generator_class in (PagesGenerator, StaticGenerator):
generator_class(context=context, settings=settings,
path=settings['PATH'], output_path=None,
themes=settings['THEMES'],
theme=settings['THEME']).generate_context()
staticnames = [os.path.basename(c.source_path)

View file

@ -73,6 +73,7 @@ class TestSettingsConfiguration(unittest.TestCase):
# These 4 settings are required to run configure_settings
'PATH': '.',
'THEME': DEFAULT_THEME,
'THEMES': {'!simple': 'simple'},
'SITEURL': 'http://blog.notmyidea.org/',
'LOCALE': '',
}
@ -90,6 +91,7 @@ class TestSettingsConfiguration(unittest.TestCase):
'LOCALE': '',
'PATH': os.curdir,
'THEME': DEFAULT_THEME,
'THEMES': {'!simple': 'simple'},
}
configure_settings(settings)
# SITEURL should not have a trailing slash

View file

@ -497,7 +497,7 @@ class TestDateFormatter(unittest.TestCase):
generator = TemplatePagesGenerator(
{'date': self.date}, settings,
self.temp_content, '', self.temp_output)
self.temp_content, '', '', self.temp_output)
generator.env.filters.update({'strftime': utils.DateFormatter()})
writer = Writer(self.temp_output, settings=settings)
@ -526,7 +526,7 @@ class TestDateFormatter(unittest.TestCase):
generator = TemplatePagesGenerator(
{'date': self.date}, settings,
self.temp_content, '', self.temp_output)
self.temp_content, '', '', self.temp_output)
generator.env.filters.update({'strftime': utils.DateFormatter()})
writer = Writer(self.temp_output, settings=settings)