Skip to content

Commit c5904c4

Browse files
authoredMay 18, 2017
Merge branch 'master' into fix-2771
2 parents 1f144c3 + 30e4461 commit c5904c4

23 files changed

+158
-44
lines changed
 

‎CHANGES.txt

+6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ Features
55
--------
66

77
* Better error handling when posts can't be parsed (Issue #2771)
8+
* Use ``.theme`` files to store theme metadata (Issue #2758)
89
* New ``add_header_permalinks`` filter, for Sphinx-style header links
910
(Issue #2636)
11+
* Added alternate links for gallery translations (Issue #993)
1012

1113
Bugfixes
1214
--------
1315

16+
* Ignore files ending wih "bak" (Issue #2740)
17+
* Use page.tmpl by default, which is inherited from story.tmpl (Issue
18+
#1891)
19+
1420
New in v7.8.5
1521
=============
1622

‎nikola/conf.py.in

+2-2
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ THEME_COLOR = '#5670d4'
123123
# Finally, note that destination can be translated, i.e. you can
124124
# specify a different translation folder per language. Example:
125125
# PAGES = (
126-
# ("pages/*.rst", {"en": "pages", "de": "seiten"}, "story.tmpl"),
127-
# ("pages/*.md", {"en": "pages", "de": "seiten"}, "story.tmpl"),
126+
# ("pages/*.rst", {"en": "pages", "de": "seiten"}, "page.tmpl"),
127+
# ("pages/*.md", {"en": "pages", "de": "seiten"}, "page.tmpl"),
128128
# )
129129

130130
POSTS = ${POSTS}
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.

‎nikola/data/themes/base/templates/gallery.tmpl

+7
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,12 @@
3737

3838
<%block name="extra_head">
3939
${parent.extra_head()}
40+
%if len(translations) > 1:
41+
%for langname in translations.keys():
42+
%if langname != lang:
43+
<link rel="alternate" hreflang="${langname}" href="${_link('gallery', gallery_path, langname)}">
44+
%endif
45+
%endfor
46+
%endif
4047
<link rel="alternate" type="application/rss+xml" title="RSS" href="rss.xml">
4148
</%block>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%inherit file="story.tmpl"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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
14+
15+
[Nikola]
16+
bootswatch = True

‎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,16 @@
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
14+
15+
[Nikola]
16+
bootswatch = True

‎nikola/data/themes/bootstrap3/engine

-1
This file was deleted.

‎nikola/data/themes/bootstrap3/parent

-1
This file was deleted.

‎nikola/data/themes/bootstrap3/templates/gallery.tmpl

+7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ ${parent.extra_head()}
4949
width: 100%;
5050
}
5151
</style>
52+
%if len(translations) > 1:
53+
%for langname in translations.keys():
54+
%if langname != lang:
55+
<link rel="alternate" hreflang="${langname}" href="${_link('gallery', gallery_path, langname)}">
56+
%endif
57+
%endfor
58+
%endif
5259
</%block>
5360

5461

‎nikola/nikola.py

+3
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,9 @@ def generic_page_renderer(self, lang, post, filters, context=None):
22702270
deps = post.deps(lang)
22712271
uptodate_deps = post.deps_uptodate(lang)
22722272
deps.extend(utils.get_asset_path(x, self.THEMES) for x in ('bundles', 'parent', 'engine'))
2273+
_theme_ini = utils.get_asset_path(self.config['THEME'] + '.theme', self.THEMES)
2274+
if _theme_ini:
2275+
deps.append(_theme_ini)
22732276

22742277
context = copy(context) if context else {}
22752278
context['post'] = post

‎nikola/plugins/command/auto/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,8 @@ def do_rebuild(self, event):
270270
if (fname.endswith('~') or
271271
fname.startswith('.') or
272272
'__pycache__' in event_path or
273-
event_path.endswith(('.pyc', '.pyo', '.pyd')) or
274-
os.path.isdir(event_path)): # Skip on folders, these are usually duplicates
273+
event_path.endswith(('.pyc', '.pyo', '.pyd', '_bak')) or
274+
event.is_directory): # Skip on folders, these are usually duplicates
275275
return
276276
self.logger.info('REBUILDING SITE (from {0})'.format(event_path))
277277
p = subprocess.Popen(self.cmd_arguments, stderr=subprocess.PIPE)

‎nikola/plugins/command/init.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@
7878
("posts/*.html", "posts", "post.tmpl"),
7979
)""",
8080
'PAGES': """(
81-
("pages/*.rst", "pages", "story.tmpl"),
82-
("pages/*.txt", "pages", "story.tmpl"),
83-
("pages/*.html", "pages", "story.tmpl"),
81+
("pages/*.rst", "pages", "page.tmpl"),
82+
("pages/*.txt", "pages", "page.tmpl"),
83+
("pages/*.html", "pages", "page.tmpl"),
8484
)""",
8585
'COMPILERS': """{
8686
"rest": ('.rst', '.txt'),

‎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/plugins/task/galleries.py

+1
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ def gen_tasks(self):
258258
folder += '/'
259259
folders.append((folder, ft))
260260

261+
context["gallery_path"] = gallery
261262
context["folders"] = natsort.natsorted(
262263
folders, alg=natsort.ns.F | natsort.ns.IC)
263264
context["crumbs"] = utils.get_crumbs(gallery, index_folder=self, lang=lang)

‎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):

‎tests/test_integration.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,10 @@ def patch_site(self):
392392
conf_path = os.path.join(self.target_dir, "conf.py")
393393
with io.open(conf_path, "r", encoding="utf-8") as inf:
394394
data = inf.read()
395-
data = data.replace('("pages/*.txt", "pages", "story.tmpl"),',
396-
'("pages/*.txt", "", "story.tmpl"),')
397-
data = data.replace('("pages/*.rst", "pages", "story.tmpl"),',
398-
'("pages/*.rst", "", "story.tmpl"),')
395+
data = data.replace('("pages/*.txt", "pages", "page.tmpl"),',
396+
'("pages/*.txt", "", "page.tmpl"),')
397+
data = data.replace('("pages/*.rst", "pages", "page.tmpl"),',
398+
'("pages/*.rst", "", "page.tmpl"),')
399399
data = data.replace('# INDEX_PATH = ""',
400400
'INDEX_PATH = "blog"')
401401
with io.open(conf_path, "w+", encoding="utf8") as outf:
@@ -553,7 +553,7 @@ def patch_site(self):
553553
"""Enable post sections."""
554554
conf_path = os.path.join(self.target_dir, "conf.py")
555555
with io.open(conf_path, "a", encoding="utf8") as outf:
556-
outf.write("""\n\nPOSTS_SECTIONS = True\nPOSTS_SECTIONS_ARE_INDEXES = True\nPRETTY_URLS = True\nPOSTS = (('posts/*.txt', '', 'post.tmpl'),)\nPAGES = (('pages/*.txt', '', 'story.tmpl'),)\n\n""")
556+
outf.write("""\n\nPOSTS_SECTIONS = True\nPOSTS_SECTIONS_ARE_INDEXES = True\nPRETTY_URLS = True\nPOSTS = (('posts/*.txt', '', 'post.tmpl'),)\nPAGES = (('pages/*.txt', '', 'page.tmpl'),)\n\n""")
557557

558558
@classmethod
559559
def fill_site(self):
@@ -602,7 +602,7 @@ def patch_site(self):
602602
"""Enable PAGE_INDEX."""
603603
conf_path = os.path.join(self.target_dir, "conf.py")
604604
with io.open(conf_path, "a", encoding="utf8") as outf:
605-
outf.write("""\n\nPAGE_INDEX = True\nPRETTY_URLS = False\nPAGES = PAGES + (('pages/*.php', 'pages', 'story.tmpl'),)\n\n""")
605+
outf.write("""\n\nPAGE_INDEX = True\nPRETTY_URLS = False\nPAGES = PAGES + (('pages/*.php', 'pages', 'page.tmpl'),)\n\n""")
606606

607607
@classmethod
608608
def fill_site(self):
@@ -707,7 +707,7 @@ def patch_site(self):
707707
"""Enable PAGE_INDEX."""
708708
conf_path = os.path.join(self.target_dir, "conf.py")
709709
with io.open(conf_path, "a", encoding="utf8") as outf:
710-
outf.write("""\n\nPAGE_INDEX = True\nPRETTY_URLS = True\nPAGES = PAGES + (('pages/*.php', 'pages', 'story.tmpl'),)\n\n""")
710+
outf.write("""\n\nPAGE_INDEX = True\nPRETTY_URLS = True\nPAGES = PAGES + (('pages/*.php', 'pages', 'page.tmpl'),)\n\n""")
711711

712712
def _make_output_path(self, dir, name):
713713
"""Make a file path to the output."""

0 commit comments

Comments
 (0)
Please sign in to comment.