Skip to content

Commit

Permalink
Merge pull request #2532 from getnikola/new-compile-function
Browse files Browse the repository at this point in the history
Fix #2531 — pass post and lang to compilers
  • Loading branch information
Kwpolska committed Oct 15, 2016
2 parents 3fae233 + bd7390b commit f5d42cf
Show file tree
Hide file tree
Showing 16 changed files with 69 additions and 68 deletions.
4 changes: 3 additions & 1 deletion CHANGES.txt
@@ -1,13 +1,15 @@
New in master
============
=============

Bugfixes
--------

Features
--------

* The destination folder in ``POSTS`` and ``PAGES`` can now be
translated (Issue #2116)
* Pass ``post`` object and ``lang`` to post compilers (Issue #2531)

New in v7.8.1
=============
Expand Down
6 changes: 4 additions & 2 deletions docs/extending.txt
Expand Up @@ -367,11 +367,13 @@ PageCompiler Plugins
--------------------

These plugins implement markup languages, they take sources for posts or pages and
create HTML or other output files. A good example is `the misaka plugin. <https://github.com/getnikola/plugins/tree/master/v7/misaka>`__
create HTML or other output files. A good example is `the misaka plugin
<https://github.com/getnikola/plugins/tree/master/v7/misaka>`__ or the built-in
compiler plugins.

They must provide:

``compile_html``
``compile``
Function that builds a file.

``create_post``
Expand Down
8 changes: 4 additions & 4 deletions nikola/nikola.py
Expand Up @@ -1260,7 +1260,7 @@ def get_compiler(self, source_name):
"""
ext = os.path.splitext(source_name)[1]
try:
compile_html = self.inverse_compilers[ext]
compiler = self.inverse_compilers[ext]
except KeyError:
# Find the correct compiler for this files extension
lang_exts_tab = list(self.config['COMPILERS'].items())
Expand All @@ -1280,12 +1280,12 @@ def get_compiler(self, source_name):

lang = langs[0]
try:
compile_html = self.compilers[lang]
compiler = self.compilers[lang]
except KeyError:
exit("Cannot find '{0}' compiler; it might require an extra plugin -- do you have it installed?".format(lang))
self.inverse_compilers[ext] = compile_html
self.inverse_compilers[ext] = compiler

return compile_html
return compiler

def render_template(self, template_name, output_name, context, url_type=None):
"""Render a template with the global context.
Expand Down
12 changes: 10 additions & 2 deletions nikola/plugin_categories.py
Expand Up @@ -275,8 +275,16 @@ def register_extra_dependencies(self, post):
"""Add dependency to post object to check .dep file."""
post.add_dependency(lambda: self._read_extra_deps(post), 'fragment')

def compile_html(self, source, dest, is_two_file=False):
"""Compile the source, save it on dest."""
def compile(self, source, dest, is_two_file=True, post=None, lang=None):
"""Compile the source file into HTML and save as dest."""
# For backwards compatibility, call `compile_html`
# If you are implementing a compiler, please implement `compile` and
# ignore `compile_html`
self.compile_html(source, dest, is_two_file)

# TODO remove in v8
def compile_html(self, source, dest, is_two_file=True):
"""Compile the source, save it on dest (DEPRECATED)."""
raise NotImplementedError()

def create_post(self, path, content=None, onefile=False, is_page=False, **kw):
Expand Down
2 changes: 1 addition & 1 deletion nikola/plugins/command/rst2html/__init__.py
Expand Up @@ -52,7 +52,7 @@ def _execute(self, options, args):
source = args[0]
with io.open(source, "r", encoding="utf8") as in_file:
data = in_file.read()
output, error_level, deps = compiler.compile_html_string(data, source, True)
output, error_level, deps = compiler.compile_string(data, source, True)

rstcss_path = resource_filename('nikola', 'data/themes/base/assets/css/rst.css')
with io.open(rstcss_path, "r", encoding="utf8") as fh:
Expand Down
12 changes: 4 additions & 8 deletions nikola/plugins/compile/html.py
Expand Up @@ -24,7 +24,7 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""Implementation of compile_html for HTML source files."""
"""Page compiler plugin for HTML source files."""

from __future__ import unicode_literals

Expand All @@ -41,13 +41,9 @@ class CompileHtml(PageCompiler):
name = "html"
friendly_name = "HTML"

def compile_html(self, source, dest, is_two_file=True):
"""Compile source file into HTML and save as dest."""
def compile(self, source, dest, is_two_file=True, post=None, lang=None):
"""Compile the source file into HTML and save as dest."""
makedirs(os.path.dirname(dest))
try:
post = self.site.post_per_input_file[source]
except KeyError:
post = None
with io.open(dest, "w+", encoding="utf8") as out_file:
with io.open(source, "r", encoding="utf8") as in_file:
data = in_file.read()
Expand All @@ -58,7 +54,7 @@ def compile_html(self, source, dest, is_two_file=True):
if post is None:
if shortcode_deps:
self.logger.error(
"Cannot save dependencies for post {0} due to unregistered source file name",
"Cannot save dependencies for post {0} (post unknown)",
source)
else:
post._depfile[dest] += shortcode_deps
Expand Down
21 changes: 11 additions & 10 deletions nikola/plugins/compile/ipynb.py
Expand Up @@ -24,7 +24,7 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""Implementation of compile_html based on nbconvert."""
"""Page compiler plugin for nbconvert."""

from __future__ import unicode_literals, print_function
import io
Expand Down Expand Up @@ -77,7 +77,7 @@ def set_site(self, site):
self.logger = get_logger('compile_ipynb', STDERR_HANDLER)
super(CompileIPynb, self).set_site(site)

def compile_html_string(self, source, is_two_file=True):
def compile_string(self, source, is_two_file=True):
"""Export notebooks as HTML strings."""
if flag is None:
req_missing(['ipython[notebook]>=2.0.0'], 'build this site (compile ipynb)')
Expand All @@ -88,21 +88,22 @@ def compile_html_string(self, source, is_two_file=True):
(body, resources) = exportHtml.from_notebook_node(nb_json)
return body

def compile_html(self, source, dest, is_two_file=True):
"""Compile source file into HTML and save as dest."""
# TODO remove in v8
def compile_html_string(self, source, is_two_file=True):
"""Export notebooks as HTML strings."""
return self.compile_string(source, is_two_file)

def compile(self, source, dest, is_two_file=False, post=None, lang=None):
"""Compile the source file into HTML and save as dest."""
makedirs(os.path.dirname(dest))
try:
post = self.site.post_per_input_file[source]
except KeyError:
post = None
with io.open(dest, "w+", encoding="utf8") as out_file:
output = self.compile_html_string(source, is_two_file)
output = self.compile_string(source, is_two_file)
output, shortcode_deps = self.site.apply_shortcodes(output, filename=source, with_dependencies=True, extra_context=dict(post=post))
out_file.write(output)
if post is None:
if shortcode_deps:
self.logger.error(
"Cannot save dependencies for post {0} due to unregistered source file name",
"Cannot save dependencies for post {0} (post unknown)",
source)
else:
post._depfile[dest] += shortcode_deps
Expand Down
12 changes: 4 additions & 8 deletions nikola/plugins/compile/markdown/__init__.py
Expand Up @@ -24,7 +24,7 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""Implementation of compile_html based on markdown."""
"""Page compiler plugin for Markdown."""

from __future__ import unicode_literals

Expand Down Expand Up @@ -63,16 +63,12 @@ def set_site(self, site):

self.config_dependencies.append(str(sorted(site.config.get("MARKDOWN_EXTENSIONS"))))

def compile_html(self, source, dest, is_two_file=True):
"""Compile source file into HTML and save as dest."""
def compile(self, source, dest, is_two_file=True, post=None, lang=None):
"""Compile the source file into HTML and save as dest."""
if markdown is None:
req_missing(['markdown'], 'build this site (compile Markdown)')
makedirs(os.path.dirname(dest))
self.extensions += self.site.config.get("MARKDOWN_EXTENSIONS")
try:
post = self.site.post_per_input_file[source]
except KeyError:
post = None
with io.open(dest, "w+", encoding="utf8") as out_file:
with io.open(source, "r", encoding="utf8") as in_file:
data = in_file.read()
Expand All @@ -84,7 +80,7 @@ def compile_html(self, source, dest, is_two_file=True):
if post is None:
if shortcode_deps:
self.logger.error(
"Cannot save dependencies for post {0} due to unregistered source file name",
"Cannot save dependencies for post {0} (post unknown)",
source)
else:
post._depfile[dest] += shortcode_deps
Expand Down
12 changes: 4 additions & 8 deletions nikola/plugins/compile/pandoc.py
Expand Up @@ -24,7 +24,7 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""Implementation of compile_html based on pandoc.
"""Page compiler plugin for pandoc.
You will need, of course, to install pandoc
"""
Expand All @@ -50,14 +50,10 @@ def set_site(self, site):
self.config_dependencies = [str(site.config['PANDOC_OPTIONS'])]
super(CompilePandoc, self).set_site(site)

def compile_html(self, source, dest, is_two_file=True):
"""Compile source file into HTML and save as dest."""
def compile(self, source, dest, is_two_file=True, post=None, lang=None):
"""Compile the source file into HTML and save as dest."""
makedirs(os.path.dirname(dest))
try:
try:
post = self.site.post_per_input_file[source]
except KeyError:
post = None
subprocess.check_call(['pandoc', '-o', dest, source] + self.site.config['PANDOC_OPTIONS'])
with open(dest, 'r', encoding='utf-8') as inf:
output, shortcode_deps = self.site.apply_shortcodes(inf.read(), with_dependencies=True)
Expand All @@ -66,7 +62,7 @@ def compile_html(self, source, dest, is_two_file=True):
if post is None:
if shortcode_deps:
self.logger.error(
"Cannot save dependencies for post {0} due to unregistered source file name",
"Cannot save dependencies for post {0} (post unknown)",
source)
else:
post._depfile[dest] += shortcode_deps
Expand Down
6 changes: 3 additions & 3 deletions nikola/plugins/compile/php.py
Expand Up @@ -24,7 +24,7 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""Implementation of compile_html for HTML+php."""
"""Page compiler plugin for PHP."""

from __future__ import unicode_literals

Expand All @@ -42,8 +42,8 @@ class CompilePhp(PageCompiler):
name = "php"
friendly_name = "PHP"

def compile_html(self, source, dest, is_two_file=True):
"""Compile source file into HTML and save as dest."""
def compile(self, source, dest, is_two_file=True, post=None, lang=None):
"""Compile the source file into HTML and save as dest."""
makedirs(os.path.dirname(dest))
with io.open(dest, "w+", encoding="utf8") as out_file:
with open(source, "rb") as in_file:
Expand Down
21 changes: 11 additions & 10 deletions nikola/plugins/compile/rest/__init__.py
Expand Up @@ -59,7 +59,7 @@ class CompileRest(PageCompiler):
demote_headers = True
logger = None

def compile_html_string(self, data, source_path=None, is_two_file=True):
def compile_string(self, data, source_path=None, is_two_file=True):
"""Compile reST into HTML strings."""
# If errors occur, this will be added to the line number reported by
# docutils so the line number matches the actual line number (off by
Expand Down Expand Up @@ -90,24 +90,25 @@ def compile_html_string(self, data, source_path=None, is_two_file=True):
output = output.decode('utf-8')
return output, error_level, deps

def compile_html(self, source, dest, is_two_file=True):
"""Compile source file into HTML and save as dest."""
# TODO remove in v8
def compile_html_string(self, data, source_path=None, is_two_file=True):
"""Compile reST into HTML strings."""
return self.compile_string(data, source_path, is_two_file)

def compile(self, source, dest, is_two_file=True, post=None, lang=None):
"""Compile the source file into HTML and save as dest."""
makedirs(os.path.dirname(dest))
error_level = 100
with io.open(dest, "w+", encoding="utf8") as out_file:
try:
post = self.site.post_per_input_file[source]
except KeyError:
post = None
with io.open(source, "r", encoding="utf8") as in_file:
data = in_file.read()
output, error_level, deps = self.compile_html_string(data, source, is_two_file)
output, error_level, deps = self.compile_string(data, source, is_two_file)
output, shortcode_deps = self.site.apply_shortcodes(output, filename=source, with_dependencies=True, extra_context=dict(post=post))
out_file.write(output)
if post is None:
if deps.list:
self.logger.error(
"Cannot save dependencies for post {0} due to unregistered source file name",
"Cannot save dependencies for post {0} (post unknown)",
source)
else:
post._depfile[dest] += deps.list
Expand Down Expand Up @@ -279,7 +280,7 @@ def rst2html(source, source_path=None, source_class=docutils.io.StringInput,
# specify here.
# logger a logger from Nikola
# source source filename (docutils gets a string)
# add_ln amount of metadata lines (see comment in compile_html above)
# add_ln amount of metadata lines (see comment in CompileRest.compile above)
reader.l_settings = {'logger': logger, 'source': source_path,
'add_ln': l_add_ln}

Expand Down
2 changes: 1 addition & 1 deletion nikola/plugins/task/listings.py
Expand Up @@ -116,7 +116,7 @@ def render_listing(in_name, out_name, input_folder, output_folder, folders=[], f
if in_name and in_name.endswith('.ipynb'):
# Special handling: render ipynbs in listings (Issue #1900)
ipynb_compiler = self.site.plugin_manager.getPluginByName("ipynb", "PageCompiler").plugin_object
ipynb_raw = ipynb_compiler.compile_html_string(in_name, True)
ipynb_raw = ipynb_compiler.compile_string(in_name, True)
ipynb_html = lxml.html.fromstring(ipynb_raw)
# The raw HTML contains garbage (scripts and styles), we can’t leave it in
code = lxml.html.tostring(ipynb_html.xpath('//*[@id="notebook"]')[0], encoding='unicode')
Expand Down
6 changes: 4 additions & 2 deletions nikola/post.py
Expand Up @@ -101,7 +101,7 @@ def __init__(
"""
self.config = config
self.compiler = compiler
self.compile_html = self.compiler.compile_html
self.compile_html = self.compiler.compile
self.demote_headers = self.compiler.demote_headers and self.config['DEMOTE_HEADERS']
tzinfo = self.config['__tzinfo__']
if self.config['FUTURE_IS_NOW']:
Expand Down Expand Up @@ -536,7 +536,9 @@ def wrap_encrypt(path, password):
self.compile_html(
self.translated_source_path(lang),
dest,
self.is_two_file)
self.is_two_file,
self,
lang)
Post.write_depfile(dest, self._depfile[dest])

signal('compiled').send({
Expand Down
10 changes: 3 additions & 7 deletions tests/test_compile_markdown.py
@@ -1,10 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import os
import sys


import io
import shutil
import tempfile
Expand All @@ -28,7 +24,7 @@ def compile(self, input_string):
with io.open(self.input_path, "w+", encoding="utf8") as input_file:
input_file.write(input_string)

self.compiler.compile_html(self.input_path, self.output_path)
self.compiler.compile(self.input_path, self.output_path)

output_str = None
with io.open(self.output_path, "r", encoding="utf8") as output_path:
Expand All @@ -39,12 +35,12 @@ def compile(self, input_string):
def tearDown(self):
shutil.rmtree(self.tmp_dir)

def test_compile_html_empty(self):
def test_compile_empty(self):
input_str = ''
actual_output = self.compile(input_str)
self.assertEquals(actual_output, '')

def test_compile_html_code_hilite(self):
def test_compile_code_hilite(self):
input_str = '''\
#!python
from this
Expand Down
1 change: 1 addition & 0 deletions tests/test_rss_feeds.py
Expand Up @@ -32,6 +32,7 @@
class FakeCompiler(object):
demote_headers = False
compile_html = None
compile = None
extension = lambda self: '.html'
name = "fake"

Expand Down
2 changes: 1 addition & 1 deletion tests/test_rst_compiler.py
Expand Up @@ -76,7 +76,7 @@ def setHtmlFromRst(self, rst):
p = FakePost('', '')
p._depfile[outf] = []
self.compiler.site.post_per_input_file[inf] = p
self.html = self.compiler.compile_html(inf, outf)
self.html = self.compiler.compile(inf, outf)
with io.open(outf, 'r', encoding='utf8') as f:
self.html = f.read()
os.unlink(inf)
Expand Down

0 comments on commit f5d42cf

Please sign in to comment.