diff options
Diffstat (limited to 'nikola/plugins')
73 files changed, 582 insertions, 219 deletions
diff --git a/nikola/plugins/basic_import.py b/nikola/plugins/basic_import.py index e368fca..0d94d16 100644 --- a/nikola/plugins/basic_import.py +++ b/nikola/plugins/basic_import.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/__init__.py b/nikola/plugins/command/__init__.py index 9be4d63..6ad8bac 100644 --- a/nikola/plugins/command/__init__.py +++ b/nikola/plugins/command/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/auto.py b/nikola/plugins/command/auto.py index cb726d9..01116d1 100644 --- a/nikola/plugins/command/auto.py +++ b/nikola/plugins/command/auto.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -26,30 +26,13 @@ from __future__ import print_function, unicode_literals -import codecs -import json import os import subprocess +import webbrowser from nikola.plugin_categories import Command from nikola.utils import req_missing -GUARDFILE = """#!/usr/bin/env python -# -*- coding: utf-8 -*- -from livereload.task import Task -import json -import subprocess - -def f(): - import subprocess - subprocess.call(("nikola", "build")) - -fdata = json.loads('''{0}''') - -for watch in fdata: - Task.add(watch, f) -""" - class Auto(Command): """Start debugging console.""" @@ -76,9 +59,9 @@ class Auto(Command): def _execute(self, options, args): """Start the watcher.""" try: - from livereload.server import start + from livereload import Server except ImportError: - req_missing(['livereload'], 'use the "auto" command') + req_missing(['livereload>=2.0.0'], 'use the "auto" command') return # Run an initial build so we are uptodate @@ -86,18 +69,18 @@ class Auto(Command): port = options and options.get('port') - # Create a Guardfile - with codecs.open("Guardfile", "wb+", "utf8") as guardfile: - l = ["conf.py", "themes", "templates", self.site.config['GALLERY_PATH']] - for item in self.site.config['post_pages']: - l.append(os.path.dirname(item[0])) - for item in self.site.config['FILES_FOLDERS']: - l.append(os.path.dirname(item)) - data = GUARDFILE.format(json.dumps(l)) - guardfile.write(data) + server = Server() + server.watch('conf.py') + server.watch('themes/') + server.watch('templates/') + server.watch(self.site.config['GALLERY_PATH']) + for item in self.site.config['post_pages']: + server.watch(os.path.dirname(item[0])) + for item in self.site.config['FILES_FOLDERS']: + server.watch(os.path.dirname(item)) out_folder = self.site.config['OUTPUT_FOLDER'] + if options and options.get('browser'): + webbrowser.open('http://localhost:{0}'.format(port)) - os.chmod("Guardfile", 0o755) - - start(port, out_folder, options and options.get('browser')) + server.serve(port, out_folder) diff --git a/nikola/plugins/command/bootswatch_theme.py b/nikola/plugins/command/bootswatch_theme.py index eb27f94..94f37f2 100644 --- a/nikola/plugins/command/bootswatch_theme.py +++ b/nikola/plugins/command/bootswatch_theme.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/check.py b/nikola/plugins/command/check.py index 5c7e49a..a7e8c13 100644 --- a/nikola/plugins/command/check.py +++ b/nikola/plugins/command/check.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -40,6 +40,29 @@ from nikola.plugin_categories import Command from nikola.utils import get_logger +def real_scan_files(site): + task_fnames = set([]) + real_fnames = set([]) + output_folder = site.config['OUTPUT_FOLDER'] + # First check that all targets are generated in the right places + for task in os.popen('nikola list --all', 'r').readlines(): + task = task.strip() + if output_folder in task and ':' in task: + fname = task.split(':', 1)[-1] + task_fnames.add(fname) + # And now check that there are no non-target files + for root, dirs, files in os.walk(output_folder): + for src_name in files: + fname = os.path.join(root, src_name) + real_fnames.add(fname) + + only_on_output = list(real_fnames - task_fnames) + + only_on_input = list(task_fnames - real_fnames) + + return (only_on_output, only_on_input) + + class CommandCheck(Command): """Check the generated site.""" @@ -63,7 +86,7 @@ class CommandCheck(Command): 'long': 'check-files', 'type': bool, 'default': False, - 'help': 'Check for unknown files', + 'help': 'Check for unknown (orphaned and not generated) files', }, { 'name': 'clean', @@ -154,7 +177,7 @@ class CommandCheck(Command): failure = False self.logger.notice("Checking Files:") self.logger.notice("===============\n") - only_on_output, only_on_input = self.real_scan_files() + only_on_output, only_on_input = real_scan_files(self.site) # Ignore folders only_on_output = [p for p in only_on_output if not os.path.isdir(p)] @@ -162,7 +185,7 @@ class CommandCheck(Command): if only_on_output: only_on_output.sort() - self.logger.warn("Files from unknown origins:") + self.logger.warn("Files from unknown origins (orphans):") for f in only_on_output: self.logger.warn(f) failure = True @@ -180,25 +203,3 @@ class CommandCheck(Command): for f in only_on_output: os.unlink(f) return True - - def real_scan_files(self): - task_fnames = set([]) - real_fnames = set([]) - output_folder = self.site.config['OUTPUT_FOLDER'] - # First check that all targets are generated in the right places - for task in os.popen('nikola list --all', 'r').readlines(): - task = task.strip() - if output_folder in task and ':' in task: - fname = task.split(':', 1)[-1] - task_fnames.add(fname) - # And now check that there are no non-target files - for root, dirs, files in os.walk(output_folder): - for src_name in files: - fname = os.path.join(root, src_name) - real_fnames.add(fname) - - only_on_output = list(real_fnames - task_fnames) - - only_on_input = list(task_fnames - real_fnames) - - return (only_on_output, only_on_input) diff --git a/nikola/plugins/command/console.plugin b/nikola/plugins/command/console.plugin index a2be9ca..2eeedae 100644 --- a/nikola/plugins/command/console.plugin +++ b/nikola/plugins/command/console.plugin @@ -3,7 +3,7 @@ Name = console Module = console [Documentation] -Author = Roberto Alsina +Author = Chris Warrick, Roberto Alsina Version = 0.1 Website = http://getnikola.com Description = Start a debugging python console diff --git a/nikola/plugins/command/console.py b/nikola/plugins/command/console.py index fe17dfc..e66b650 100644 --- a/nikola/plugins/command/console.py +++ b/nikola/plugins/command/console.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Chris Warrick, Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -39,8 +39,21 @@ class Console(Command): """Start debugging console.""" name = "console" shells = ['ipython', 'bpython', 'plain'] - doc_purpose = "Start an interactive Python (IPython->bpython->plain) console with access to your site and configuration" + doc_purpose = "start an interactive Python console with access to your site" + doc_description = """\ +Order of resolution: IPython → bpython [deprecated] → plain Python interpreter +The site engine is accessible as `SITE`, and the config as `conf`.""" header = "Nikola v" + __version__ + " -- {0} Console (conf = configuration, SITE = site engine)" + cmd_options = [ + { + 'name': 'plain', + 'short': 'p', + 'long': 'plain', + 'type': bool, + 'default': False, + 'help': 'Force the plain Python console', + } + ] def ipython(self): """IPython shell.""" @@ -102,9 +115,12 @@ class Console(Command): def _execute(self, options, args): """Start the console.""" - for shell in self.shells: - try: - return getattr(self, shell)() - except ImportError: - pass - raise ImportError + if options['plain']: + self.plain() + else: + for shell in self.shells: + try: + return getattr(self, shell)() + except ImportError: + pass + raise ImportError diff --git a/nikola/plugins/command/deploy.py b/nikola/plugins/command/deploy.py index efb909d..eb5787e 100644 --- a/nikola/plugins/command/deploy.py +++ b/nikola/plugins/command/deploy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -85,18 +85,17 @@ class Deploy(Command): sys.exit(e.returncode) self.logger.notice("Successful deployment") - if self.site.config['TIMEZONE'] is not None: - tzinfo = pytz.timezone(self.site.config['TIMEZONE']) - else: - tzinfo = pytz.UTC + tzinfo = pytz.timezone(self.site.config['TIMEZONE']) try: with open(timestamp_path, 'rb') as inf: last_deploy = literal_eval(inf.read().strip()) - # this might ignore DST - last_deploy = last_deploy.replace(tzinfo=tzinfo) + if tzinfo: + last_deploy = last_deploy.replace(tzinfo=tzinfo) clean = False except Exception: - last_deploy = datetime(1970, 1, 1).replace(tzinfo=tzinfo) + last_deploy = datetime(1970, 1, 1) + if tzinfo: + last_deploy = last_deploy.replace(tzinfo=tzinfo) clean = True new_deploy = datetime.now() diff --git a/nikola/plugins/command/import_blogger.py b/nikola/plugins/command/import_blogger.py index 53618b4..ea12b4a 100644 --- a/nikola/plugins/command/import_blogger.py +++ b/nikola/plugins/command/import_blogger.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/import_feed.py b/nikola/plugins/command/import_feed.py index b25d9ec..70a5cd5 100644 --- a/nikola/plugins/command/import_feed.py +++ b/nikola/plugins/command/import_feed.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/import_wordpress.py b/nikola/plugins/command/import_wordpress.py index 4f32198..0c9915a 100644 --- a/nikola/plugins/command/import_wordpress.py +++ b/nikola/plugins/command/import_wordpress.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -145,7 +145,7 @@ class CommandImportWordpress(Command, ImportMixin): rendered_template = re.sub('# REDIRECTIONS = ', 'REDIRECTIONS = ', rendered_template) if self.timezone: - rendered_template = re.sub('# TIMEZONE = \'Europe/Zurich\'', + rendered_template = re.sub('# TIMEZONE = \'UTC\'', 'TIMEZONE = \'' + self.timezone + '\'', rendered_template) self.write_configuration(self.get_configuration_output_path(), diff --git a/nikola/plugins/command/init.py b/nikola/plugins/command/init.py index 1873ec4..96caad8 100644 --- a/nikola/plugins/command/init.py +++ b/nikola/plugins/command/init.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/install_plugin.py b/nikola/plugins/command/install_plugin.py index fdbd0b7..1d6584d 100644 --- a/nikola/plugins/command/install_plugin.py +++ b/nikola/plugins/command/install_plugin.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -27,6 +27,7 @@ from __future__ import print_function import codecs import os +import sys import json import shutil import subprocess @@ -145,7 +146,6 @@ class CommandInstallPlugin(Command): shutil.copytree(plugin_path, dest_path) reqpath = os.path.join(dest_path, 'requirements.txt') - print(reqpath) if os.path.exists(reqpath): LOGGER.notice('This plugin has Python dependencies.') LOGGER.notice('Installing dependencies with pip...') @@ -180,6 +180,10 @@ class CommandInstallPlugin(Command): LOGGER.notice('This plugin has a sample config file.') print('Contents of the conf.py.sample file:\n') with codecs.open(confpypath, 'rb', 'utf-8') as fh: - print(indent(pygments.highlight( - fh.read(), PythonLexer(), TerminalFormatter()), 4 * ' ')) + if sys.platform == 'win32': + print(indent(pygments.highlight( + fh.read(), PythonLexer(), TerminalFormatter()), + 4 * ' ')) + else: + print(indent(fh.read(), 4 * ' ')) return True diff --git a/nikola/plugins/command/install_theme.py b/nikola/plugins/command/install_theme.py index a9d835a..569397b 100644 --- a/nikola/plugins/command/install_theme.py +++ b/nikola/plugins/command/install_theme.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -26,9 +26,10 @@ from __future__ import print_function import os +import sys +import codecs import json import shutil -import codecs from io import BytesIO import pygments @@ -116,18 +117,22 @@ class CommandInstallTheme(Command): print(theme) return True else: - self.do_install(name, data) - # See if the theme's parent is available. If not, install it - while True: - parent_name = utils.get_parent_theme_name(name) - if parent_name is None: - break - try: - utils.get_theme_path(parent_name) - break - except: # Not available - self.do_install(parent_name, data) - name = parent_name + # `name` may be modified by the while loop. + origname = name + installstatus = self.do_install(name, data) + # See if the theme's parent is available. If not, install it + while True: + parent_name = utils.get_parent_theme_name(name) + if parent_name is None: + break + try: + utils.get_theme_path(parent_name) + break + except: # Not available + self.do_install(parent_name, data) + name = parent_name + if installstatus: + LOGGER.notice('Remember to set THEME="{0}" in conf.py to use this theme.'.format(origname)) def do_install(self, name, data): if name in data: @@ -155,9 +160,13 @@ class CommandInstallTheme(Command): shutil.copytree(theme_path, dest_path) confpypath = os.path.join(dest_path, 'conf.py.sample') if os.path.exists(confpypath): - LOGGER.notice('This plugin has a sample config file.') + LOGGER.notice('This plugin has a sample config file. Integrate it with yours in order to make this theme work!') print('Contents of the conf.py.sample file:\n') with codecs.open(confpypath, 'rb', 'utf-8') as fh: - print(indent(pygments.highlight( - fh.read(), PythonLexer(), TerminalFormatter()), 4 * ' ')) - return True + if sys.platform == 'win32': + print(indent(pygments.highlight( + fh.read(), PythonLexer(), TerminalFormatter()), + 4 * ' ')) + else: + print(indent(fh.read(), 4 * ' ')) + return True diff --git a/nikola/plugins/command/mincss.py b/nikola/plugins/command/mincss.py index 5c9a7cb..0193458 100644 --- a/nikola/plugins/command/mincss.py +++ b/nikola/plugins/command/mincss.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/new_post.py b/nikola/plugins/command/new_post.py index ea0f3de..a5c551d 100644 --- a/nikola/plugins/command/new_post.py +++ b/nikola/plugins/command/new_post.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/orphans.plugin b/nikola/plugins/command/orphans.plugin new file mode 100644 index 0000000..408578b --- /dev/null +++ b/nikola/plugins/command/orphans.plugin @@ -0,0 +1,10 @@ +[Core] +Name = orphans +Module = orphans + +[Documentation] +Author = Roberto Alsina, Chris Warrick +Version = 0.1 +Website = http://getnikola.com +Description = List all orphans + diff --git a/nikola/plugins/command/orphans.py b/nikola/plugins/command/orphans.py new file mode 100644 index 0000000..ff114b4 --- /dev/null +++ b/nikola/plugins/command/orphans.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2014 Roberto Alsina, Chris Warrick and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function +import os + +from nikola.plugin_categories import Command +from nikola.plugins.command.check import real_scan_files + + +class CommandOrphans(Command): + name = "orphans" + doc_purpose = "list all orphans" + doc_description = """\ +List all orphans, i.e. all files that are in the output directory, +but are not generated by Nikola. + +Output contains filenames only (it is passable to `xargs rm` or the like).""" + + def _execute(self, options, args): + orphans = real_scan_files(self.site)[0] + print('\n'.join([p for p in orphans if not os.path.isdir(p)])) diff --git a/nikola/plugins/command/planetoid/__init__.py b/nikola/plugins/command/planetoid/__init__.py index 369862b..ff5dd13 100644 --- a/nikola/plugins/command/planetoid/__init__.py +++ b/nikola/plugins/command/planetoid/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/serve.py b/nikola/plugins/command/serve.py index 07403d4..2dd15c1 100644 --- a/nikola/plugins/command/serve.py +++ b/nikola/plugins/command/serve.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/command/version.py b/nikola/plugins/command/version.py index 65896e9..9b42423 100644 --- a/nikola/plugins/command/version.py +++ b/nikola/plugins/command/version.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -41,4 +41,4 @@ class CommandVersion(Command): def _execute(self, options={}, args=None): """Print the version number.""" - print("Nikola version " + __version__) + print("Nikola v" + __version__) diff --git a/nikola/plugins/compile/__init__.py b/nikola/plugins/compile/__init__.py index e69de29..6ad8bac 100644 --- a/nikola/plugins/compile/__init__.py +++ b/nikola/plugins/compile/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2014 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/nikola/plugins/compile/asciidoc.py b/nikola/plugins/compile/asciidoc.py index 67dfe1a..12cb4bf 100644 --- a/nikola/plugins/compile/asciidoc.py +++ b/nikola/plugins/compile/asciidoc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -37,11 +37,17 @@ import subprocess from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs, req_missing +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + class CompileAsciiDoc(PageCompiler): """Compile asciidoc into HTML.""" name = "asciidoc" + demote_headers = True def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) @@ -52,7 +58,10 @@ class CompileAsciiDoc(PageCompiler): req_missing(['asciidoc'], 'build this site (compile with asciidoc)', python=False) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/bbcode.py b/nikola/plugins/compile/bbcode.py index e998417..5345be3 100644 --- a/nikola/plugins/compile/bbcode.py +++ b/nikola/plugins/compile/bbcode.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -37,6 +37,10 @@ except ImportError: from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs, req_missing +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA class CompileBbcode(PageCompiler): @@ -63,7 +67,10 @@ class CompileBbcode(PageCompiler): out_file.write(output) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/html.py b/nikola/plugins/compile/html.py index a309960..5352f00 100644 --- a/nikola/plugins/compile/html.py +++ b/nikola/plugins/compile/html.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -27,25 +27,40 @@ """Implementation of compile_html for HTML source files.""" import os -import shutil +import re import codecs from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + + +_META_SEPARATOR = '(' + os.linesep * 2 + '|' + ('\n' * 2) + '|' + ("\r\n" * 2) + ')' + class CompileHtml(PageCompiler): """Compile HTML into HTML.""" - name = "html" def compile_html(self, source, dest, is_two_file=True): makedirs(os.path.dirname(dest)) - shutil.copyfile(source, dest) + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + if not is_two_file: + data = re.split(_META_SEPARATOR, data, maxsplit=1)[-1] + out_file.write(data) return True def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) @@ -55,4 +70,4 @@ class CompileHtml(PageCompiler): for k, v in metadata.items(): fd.write('.. {0}: {1}\n'.format(k, v)) fd.write('-->\n\n') - fd.write("\n<p>Write your post here.</p>") + fd.write("\n<p>Write your post here.</p>\n") diff --git a/nikola/plugins/compile/ipynb/__init__.py b/nikola/plugins/compile/ipynb/__init__.py index 7c318ca..5f2f0b3 100644 --- a/nikola/plugins/compile/ipynb/__init__.py +++ b/nikola/plugins/compile/ipynb/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2013 Damian Avila. +# Copyright © 2013-2014 Damián Avila and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -41,6 +41,11 @@ except ImportError: from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs, req_missing +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + class CompileIPynb(PageCompiler): """Compile IPynb into HTML.""" @@ -49,7 +54,7 @@ class CompileIPynb(PageCompiler): def compile_html(self, source, dest, is_two_file=True): if flag is None: - req_missing(['ipython>=1.0.0'], 'build this site (compile ipynb)') + req_missing(['ipython>=1.1.0'], 'build this site (compile ipynb)') makedirs(os.path.dirname(dest)) HTMLExporter.default_template = 'basic' c = Config(self.site.config['IPYNB_CONFIG']) @@ -62,18 +67,20 @@ class CompileIPynb(PageCompiler): out_file.write(body) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) d_name = os.path.dirname(path) makedirs(os.path.dirname(path)) meta_path = os.path.join(d_name, kw['slug'] + ".meta") with codecs.open(meta_path, "wb+", "utf8") as fd: - if onefile: - fd.write('%s\n' % kw['title']) - fd.write('%s\n' % kw['slug']) - fd.write('%s\n' % kw['date']) - fd.write('%s\n' % kw['tags']) + fd.write('\n'.join((metadata['title'], metadata['slug'], + metadata['date'], metadata['tags'], + metadata['link'], + metadata['description'], metadata['type']))) print("Your post's metadata is at: ", meta_path) with codecs.open(path, "wb+", "utf8") as fd: fd.write("""{ diff --git a/nikola/plugins/compile/markdown/__init__.py b/nikola/plugins/compile/markdown/__init__.py index b41c6b5..1376b11 100644 --- a/nikola/plugins/compile/markdown/__init__.py +++ b/nikola/plugins/compile/markdown/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -50,6 +50,12 @@ except ImportError: gist_extension = None podcast_extension = None + +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs, req_missing @@ -58,6 +64,7 @@ class CompileMarkdown(PageCompiler): """Compile markdown into HTML.""" name = "markdown" + demote_headers = True extensions = [gist_extension, nikola_extension, podcast_extension] site = None @@ -75,7 +82,10 @@ class CompileMarkdown(PageCompiler): out_file.write(output) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/markdown/mdx_gist.py b/nikola/plugins/compile/markdown/mdx_gist.py index 3c3bef9..d92295d 100644 --- a/nikola/plugins/compile/markdown/mdx_gist.py +++ b/nikola/plugins/compile/markdown/mdx_gist.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2013 Michael Rabbitt. +# Copyright © 2013 Michael Rabbitt. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the diff --git a/nikola/plugins/compile/markdown/mdx_nikola.py b/nikola/plugins/compile/markdown/mdx_nikola.py index b0ad2f7..b7c29a5 100644 --- a/nikola/plugins/compile/markdown/mdx_nikola.py +++ b/nikola/plugins/compile/markdown/mdx_nikola.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -34,10 +34,6 @@ from markdown.extensions import Extension class NikolaPostProcessor(Postprocessor): def run(self, text): output = text - # h1 is reserved for the title so increment all header levels - for n in reversed(range(1, 9)): - output = re.sub('<h%i>' % n, '<h%i>' % (n + 1), output) - output = re.sub('</h%i>' % n, '</h%i>' % (n + 1), output) # python-markdown's highlighter uses the class 'codehilite' to wrap # code, instead of the standard 'code'. None of the standard diff --git a/nikola/plugins/compile/markdown/mdx_podcast.py b/nikola/plugins/compile/markdown/mdx_podcast.py index be8bb6b..b38b969 100644 --- a/nikola/plugins/compile/markdown/mdx_podcast.py +++ b/nikola/plugins/compile/markdown/mdx_podcast.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2013 Michael Rabbitt, Roberto Alsina +# Copyright © 2013-2014 Michael Rabbitt, Roberto Alsina and others. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the diff --git a/nikola/plugins/compile/misaka.py b/nikola/plugins/compile/misaka.py index 3733a85..8777ffc 100644 --- a/nikola/plugins/compile/misaka.py +++ b/nikola/plugins/compile/misaka.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (c) 2013 Chris Lee +# Copyright © 2013-2014 Chris Lee and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -37,6 +37,11 @@ try: except ImportError: misaka = None # NOQA nikola_extension = None +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + gist_extension = None podcast_extension = None @@ -48,6 +53,7 @@ class CompileMisaka(PageCompiler): """Compile Misaka into HTML.""" name = "misaka" + demote_headers = True def __init__(self, *args, **kwargs): super(CompileMisaka, self).__init__(*args, **kwargs) @@ -68,7 +74,10 @@ class CompileMisaka(PageCompiler): out_file.write(output) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/pandoc.py b/nikola/plugins/compile/pandoc.py index 3a2911f..57c7d71 100644 --- a/nikola/plugins/compile/pandoc.py +++ b/nikola/plugins/compile/pandoc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -37,6 +37,11 @@ import subprocess from nikola.plugin_categories import PageCompiler from nikola.utils import req_missing, makedirs +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + class CompilePandoc(PageCompiler): """Compile markups into HTML using pandoc.""" @@ -52,7 +57,10 @@ class CompilePandoc(PageCompiler): req_missing(['pandoc'], 'build this site (compile with pandoc)', python=False) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/php.py b/nikola/plugins/compile/php.py index 44701c8..14b80e8 100644 --- a/nikola/plugins/compile/php.py +++ b/nikola/plugins/compile/php.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -35,6 +35,11 @@ import codecs from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + class CompilePhp(PageCompiler): """Compile PHP into PHP.""" @@ -46,7 +51,10 @@ class CompilePhp(PageCompiler): shutil.copyfile(source, dest) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) os.makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py index c71a5f8..50b37cf 100644 --- a/nikola/plugins/compile/rest/__init__.py +++ b/nikola/plugins/compile/rest/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -35,10 +35,16 @@ try: import docutils.utils import docutils.io import docutils.readers.standalone + import docutils.writers.html4css1 has_docutils = True except ImportError: has_docutils = False +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + from nikola.plugin_categories import PageCompiler from nikola.utils import get_logger, makedirs, req_missing @@ -47,6 +53,7 @@ class CompileRest(PageCompiler): """Compile reSt into HTML.""" name = "rest" + demote_headers = True logger = None def compile_html(self, source, dest, is_two_file=True): @@ -71,14 +78,16 @@ class CompileRest(PageCompiler): # author). add_ln = len(spl[0].splitlines()) + 1 + default_template_path = os.path.join(os.path.dirname(__file__), 'template.txt') output, error_level, deps = rst2html( data, settings_overrides={ - 'initial_header_level': 2, + 'initial_header_level': 1, 'record_dependencies': True, 'stylesheet_path': None, 'link_stylesheet': True, 'syntax_highlight': 'short', 'math_output': 'mathjax', + 'template': default_template_path, }, logger=self.logger, l_source=source, l_add_ln=add_ln) out_file.write(output) deps_path = dest + '.dep' @@ -94,7 +103,10 @@ class CompileRest(PageCompiler): return False def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) @@ -117,6 +129,9 @@ class CompileRest(PageCompiler): plugin_info.plugin_object.short_help = plugin_info.description self.logger = get_logger('compile_rest', site.loghandlers) + if not site.debug: + self.logger.level = 4 + return super(CompileRest, self).set_site(site) @@ -139,7 +154,10 @@ def get_observer(settings): """ errormap = {0: 1, 1: 2, 2: 4, 3: 5, 4: 6} text = docutils.nodes.Element.astext(msg) - out = '[{source}:{line}] {text}'.format(source=settings['source'], line=msg['line'] + settings['add_ln'], text=text) + line = msg['line'] + settings['add_ln'] if 'line' in msg else 0 + out = '[{source}{colon}{line}] {text}'.format( + source=settings['source'], colon=(':' if line else ''), + line=line, text=text) settings['logger'].log(errormap[msg['level']], out) return observer @@ -155,6 +173,14 @@ class NikolaReader(docutils.readers.standalone.Reader): return document +def add_node(node, visit_function=None, depart_function=None): + docutils.nodes._add_node_class_names([node.__name__]) + if visit_function: + setattr(docutils.writers.html4css1.HTMLTranslator, 'visit_' + node.__name__, visit_function) + if depart_function: + setattr(docutils.writers.html4css1.HTMLTranslator, 'depart_' + node.__name__, depart_function) + + def rst2html(source, source_path=None, source_class=docutils.io.StringInput, destination_path=None, reader=None, parser=None, parser_name='restructuredtext', writer=None, diff --git a/nikola/plugins/compile/rest/chart.py b/nikola/plugins/compile/rest/chart.py index ee917b9..03878a3 100644 --- a/nikola/plugins/compile/rest/chart.py +++ b/nikola/plugins/compile/rest/chart.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/compile/rest/doc.py b/nikola/plugins/compile/rest/doc.py index 915a7e1..a150a81 100644 --- a/nikola/plugins/compile/rest/doc.py +++ b/nikola/plugins/compile/rest/doc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/compile/rest/listing.py b/nikola/plugins/compile/rest/listing.py index 31975bb..ecf885f 100644 --- a/nikola/plugins/compile/rest/listing.py +++ b/nikola/plugins/compile/rest/listing.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/compile/rest/media.py b/nikola/plugins/compile/rest/media.py index d1930dd..ccda559 100644 --- a/nikola/plugins/compile/rest/media.py +++ b/nikola/plugins/compile/rest/media.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py index eae4016..6804b58 100644 --- a/nikola/plugins/compile/rest/post_list.py +++ b/nikola/plugins/compile/rest/post_list.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2013 Udo Spallek, Roberto Alsina and others. +# Copyright © 2013-2014 Udo Spallek, Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -33,6 +33,9 @@ from docutils.parsers.rst import Directive, directives from nikola import utils from nikola.plugin_categories import RestExtension +# WARNING: the directive name is post-list +# (with a DASH instead of an UNDERSCORE) + class Plugin(RestExtension): name = "rest_post_list" diff --git a/nikola/plugins/compile/rest/slides.py b/nikola/plugins/compile/rest/slides.py index 41c3314..203ae51 100644 --- a/nikola/plugins/compile/rest/slides.py +++ b/nikola/plugins/compile/rest/slides.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/compile/rest/soundcloud.py b/nikola/plugins/compile/rest/soundcloud.py index 6fb3e99..a26806c 100644 --- a/nikola/plugins/compile/rest/soundcloud.py +++ b/nikola/plugins/compile/rest/soundcloud.py @@ -15,12 +15,13 @@ class Plugin(RestExtension): def set_site(self, site): self.site = site directives.register_directive('soundcloud', SoundCloud) + directives.register_directive('soundcloud_playlist', SoundCloudPlaylist) return super(Plugin, self).set_site(site) CODE = ("""<iframe width="{width}" height="{height}" scrolling="no" frameborder="no" -src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/tracks/""" +src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/{preslug}/""" """{sid}"> </iframe>""") @@ -40,6 +41,7 @@ class SoundCloud(Directive): 'width': directives.positive_int, 'height': directives.positive_int, } + preslug = "tracks" def run(self): """ Required by the Directive interface. Create docutils nodes """ @@ -48,6 +50,7 @@ class SoundCloud(Directive): 'sid': self.arguments[0], 'width': 600, 'height': 160, + 'preslug': self.preslug, } options.update(self.options) return [nodes.raw('', CODE.format(**options), format='html')] @@ -58,3 +61,7 @@ class SoundCloud(Directive): raise self.warning("This directive does not accept content. The " "'key=value' format for options is deprecated, " "use ':key: value' instead") + + +class SoundCloudPlaylist(SoundCloud): + preslug = "playlists" diff --git a/nikola/plugins/compile/rest/template.txt b/nikola/plugins/compile/rest/template.txt new file mode 100644 index 0000000..2591bce --- /dev/null +++ b/nikola/plugins/compile/rest/template.txt @@ -0,0 +1,8 @@ +%(head_prefix)s +%(head)s +%(stylesheet)s +%(body_prefix)s +%(body_pre_docinfo)s +%(docinfo)s +%(body)s +%(body_suffix)s diff --git a/nikola/plugins/compile/rest/vimeo.py b/nikola/plugins/compile/rest/vimeo.py index 6d66648..82c4dc1 100644 --- a/nikola/plugins/compile/rest/vimeo.py +++ b/nikola/plugins/compile/rest/vimeo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/compile/rest/youtube.py b/nikola/plugins/compile/rest/youtube.py index 3d4bdd3..19e12d1 100644 --- a/nikola/plugins/compile/rest/youtube.py +++ b/nikola/plugins/compile/rest/youtube.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/compile/textile.py b/nikola/plugins/compile/textile.py index b402329..73f35c0 100644 --- a/nikola/plugins/compile/textile.py +++ b/nikola/plugins/compile/textile.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -38,11 +38,17 @@ except ImportError: from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs, req_missing +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + class CompileTextile(PageCompiler): """Compile textile into HTML.""" name = "textile" + demote_headers = True def compile_html(self, source, dest, is_two_file=True): if textile is None: @@ -57,7 +63,10 @@ class CompileTextile(PageCompiler): out_file.write(output) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/txt2tags.py b/nikola/plugins/compile/txt2tags.py index 2f62f04..8c9724e 100644 --- a/nikola/plugins/compile/txt2tags.py +++ b/nikola/plugins/compile/txt2tags.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -40,14 +40,20 @@ try: except ImportError: txt2tags = None # NOQA +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + from nikola.plugin_categories import PageCompiler from nikola.utils import makedirs, req_missing -class CompileTextile(PageCompiler): +class CompileTxt2tags(PageCompiler): """Compile txt2tags into HTML.""" name = "txt2tags" + demote_headers = True def compile_html(self, source, dest, is_two_file=True): if txt2tags is None: @@ -57,7 +63,10 @@ class CompileTextile(PageCompiler): txt2tags(cmd) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/compile/wiki.py b/nikola/plugins/compile/wiki.py index b2c4afc..9a365fa 100644 --- a/nikola/plugins/compile/wiki.py +++ b/nikola/plugins/compile/wiki.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -37,6 +37,11 @@ except ImportError: creole = None from nikola.plugin_categories import PageCompiler +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None # NOQA + from nikola.utils import makedirs, req_missing @@ -44,6 +49,7 @@ class CompileWiki(PageCompiler): """Compile CreoleWiki into HTML.""" name = "wiki" + demote_headers = True def compile_html(self, source, dest, is_two_file=True): if creole is None: @@ -57,7 +63,10 @@ class CompileWiki(PageCompiler): out_file.write(output) def create_post(self, path, onefile=False, **kw): - metadata = {} + if OrderedDict is not None: + metadata = OrderedDict() + else: + metadata = {} metadata.update(self.default_metadata) metadata.update(kw) makedirs(os.path.dirname(path)) diff --git a/nikola/plugins/loghandler/__init__.py b/nikola/plugins/loghandler/__init__.py new file mode 100644 index 0000000..6ad8bac --- /dev/null +++ b/nikola/plugins/loghandler/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2014 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/nikola/plugins/loghandler/smtp.py b/nikola/plugins/loghandler/smtp.py index deb8f4e..2c9fd9c 100644 --- a/nikola/plugins/loghandler/smtp.py +++ b/nikola/plugins/loghandler/smtp.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Daniel Devine and others. +# Copyright © 2012-2014 Daniel Devine and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/loghandler/stderr.py b/nikola/plugins/loghandler/stderr.py index 71f1de5..75acffc 100644 --- a/nikola/plugins/loghandler/stderr.py +++ b/nikola/plugins/loghandler/stderr.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Daniel Devine and others. +# Copyright © 2012-2014 Daniel Devine and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -29,6 +29,8 @@ from blinker import signal import logbook import os +from nikola import DEBUG + class StderrHandler(SignalHandler): """Logs messages to stderr.""" @@ -39,7 +41,7 @@ class StderrHandler(SignalHandler): conf = self.site.config.get('LOGGING_HANDLERS').get('stderr') if conf or os.getenv('NIKOLA_DEBUG'): self.site.loghandlers.append(logbook.StderrHandler( - level='DEBUG' if os.getenv('NIKOLA_DEBUG') else conf.get('loglevel', 'WARNING').upper(), + level='DEBUG' if DEBUG else conf.get('loglevel', 'WARNING').upper(), format_string=u'[{record.time:%Y-%m-%dT%H:%M:%SZ}] {record.level_name}: {record.channel}: {record.message}' )) diff --git a/nikola/plugins/task/__init__.py b/nikola/plugins/task/__init__.py index e69de29..6ad8bac 100644 --- a/nikola/plugins/task/__init__.py +++ b/nikola/plugins/task/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2014 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/nikola/plugins/task/archive.py b/nikola/plugins/task/archive.py index 3afbea1..a65a63f 100644 --- a/nikola/plugins/task/archive.py +++ b/nikola/plugins/task/archive.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -92,7 +92,8 @@ class Archive(Task): kw['filters'], context, ) - task_cfg = {1: task['uptodate'][0].config, 2: kw} + n = len(post_list) if 'posts' in context else len(months) + task_cfg = {1: task['uptodate'][0].config, 2: kw, 3: n} task['uptodate'] = [config_changed(task_cfg)] task['basename'] = self.name yield task @@ -123,7 +124,7 @@ class Archive(Task): kw['filters'], context, ) - task_cfg = {1: task['uptodate'][0].config, 2: kw} + task_cfg = {1: task['uptodate'][0].config, 2: kw, 3: len(post_list)} task['uptodate'] = [config_changed(task_cfg)] task['basename'] = self.name yield task @@ -151,7 +152,7 @@ class Archive(Task): kw['filters'], context, ) - task_cfg = {1: task['uptodate'][0].config, 2: kw} + task_cfg = {1: task['uptodate'][0].config, 2: kw, 3: len(years)} task['uptodate'] = [config_changed(task_cfg)] task['basename'] = self.name yield task diff --git a/nikola/plugins/task/build_less.py b/nikola/plugins/task/build_less.py index 8889cbe..14a53f9 100644 --- a/nikola/plugins/task/build_less.py +++ b/nikola/plugins/task/build_less.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -29,6 +29,7 @@ from __future__ import unicode_literals import codecs import glob import os +import sys import subprocess from nikola.plugin_categories import Task @@ -41,10 +42,10 @@ class BuildLess(Task): name = "build_less" sources_folder = "less" sources_ext = ".less" - compiler_name = "lessc" def gen_tasks(self): """Generate CSS out of LESS sources.""" + self.compiler_name = self.site.config['LESS_COMPILER'] kw = { 'cache_folder': self.site.config['CACHE_FOLDER'], @@ -79,7 +80,13 @@ class BuildLess(Task): def compile_target(target, dst): utils.makedirs(dst_dir) src = os.path.join(kw['cache_folder'], self.sources_folder, target) - compiled = subprocess.check_output([self.compiler_name, src]) + run_in_shell = sys.platform == 'win32' + try: + compiled = subprocess.check_output([self.compiler_name, src], shell=run_in_shell) + except OSError: + utils.req_missing([self.compiler_name], + 'build LESS files (and use this theme)', + False, False) with open(dst, "wb+") as outf: outf.write(compiled) diff --git a/nikola/plugins/task/build_sass.py b/nikola/plugins/task/build_sass.py index a5d22fb..7575505 100644 --- a/nikola/plugins/task/build_sass.py +++ b/nikola/plugins/task/build_sass.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -29,6 +29,7 @@ from __future__ import unicode_literals import codecs import glob import os +import sys import subprocess from nikola.plugin_categories import Task @@ -41,11 +42,11 @@ class BuildSass(Task): name = "build_sass" sources_folder = "sass" sources_ext = (".sass", ".scss") - compiler_name = "sass" def gen_tasks(self): """Generate CSS out of Sass sources.""" self.logger = utils.get_logger('build_sass', self.site.loghandlers) + self.compiler_name = self.site.config['SASS_COMPILER'] kw = { 'cache_folder': self.site.config['CACHE_FOLDER'], @@ -79,8 +80,14 @@ class BuildSass(Task): def compile_target(target, dst): utils.makedirs(dst_dir) + run_in_shell = sys.platform == 'win32' src = os.path.join(kw['cache_folder'], self.sources_folder, target) - compiled = subprocess.check_output([self.compiler_name, src]) + try: + compiled = subprocess.check_output([self.compiler_name, src], shell=run_in_shell) + except OSError: + utils.req_missing([self.compiler_name], + 'build Sass files (and use this theme)', + False, False) with open(dst, "wb+") as outf: outf.write(compiled) @@ -99,7 +106,7 @@ class BuildSass(Task): if base in seennames: self.logger.error( - 'Duplicate filenames for SASS compiled files: {0} and ' + 'Duplicate filenames for Sass compiled files: {0} and ' '{1} (both compile to {2})'.format( seennames[base], target, base + ".css")) else: diff --git a/nikola/plugins/task/bundles.py b/nikola/plugins/task/bundles.py index 488f96f..b035b97 100644 --- a/nikola/plugins/task/bundles.py +++ b/nikola/plugins/task/bundles.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -44,7 +44,9 @@ class BuildBundles(LateTask): def set_site(self, site): super(BuildBundles, self).set_site(site) - if webassets is None: + if webassets is None and self.site.config['USE_BUNDLES']: + utils.req_missing(['webassets'], 'USE_BUNDLES', optional=True) + utils.LOGGER.warn('Setting USE_BUNDLES to False.') self.site.config['USE_BUNDLES'] = False def gen_tasks(self): @@ -111,6 +113,6 @@ def get_theme_bundles(themes): for line in fd: name, files = line.split('=') files = [f.strip() for f in files.split(',')] - bundles[name.strip()] = files + bundles[name.strip().replace('/', os.sep)] = files break return bundles diff --git a/nikola/plugins/task/copy_assets.py b/nikola/plugins/task/copy_assets.py index f3d85df..21f1f85 100644 --- a/nikola/plugins/task/copy_assets.py +++ b/nikola/plugins/task/copy_assets.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/copy_files.py b/nikola/plugins/task/copy_files.py index 88e89eb..9846ca0 100644 --- a/nikola/plugins/task/copy_files.py +++ b/nikola/plugins/task/copy_files.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/galleries.py b/nikola/plugins/task/galleries.py index cf670e0..6977eab 100644 --- a/nikola/plugins/task/galleries.py +++ b/nikola/plugins/task/galleries.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -51,6 +51,7 @@ import PyRSS2Gen as rss from nikola.plugin_categories import Task from nikola import utils from nikola.post import Post +from nikola.utils import req_missing class Galleries(Task): @@ -77,6 +78,9 @@ class Galleries(Task): def gen_tasks(self): """Render image galleries.""" + if Image is None: + req_missing(['pillow'], 'render galleries') + self.logger = utils.get_logger('render_galleries', self.site.loghandlers) self.image_ext_list = ['.jpg', '.png', '.jpeg', '.gif', '.svg', '.bmp', '.tiff'] self.image_ext_list.extend(self.site.config.get('EXTRA_IMAGE_EXTENSIONS', [])) @@ -111,7 +115,7 @@ class Galleries(Task): for gallery in self.gallery_list: # Create subfolder list - folder_list = [x.split(os.sep)[-2] for x in + folder_list = [(x, x.split(os.sep)[-2]) for x in glob.glob(os.path.join(gallery, '*') + os.sep)] # Parse index into a post (with translations) @@ -137,7 +141,7 @@ class Galleries(Task): for task in self.remove_excluded_image(image): yield task - crumbs = utils.get_crumbs(gallery) + crumbs = utils.get_crumbs(gallery, index_folder=self) # Create index.html for each language for lang in self.kw['translations']: @@ -173,9 +177,20 @@ class Galleries(Task): thumbs = ['.thumbnail'.join(os.path.splitext(p)) for p in image_list] thumbs = [os.path.join(self.kw['output_folder'], t) for t in thumbs] + folders = [] + + # Generate friendly gallery names + for path, folder in folder_list: + fpost = self.parse_index(path) + if fpost: + ft = fpost.title(lang) or folder + else: + ft = folder + folders.append((folder, ft)) + ## TODO: in v7 remove images from context, use photo_array context["images"] = list(zip(image_name_list, thumbs, img_titles)) - context["folders"] = folder_list + context["folders"] = folders context["crumbs"] = crumbs context["permalink"] = self.site.link( "gallery", os.path.basename(gallery), lang) @@ -288,8 +303,14 @@ class Galleries(Task): False, self.site.MESSAGES, 'story.tmpl', - self.site.get_compiler(index_path).compile_html + self.site.get_compiler(index_path) ) + # If this did not exist, galleries without a title in the + # index.txt file would be errorneously named `index` + # (warning: galleries titled index and filenamed differently + # may break) + if post.title == 'index': + post.title = os.path.split(gallery)[1] else: post = None return post @@ -460,7 +481,7 @@ class Galleries(Task): os.path.join( self.site.config['OUTPUT_FOLDER'], img)).st_size args = { - 'title': full_title.split('"')[-2], + 'title': full_title.split('"')[-2] if full_title else '', 'link': make_url(img), 'guid': rss.Guid(img, False), 'pubDate': self.image_date(img), @@ -477,7 +498,7 @@ class Galleries(Task): description='', lastBuildDate=datetime.datetime.now(), items=items, - generator='nikola', + generator='Nikola <http://getnikola.com/>', language=lang ) rss_obj.self_url = make_url(permalink) @@ -523,8 +544,9 @@ class Galleries(Task): try: im.thumbnail(size, Image.ANTIALIAS) im.save(dst) - except Exception: - self.logger.warn("Can't thumbnail {0}, using original image as thumbnail".format(src)) + except Exception as e: + self.logger.warn("Can't thumbnail {0}, using original " + "image as thumbnail ({1})".format(src, e)) utils.copy_file(src, dst) else: # Image is small utils.copy_file(src, dst) diff --git a/nikola/plugins/task/gzip.py b/nikola/plugins/task/gzip.py index 738d52c..bcc9637 100644 --- a/nikola/plugins/task/gzip.py +++ b/nikola/plugins/task/gzip.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/indexes.py b/nikola/plugins/task/indexes.py index 0d20422..3f45161 100644 --- a/nikola/plugins/task/indexes.py +++ b/nikola/plugins/task/indexes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -57,6 +57,7 @@ class Indexes(Task): "hide_untranslated_posts": self.site.config['HIDE_UNTRANSLATED_POSTS'], "indexes_title": self.site.config['INDEXES_TITLE'], "indexes_pages": self.site.config['INDEXES_PAGES'], + "indexes_pages_main": self.site.config['INDEXES_PAGES_MAIN'], "blog_title": self.site.config["BLOG_TITLE"], } @@ -78,12 +79,18 @@ class Indexes(Task): for i, post_list in enumerate(lists): context = {} indexes_title = kw['indexes_title'] or kw['blog_title'] + if kw["indexes_pages_main"]: + ipages_i = i + 1 + ipages_msg = "page %d" + else: + ipages_i = i + ipages_msg = "old posts, page %d" if kw["indexes_pages"]: - indexes_pages = kw["indexes_pages"] % i + indexes_pages = kw["indexes_pages"] % ipages_i else: indexes_pages = " (" + \ - kw["messages"][lang]["old posts page %d"] % i + ")" - if i > 0: + kw["messages"][lang][ipages_msg] % ipages_i + ")" + if i > 0 or kw["indexes_pages_main"]: context["title"] = indexes_title + indexes_pages else: context["title"] = indexes_title diff --git a/nikola/plugins/task/listings.py b/nikola/plugins/task/listings.py index ab62e74..d8ed43b 100644 --- a/nikola/plugins/task/listings.py +++ b/nikola/plugins/task/listings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/localsearch/__init__.py b/nikola/plugins/task/localsearch/__init__.py index 9162604..c501d80 100644 --- a/nikola/plugins/task/localsearch/__init__.py +++ b/nikola/plugins/task/localsearch/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/mustache/__init__.py b/nikola/plugins/task/mustache/__init__.py index c392e3b..5be98f0 100644 --- a/nikola/plugins/task/mustache/__init__.py +++ b/nikola/plugins/task/mustache/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -31,7 +31,9 @@ import json import os from nikola.plugin_categories import Task -from nikola.utils import config_changed, copy_file, unicode_str, makedirs +from nikola.utils import ( + config_changed, copy_file, LocaleBorg, makedirs, unicode_str, +) class Mustache(Task): @@ -106,7 +108,7 @@ class Mustache(Task): }) # Comments - context = dict(post=post, lang=self.site.current_lang()) + context = dict(post=post, lang=LocaleBorg().current_lang) context.update(self.site.GLOBAL_CONTEXT) data["comment_html"] = self.site.template_system.render_template( 'mustache-comment-form.tmpl', None, context).strip() diff --git a/nikola/plugins/task/pages.py b/nikola/plugins/task/pages.py index eb5b49e..f4c0469 100644 --- a/nikola/plugins/task/pages.py +++ b/nikola/plugins/task/pages.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/posts.py b/nikola/plugins/task/posts.py index 18d61b8..a502b81 100644 --- a/nikola/plugins/task/posts.py +++ b/nikola/plugins/task/posts.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/redirect.py b/nikola/plugins/task/redirect.py index ade878a..6fafd13 100644 --- a/nikola/plugins/task/redirect.py +++ b/nikola/plugins/task/redirect.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/rss.py b/nikola/plugins/task/rss.py index bcca4da..e5f7548 100644 --- a/nikola/plugins/task/rss.py +++ b/nikola/plugins/task/rss.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/sitemap/__init__.py b/nikola/plugins/task/sitemap/__init__.py index f34bc0a..0164000 100644 --- a/nikola/plugins/task/sitemap/__init__.py +++ b/nikola/plugins/task/sitemap/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated diff --git a/nikola/plugins/task/sources.py b/nikola/plugins/task/sources.py index 672f354..2324af2 100644 --- a/nikola/plugins/task/sources.py +++ b/nikola/plugins/task/sources.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -66,7 +66,7 @@ class Sources(Task): if dest_ext == post.source_ext(): continue if lang != kw["default_lang"]: - source_lang = source + '.' + lang + source_lang = utils.get_translation_candidate(self.site.config, source, lang) if os.path.exists(source_lang): source = source_lang if os.path.isfile(source): diff --git a/nikola/plugins/task/tags.py b/nikola/plugins/task/tags.py index 299dca4..a2444ec 100644 --- a/nikola/plugins/task/tags.py +++ b/nikola/plugins/task/tags.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -110,8 +110,14 @@ class RenderTags(Task): # Tag cloud json file tag_cloud_data = {} for tag, posts in self.site.posts_per_tag.items(): + tag_posts = dict(posts=[{'title': post.meta[post.default_lang]['title'], + 'date': post.date.strftime('%m/%d/%Y'), + 'isodate': post.date.isoformat(), + 'url': post.base_path.replace('cache', '')} + for post in reversed(sorted(self.site.timeline, key=lambda post: post.date)) + if tag in post.alltags]) tag_cloud_data[tag] = [len(posts), self.site.link( - 'tag', tag, self.site.config['DEFAULT_LANG'])] + 'tag', tag, self.site.config['DEFAULT_LANG']), tag_posts] output_name = os.path.join(kw['output_folder'], 'assets', 'js', 'tag_cloud_data.json') @@ -124,6 +130,7 @@ class RenderTags(Task): 'basename': str(self.name), 'name': str(output_name) } + task['uptodate'] = [utils.config_changed(tag_cloud_data)] task['targets'] = [output_name] task['actions'] = [(write_tag_data, [tag_cloud_data])] @@ -189,7 +196,7 @@ class RenderTags(Task): return name # FIXME: deduplicate this with render_indexes - template_name = "index.tmpl" + template_name = "tagindex.tmpl" # Split in smaller lists lists = [] while post_list: diff --git a/nikola/plugins/template/__init__.py b/nikola/plugins/template/__init__.py index e69de29..6ad8bac 100644 --- a/nikola/plugins/template/__init__.py +++ b/nikola/plugins/template/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +# Copyright © 2012-2014 Roberto Alsina and others. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/nikola/plugins/template/jinja.py b/nikola/plugins/template/jinja.py index a40a476..17c33d4 100644 --- a/nikola/plugins/template/jinja.py +++ b/nikola/plugins/template/jinja.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -55,7 +55,7 @@ class JinjaTemplates(TemplateSystem): self.lookup.globals['enumerate'] = enumerate def set_directories(self, directories, cache_folder): - """Createa template lookup.""" + """Create a template lookup.""" if jinja2 is None: req_missing(['jinja2'], 'use this theme') self.lookup.loader = jinja2.FileSystemLoader(directories, @@ -74,9 +74,8 @@ class JinjaTemplates(TemplateSystem): return output def render_template_to_string(self, template, context): - """ Render template to a string using context. """ - - return jinja2.Template(template).render(**context) + """Render template to a string using context.""" + return self.lookup.from_string(template).render(**context) def template_deps(self, template_name): # Cache the lists of dependencies for each template name. diff --git a/nikola/plugins/template/mako.py b/nikola/plugins/template/mako.py index ae51cac..45f4335 100644 --- a/nikola/plugins/template/mako.py +++ b/nikola/plugins/template/mako.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2013 Roberto Alsina and others. +# Copyright © 2012-2014 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated |
