Skip to content

Commit 9e8dd6d

Browse files
Kwpolskaralsina
authored andcommittedMay 17, 2017
Fix #2758 -- Add support for theme meta files
Signed-off-by: Chris Warrick <kwpolska@gmail.com>
1 parent adeb7d3 commit 9e8dd6d

File tree

15 files changed

+117
-30
lines changed

15 files changed

+117
-30
lines changed
 

‎CHANGES.txt

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ New in master
44
Features
55
--------
66

7+
* Use ``.theme`` files to store theme metadata (Issue #2758)
78
* New ``add_header_permalinks`` filter, for Sphinx-style header links
89
(Issue #2636)
910
* Added alternate links for gallery translations (Issue #993)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[Theme]
2+
engine = jinja
3+
parent = base
4+
author = The Nikola Contributors
5+
author_url = https://getnikola.com/
6+
license = MIT
7+
8+
[Family]
9+
family = base
10+
mako_version = base

‎nikola/data/themes/base-jinja/engine

-1
This file was deleted.

‎nikola/data/themes/base-jinja/parent

-1
This file was deleted.

‎nikola/data/themes/base/base.theme

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[Theme]
2+
engine = mako
3+
author = The Nikola Contributors
4+
author_url = https://getnikola.com/
5+
license = MIT
6+
7+
[Family]
8+
family = base
9+
jinja_version = base-jinja

‎nikola/data/themes/base/engine

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[Theme]
2+
engine = jinja
3+
parent = base-jinja
4+
author = The Nikola Contributors
5+
author_url = https://getnikola.com/
6+
based_on = Bootstrap 3 <http://getbootstrap.com/>
7+
license = MIT
8+
tags = bootstrap
9+
10+
[Family]
11+
family = bootstrap3
12+
mako_version = bootstrap3
13+
variants = bootstrap3-gradients, bootstrap3-gradients-jinja

‎nikola/data/themes/bootstrap3-jinja/engine

-1
This file was deleted.

‎nikola/data/themes/bootstrap3-jinja/parent

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[Theme]
2+
engine = mako
3+
parent = base
4+
author = The Nikola Contributors
5+
author_url = https://getnikola.com/
6+
based_on = Bootstrap 3 <http://getbootstrap.com/>
7+
license = MIT
8+
tags = bootstrap
9+
10+
[Family]
11+
family = bootstrap3
12+
jinja_version = bootstrap3-jinja
13+
variants = bootstrap3-gradients, bootstrap3-gradients-jinja

‎nikola/data/themes/bootstrap3/engine

-1
This file was deleted.

‎nikola/data/themes/bootstrap3/parent

-1
This file was deleted.

‎nikola/nikola.py

+3
Original file line numberDiff line numberDiff line change
@@ -2267,6 +2267,9 @@ def generic_page_renderer(self, lang, post, filters, context=None):
22672267
deps = post.deps(lang)
22682268
uptodate_deps = post.deps_uptodate(lang)
22692269
deps.extend(utils.get_asset_path(x, self.THEMES) for x in ('bundles', 'parent', 'engine'))
2270+
_theme_ini = utils.get_asset_path(self.config['THEME'] + '.theme', self.THEMES)
2271+
if _theme_ini:
2272+
deps.append(_theme_ini)
22702273

22712274
context = copy(context) if context else {}
22722275
context['post'] = post

‎nikola/plugins/command/theme.py

+30-11
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import shutil
3333
import time
3434
import requests
35+
import configparser
3536

3637
import pygments
3738
from pygments.lexers import PythonLexer
@@ -131,6 +132,13 @@ class CommandTheme(Command):
131132
'default': 'base',
132133
'help': 'Parent to use for new theme (default: base)',
133134
},
135+
{
136+
'name': 'new_legacy_meta',
137+
'long': 'legacy-meta',
138+
'type': bool,
139+
'default': False,
140+
'help': 'Create legacy meta files for new theme',
141+
},
134142
]
135143

136144
def _execute(self, options, args):
@@ -147,6 +155,7 @@ def _execute(self, options, args):
147155
new = options.get('new')
148156
new_engine = options.get('new_engine')
149157
new_parent = options.get('new_parent')
158+
new_legacy_meta = options.get('new_legacy_meta')
150159
command_count = [bool(x) for x in (
151160
install,
152161
uninstall,
@@ -172,7 +181,7 @@ def _execute(self, options, args):
172181
elif copy_template:
173182
return self.copy_template(copy_template)
174183
elif new:
175-
return self.new_theme(new, new_engine, new_parent)
184+
return self.new_theme(new, new_engine, new_parent, new_legacy_meta)
176185

177186
def do_install_deps(self, url, name):
178187
"""Install themes and their dependencies."""
@@ -316,7 +325,7 @@ def copy_template(self, template):
316325
LOGGER.error("This file already exists in your templates directory ({0}).".format(base))
317326
return 3
318327

319-
def new_theme(self, name, engine, parent):
328+
def new_theme(self, name, engine, parent, create_legacy_meta=False):
320329
"""Create a new theme."""
321330
base = 'themes'
322331
themedir = os.path.join(base, name)
@@ -326,9 +335,7 @@ def new_theme(self, name, engine, parent):
326335
LOGGER.info("Created directory {0}".format(base))
327336

328337
# Check if engine and parent match
329-
engine_file = utils.get_asset_path('engine', utils.get_theme_chain(parent, self.site.themes_dirs))
330-
with io.open(engine_file, 'r', encoding='utf-8') as fh:
331-
parent_engine = fh.read().strip()
338+
parent_engine = utils.get_template_engine(utils.get_theme_chain(parent, self.site.themes_dirs))
332339

333340
if parent_engine != engine:
334341
LOGGER.error("Cannot use engine {0} because parent theme '{1}' uses {2}".format(engine, parent, parent_engine))
@@ -342,12 +349,24 @@ def new_theme(self, name, engine, parent):
342349
LOGGER.error("Theme already exists")
343350
return 2
344351

345-
with io.open(os.path.join(themedir, 'parent'), 'w', encoding='utf-8') as fh:
346-
fh.write(parent + '\n')
347-
LOGGER.info("Created file {0}".format(os.path.join(themedir, 'parent')))
348-
with io.open(os.path.join(themedir, 'engine'), 'w', encoding='utf-8') as fh:
349-
fh.write(engine + '\n')
350-
LOGGER.info("Created file {0}".format(os.path.join(themedir, 'engine')))
352+
cp = configparser.ConfigParser()
353+
cp['Theme'] = {
354+
'engine': engine,
355+
'parent': parent
356+
}
357+
358+
theme_meta_path = os.path.join(themedir, name + '.theme')
359+
with io.open(theme_meta_path, 'w', encoding='utf-8') as fh:
360+
cp.write(fh)
361+
LOGGER.info("Created file {0}".format(theme_meta_path))
362+
363+
if create_legacy_meta:
364+
with io.open(os.path.join(themedir, 'parent'), 'w', encoding='utf-8') as fh:
365+
fh.write(parent + '\n')
366+
LOGGER.info("Created file {0}".format(os.path.join(themedir, 'parent')))
367+
with io.open(os.path.join(themedir, 'engine'), 'w', encoding='utf-8') as fh:
368+
fh.write(engine + '\n')
369+
LOGGER.info("Created file {0}".format(os.path.join(themedir, 'engine')))
351370

352371
LOGGER.info("Theme {0} created successfully.".format(themedir))
353372
LOGGER.notice('Remember to set THEME="{0}" in conf.py to use this theme.'.format(name))

‎nikola/utils.py

+38-12
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
from __future__ import print_function, unicode_literals, absolute_import
3030
import calendar
31+
import configparser
3132
import datetime
3233
import dateutil.tz
3334
import hashlib
@@ -607,27 +608,52 @@ def get_theme_path(theme):
607608
return theme
608609

609610

611+
def parse_theme_meta(theme_dir):
612+
"""Parse a .theme meta file."""
613+
cp = configparser.ConfigParser()
614+
# The `or` case is in case theme_dir ends with a trailing slash
615+
theme_name = os.path.basename(theme_dir) or os.path.basename(os.path.dirname(theme_dir))
616+
theme_meta_path = os.path.join(theme_dir, theme_name + '.theme')
617+
cp.read(theme_meta_path)
618+
return cp if cp.has_section('Theme') else None
619+
620+
610621
def get_template_engine(themes):
611622
"""Get template engine used by a given theme."""
612623
for theme_name in themes:
613-
engine_path = os.path.join(theme_name, 'engine')
614-
if os.path.isfile(engine_path):
615-
with open(engine_path) as fd:
616-
return fd.readlines()[0].strip()
617-
# default
618-
return 'mako'
624+
meta = parse_theme_meta(theme_name)
625+
if meta:
626+
e = meta.get('Theme', 'engine', fallback=None)
627+
if e:
628+
return e
629+
else:
630+
# Theme still uses old-style parent/engine files
631+
engine_path = os.path.join(theme_name, 'engine')
632+
if os.path.isfile(engine_path):
633+
with open(engine_path) as fd:
634+
return fd.readlines()[0].strip()
635+
# default
636+
return 'mako'
619637

620638

621639
def get_parent_theme_name(theme_name, themes_dirs=None):
622640
"""Get name of parent theme."""
623-
parent_path = os.path.join(theme_name, 'parent')
624-
if os.path.isfile(parent_path):
625-
with open(parent_path) as fd:
626-
parent = fd.readlines()[0].strip()
627-
if themes_dirs:
641+
meta = parse_theme_meta(theme_name)
642+
if meta:
643+
parent = meta.get('Theme', 'parent', fallback=None)
644+
if themes_dirs and parent:
628645
return get_theme_path_real(parent, themes_dirs)
629646
return parent
630-
return None
647+
else:
648+
# Theme still uses old-style parent/engine files
649+
parent_path = os.path.join(theme_name, 'parent')
650+
if os.path.isfile(parent_path):
651+
with open(parent_path) as fd:
652+
parent = fd.readlines()[0].strip()
653+
if themes_dirs:
654+
return get_theme_path_real(parent, themes_dirs)
655+
return parent
656+
return None
631657

632658

633659
def get_theme_chain(theme, themes_dirs):

0 commit comments

Comments
 (0)
Please sign in to comment.