summaryrefslogtreecommitdiffstats
path: root/nikola/plugins
diff options
context:
space:
mode:
authorLibravatarAgustin Henze <tin@sluc.org.ar>2013-03-13 20:58:39 -0300
committerLibravatarAgustin Henze <tin@sluc.org.ar>2013-03-13 20:58:39 -0300
commit8b14a1e5b2ca574fdd4fd2377567ec98a110d4b6 (patch)
tree0895935489e4920d18824f7fb3a0d799649a27c3 /nikola/plugins
parent878ba1152ebc64a4a2609d23c9e400a6111db642 (diff)
Imported Upstream version 5.4.2upstream/5.4.2
Diffstat (limited to 'nikola/plugins')
-rw-r--r--nikola/plugins/__init__.py1
-rw-r--r--nikola/plugins/command_bootswatch_theme.py57
-rw-r--r--nikola/plugins/command_build.plugin10
-rw-r--r--nikola/plugins/command_build.py67
-rw-r--r--nikola/plugins/command_check.py67
-rw-r--r--nikola/plugins/command_console.py32
-rw-r--r--nikola/plugins/command_deploy.py8
-rw-r--r--nikola/plugins/command_import_blogger.py139
-rw-r--r--nikola/plugins/command_import_wordpress.py240
-rw-r--r--nikola/plugins/command_init.py44
-rw-r--r--nikola/plugins/command_install_theme.py57
-rw-r--r--nikola/plugins/command_new_post.py127
-rw-r--r--nikola/plugins/command_serve.py38
-rw-r--r--nikola/plugins/compile_bbcode.py8
-rw-r--r--nikola/plugins/compile_html.py8
-rw-r--r--nikola/plugins/compile_markdown/__init__.py14
-rw-r--r--nikola/plugins/compile_rest/__init__.py10
-rw-r--r--nikola/plugins/compile_rest/gist_directive.py12
-rw-r--r--nikola/plugins/compile_rest/pygments_code_block_directive.py39
-rw-r--r--nikola/plugins/compile_rest/slides.py7
-rw-r--r--nikola/plugins/compile_rest/soundcloud.py32
-rw-r--r--nikola/plugins/compile_rest/vimeo.py10
-rw-r--r--nikola/plugins/compile_rest/youtube.py8
-rw-r--r--nikola/plugins/compile_textile.py8
-rw-r--r--nikola/plugins/compile_txt2tags.py8
-rw-r--r--nikola/plugins/task_create_bundles.py12
-rw-r--r--nikola/plugins/task_indexes.py4
-rw-r--r--nikola/plugins/task_redirect.py5
-rw-r--r--nikola/plugins/task_render_galleries.py11
-rw-r--r--nikola/plugins/task_render_listings.py56
-rw-r--r--nikola/plugins/task_render_rss.py4
-rw-r--r--nikola/plugins/task_render_tags.py22
-rw-r--r--nikola/plugins/task_sitemap/__init__.py26
-rw-r--r--nikola/plugins/task_sitemap/sitemap_gen.py2
34 files changed, 685 insertions, 508 deletions
diff --git a/nikola/plugins/__init__.py b/nikola/plugins/__init__.py
index 2d9b1b2..b1de7f1 100644
--- a/nikola/plugins/__init__.py
+++ b/nikola/plugins/__init__.py
@@ -1,4 +1,3 @@
from __future__ import absolute_import
from . import command_import_wordpress # NOQA
-from . import command_build # NOQA
diff --git a/nikola/plugins/command_bootswatch_theme.py b/nikola/plugins/command_bootswatch_theme.py
index 6c1061f..8400c9f 100644
--- a/nikola/plugins/command_bootswatch_theme.py
+++ b/nikola/plugins/command_bootswatch_theme.py
@@ -23,7 +23,6 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-from optparse import OptionParser
import os
try:
@@ -38,37 +37,53 @@ class CommandBootswatchTheme(Command):
"""Given a swatch name and a parent theme, creates a custom theme."""
name = "bootswatch_theme"
+ doc_usage = "[options]"
+ doc_purpose = "Given a swatch name and a parent theme, creates a custom"\
+ " theme."
+ cmd_options = [
+ {
+ 'name': 'name',
+ 'short': 'n',
+ 'long': 'name',
+ 'default': 'custom',
+ 'type': str,
+ 'help': 'New theme name (default: custom)',
+ },
+ {
+ 'name': 'swatch',
+ 'short': 's',
+ 'default': 'slate',
+ 'type': str,
+ 'help': 'Name of the swatch from bootswatch.com.'
+ },
+ {
+ 'name': 'parent',
+ 'short': 'p',
+ 'long': 'parent',
+ 'default': 'site',
+ 'help': 'Parent theme name (default: site)',
+ },
+ ]
- def run(self, *args):
+ def _execute(self, options, args):
"""Given a swatch name and a parent theme, creates a custom theme."""
if requests is None:
print('To use the install_theme command, you need to install the '
'"requests" package.')
return
- parser = OptionParser(usage="nikola %s [options]" % self.name)
- parser.add_option("-n", "--name", dest="name",
- help="New theme name (default: custom)",
- default='custom')
- parser.add_option("-s", "--swatch", dest="swatch",
- help="Name of the swatch from bootswatch.com "
- "(default: slate)", default='slate')
- parser.add_option("-p", "--parent", dest="parent",
- help="Parent theme name (default: site)",
- default='site')
- (options, args) = parser.parse_args(list(args))
- name = options.name
- swatch = options.swatch
- parent = options.parent
+ name = options['name']
+ swatch = options['swatch']
+ parent = options['parent']
- print("Creating '%s' theme from '%s' and '%s'" % (
- name, swatch, parent))
+ print("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch,
+ parent))
try:
os.makedirs(os.path.join('themes', name, 'assets', 'css'))
except:
pass
for fname in ('bootstrap.min.css', 'bootstrap.css'):
- url = 'http://bootswatch.com/%s/%s' % (swatch, fname)
+ url = '/'.join(('http://bootswatch.com', swatch, fname))
print("Downloading: ", url)
data = requests.get(url).text
with open(os.path.join('themes', name, 'assets', 'css', fname),
@@ -77,5 +92,5 @@ class CommandBootswatchTheme(Command):
with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
output.write(parent)
- print('Theme created. Change the THEME setting to "%s" to use it.' %
- name)
+ print('Theme created. Change the THEME setting to "{0}" to use '
+ 'it.'.format(name))
diff --git a/nikola/plugins/command_build.plugin b/nikola/plugins/command_build.plugin
deleted file mode 100644
index 7d029a7..0000000
--- a/nikola/plugins/command_build.plugin
+++ /dev/null
@@ -1,10 +0,0 @@
-[Core]
-Name = build
-Module = command_build
-
-[Documentation]
-Author = Roberto Alsina
-Version = 0.1
-Website = http://nikola.ralsina.com.ar
-Description = Build the site.
-
diff --git a/nikola/plugins/command_build.py b/nikola/plugins/command_build.py
deleted file mode 100644
index 8a1de5f..0000000
--- a/nikola/plugins/command_build.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (c) 2012 Roberto Alsina y otros.
-
-# 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 unicode_literals
-import os
-import tempfile
-
-from nikola.plugin_categories import Command
-
-
-class CommandBuild(Command):
- """Build the site."""
-
- name = "build"
-
- def run(self, *args):
- """Build the site using doit."""
-
- # FIXME: this is crap, do it right
- with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as self.dodo:
- self.dodo.write(b'''
-import sys
-sys.path.insert(0, '.')
-from doit.reporter import ExecutedOnlyReporter
-DOIT_CONFIG = {
- 'reporter': ExecutedOnlyReporter,
- 'default_tasks': ['render_site'],
-}
-from nikola import Nikola
-import conf
-SITE = Nikola(**conf.__dict__)
-
-
-def task_render_site():
- return SITE.gen_tasks()
- ''')
- self.dodo.flush()
- first = args[0] if args else None
- if first in ('auto', 'clean', 'forget', 'ignore', 'list', 'run'):
- cmd = first
- args = args[1:]
- else:
- cmd = 'run'
- os.system('doit %s -f %s -d . %s' % (cmd, self.dodo.name,
- ''.join(args)))
- os.unlink(self.dodo.name)
diff --git a/nikola/plugins/command_check.py b/nikola/plugins/command_check.py
index ae19c41..a396f63 100644
--- a/nikola/plugins/command_check.py
+++ b/nikola/plugins/command_check.py
@@ -23,9 +23,7 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-from optparse import OptionParser
import os
-import sys
try:
from urllib import unquote
from urlparse import urlparse
@@ -42,25 +40,48 @@ class CommandCheck(Command):
name = "check"
- def run(self, *args):
+ doc_usage = "-l [--find-sources] | -f"
+ doc_purpose = "Check links and files in the generated site."
+ cmd_options = [
+ {
+ 'name': 'links',
+ 'short': 'l',
+ 'long': 'check-links',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Check for dangling links',
+ },
+ {
+ 'name': 'files',
+ 'short': 'f',
+ 'long': 'check-files',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Check for unknown files',
+ },
+ {
+ 'name': 'find_sources',
+ 'long': 'find-sources',
+ 'type': bool,
+ 'default': False,
+ 'help': 'List possible source files for files with broken links.',
+ },
+ ]
+
+ def _execute(self, options, args):
"""Check the generated site."""
- parser = OptionParser(usage="nikola %s [options]" % self.name)
- parser.add_option('-l', '--check-links', dest='links',
- action='store_true',
- help='Check for dangling links.')
- parser.add_option('-f', '--check-files', dest='files',
- action='store_true', help='Check for unknown files.')
-
- (options, args) = parser.parse_args(list(args))
- if options.links:
- scan_links()
- if options.files:
+ if not options['links'] and not options['files']:
+ print(self.help())
+ return False
+ if options['links']:
+ scan_links(options['find_sources'])
+ if options['files']:
scan_files()
existing_targets = set([])
-def analize(task):
+def analize(task, find_sources=False):
try:
filename = task.split(":")[-1]
d = lxml.html.fromstring(open(filename).read())
@@ -79,26 +100,26 @@ def analize(task):
if os.path.exists(target_filename):
existing_targets.add(target_filename)
else:
- print("In %s broken link: " % filename, target)
- if '--find-sources' in sys.argv:
+ print("Broken link in {0}: ".format(filename), target)
+ if find_sources:
print("Possible sources:")
- print(os.popen(
- 'nikola build list --deps %s' % task, 'r').read())
+ print(os.popen('nikola list --deps ' + task,
+ 'r').read())
print("===============================\n")
except Exception as exc:
print("Error with:", filename, exc)
-def scan_links():
+def scan_links(find_sources=False):
print("Checking Links:\n===============\n")
- for task in os.popen('nikola build list --all', 'r').readlines():
+ for task in os.popen('nikola list --all', 'r').readlines():
task = task.strip()
if task.split(':')[0] in ('render_tags', 'render_archive',
'render_galleries', 'render_indexes',
'render_pages',
'render_site') and '.html' in task:
- analize(task)
+ analize(task, find_sources)
def scan_files():
@@ -106,7 +127,7 @@ def scan_files():
task_fnames = set([])
real_fnames = set([])
# First check that all targets are generated in the right places
- for task in os.popen('nikola build list --all', 'r').readlines():
+ for task in os.popen('nikola list --all', 'r').readlines():
task = task.strip()
if 'output' in task and ':' in task:
fname = task.split(':')[-1]
diff --git a/nikola/plugins/command_console.py b/nikola/plugins/command_console.py
index 7a009fd..4af759f 100644
--- a/nikola/plugins/command_console.py
+++ b/nikola/plugins/command_console.py
@@ -22,6 +22,8 @@
# 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, unicode_literals
+
import os
from nikola.plugin_categories import Command
@@ -31,5 +33,31 @@ class Deploy(Command):
"""Start debugging console."""
name = "console"
- def run(self, *args):
- os.system('python -i -c "from nikola.console import *"')
+ def _execute(self, options, args):
+ """Start the console."""
+ from nikola import Nikola
+ try:
+ import conf
+ SITE = Nikola(**conf.__dict__)
+ SITE.scan_posts()
+ print("You can now access your configuration as conf and your "
+ "site engine as SITE.")
+ except ImportError:
+ print("No configuration found.")
+ import code
+ try:
+ import readline
+ except ImportError:
+ pass
+ else:
+ import rlcompleter
+ readline.set_completer(rlcompleter.Completer(globals()).complete)
+ readline.parse_and_bind("tab:complete")
+
+ pythonrc = os.environ.get("PYTHONSTARTUP")
+ if pythonrc and os.path.isfile(pythonrc):
+ try:
+ execfile(pythonrc) # NOQA
+ except NameError:
+ pass
+ code.interact(local=globals())
diff --git a/nikola/plugins/command_deploy.py b/nikola/plugins/command_deploy.py
index 48d6e91..ffa86ab 100644
--- a/nikola/plugins/command_deploy.py
+++ b/nikola/plugins/command_deploy.py
@@ -23,7 +23,6 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-from optparse import OptionParser
import os
from nikola.plugin_categories import Command
@@ -33,9 +32,10 @@ class Deploy(Command):
"""Deploy site. """
name = "deploy"
- def run(self, *args):
- parser = OptionParser(usage="nikola %s [options]" % self.name)
- (options, args) = parser.parse_args(list(args))
+ doc_usage = ""
+ doc_purpose = "Deploy the site."
+
+ def _execute(self, command, args):
for command in self.site.config['DEPLOY_COMMANDS']:
print("==>", command)
os.system(command)
diff --git a/nikola/plugins/command_import_blogger.py b/nikola/plugins/command_import_blogger.py
index aea210a..35a702e 100644
--- a/nikola/plugins/command_import_blogger.py
+++ b/nikola/plugins/command_import_blogger.py
@@ -27,7 +27,6 @@ import codecs
import csv
import datetime
import os
-from optparse import OptionParser
import time
try:
@@ -52,9 +51,63 @@ class CommandImportBlogger(Command):
"""Import a blogger dump."""
name = "import_blogger"
+ needs_config = False
+ doc_usage = "[options] blogger_export_file"
+ doc_purpose = "Import a blogger dump."
+ cmd_options = [
+ {
+ 'name': 'output_folder',
+ 'long': 'output-folder',
+ 'short': 'o',
+ 'default': 'new_site',
+ 'help': 'Location to write imported content.'
+ },
+ {
+ 'name': 'exclude_drafts',
+ 'long': 'no-drafts',
+ 'short': 'd',
+ 'default': False,
+ 'type': bool,
+ 'help': "Don't import drafts",
+ },
+ ]
+
+ def _execute(self, options, args):
+ """Import a Wordpress blog from an export file into a Nikola site."""
+
+ # Parse the data
+ if feedparser is None:
+ print('To use the import_blogger command,'
+ ' you have to install the "feedparser" package.')
+ return
+
+ if not args:
+ print(self.help())
+ return
+
+ options['filename'] = args[0]
+ self.blogger_export_file = options['filename']
+ self.output_folder = options['output_folder']
+ self.import_into_existing_site = False
+ self.exclude_drafts = options['exclude_drafts']
+ self.url_map = {}
+ channel = self.get_channel_from_file(self.blogger_export_file)
+ self.context = self.populate_context(channel)
+ conf_template = self.generate_base_site()
+ self.context['REDIRECTIONS'] = self.configure_redirections(
+ self.url_map)
+
+ self.import_posts(channel)
+ self.write_urlmap_csv(
+ os.path.join(self.output_folder, 'url_map.csv'), self.url_map)
+
+ self.write_configuration(self.get_configuration_output_path(
+ ), conf_template.render(**self.context))
@classmethod
def get_channel_from_file(cls, filename):
+ if not os.path.isfile(filename):
+ raise Exception("Missing file: %s" % filename)
return feedparser.parse(filename)
@staticmethod
@@ -65,7 +118,7 @@ class CommandImportBlogger(Command):
src = (urlparse(k).path + 'index.html')[1:]
dst = (urlparse(v).path)
if src == 'index.html':
- print("Can't do a redirect for: %r" % k)
+ print("Can't do a redirect for: {0!r}".format(k))
else:
redirections.append((src, dst))
@@ -73,11 +126,11 @@ class CommandImportBlogger(Command):
def generate_base_site(self):
if not os.path.exists(self.output_folder):
- os.system('nikola init --empty %s' % (self.output_folder, ))
+ os.system('nikola init --empty ' + self.output_folder)
else:
self.import_into_existing_site = True
- print('The folder %s already exists - assuming that this is a '
- 'already existing nikola site.' % self.output_folder)
+ print('The folder {0} already exists - assuming that this is a '
+ 'already existing nikola site.'.format(self.output_folder))
conf_template = Template(filename=os.path.join(
os.path.dirname(utils.__file__), 'conf.py.in'))
@@ -92,7 +145,7 @@ class CommandImportBlogger(Command):
context['BLOG_TITLE'] = channel.feed.title
context['BLOG_DESCRIPTION'] = '' # Missing in the dump
- context['BLOG_URL'] = channel.feed.link.rstrip('/')
+ context['SITE_URL'] = channel.feed.link.rstrip('/')
context['BLOG_EMAIL'] = channel.feed.author_detail.email
context['BLOG_AUTHOR'] = channel.feed.author_detail.name
context['POST_PAGES'] = '''(
@@ -124,12 +177,8 @@ class CommandImportBlogger(Command):
@staticmethod
def write_metadata(filename, title, slug, post_date, description, tags):
with codecs.open(filename, "w+", "utf8") as fd:
- fd.write('%s\n' % title)
- fd.write('%s\n' % slug)
- fd.write('%s\n' % post_date)
- fd.write('%s\n' % ','.join(tags))
- fd.write('\n')
- fd.write('%s\n' % description)
+ fd.write('\n'.join((title, slug, post_date, ','.join(tags), '',
+ description)))
def import_item(self, item, out_folder=None):
"""Takes an item from the feed and creates a post file."""
@@ -145,8 +194,8 @@ class CommandImportBlogger(Command):
# blogger supports empty titles, which Nikola doesn't
if not title:
- print("Warning: Empty title in post with URL %s. Using NO_TITLE "
- "as placeholder, please fix." % link)
+ print("Warning: Empty title in post with URL {0}. Using NO_TITLE "
+ "as placeholder, please fix.".format(link))
title = "NO_TITLE"
if link_path.lower().endswith('.html'):
@@ -179,11 +228,11 @@ class CommandImportBlogger(Command):
else:
is_draft = False
- self.url_map[link] = self.context['BLOG_URL'] + '/' + \
+ self.url_map[link] = self.context['SITE_URL'] + '/' + \
out_folder + '/' + slug + '.html'
if is_draft and self.exclude_drafts:
- print('Draft "%s" will not be imported.' % (title, ))
+ print('Draft "{0}" will not be imported.'.format(title))
elif content.strip():
# If no content is found, no files are written.
content = self.transform_content(content)
@@ -195,8 +244,8 @@ class CommandImportBlogger(Command):
os.path.join(self.output_folder, out_folder, slug + '.html'),
content)
else:
- print('Not going to import "%s" because it seems to contain'
- ' no content.' % (title, ))
+ print('Not going to import "{0}" because it seems to contain'
+ ' no content.'.format(title))
def process_item(self, item):
post_type = item.tags[0].term
@@ -235,10 +284,10 @@ class CommandImportBlogger(Command):
if not self.import_into_existing_site:
filename = 'conf.py'
else:
- filename = 'conf.py.wordpress_import-%s' % datetime.datetime.now(
- ).strftime('%Y%m%d_%H%M%s')
+ filename = 'conf.py.wordpress_import-{0}'.format(
+ datetime.datetime.now().strftime('%Y%m%d_%H%M%s'))
config_output_path = os.path.join(self.output_folder, filename)
- print('Configuration will be written to: %s' % config_output_path)
+ print('Configuration will be written to: ' + config_output_path)
return config_output_path
@@ -247,54 +296,6 @@ class CommandImportBlogger(Command):
with codecs.open(filename, 'w+', 'utf8') as fd:
fd.write(rendered_template)
- def run(self, *arguments):
- """Import a Wordpress blog from an export file into a Nikola site."""
- # Parse the data
- if feedparser is None:
- print('To use the import_blogger command,'
- ' you have to install the "feedparser" package.')
- return
-
- parser = OptionParser(
- usage="nikola %s [options] blogger_export_file" % self.name)
- parser.add_option('-f', '--filename', dest='filename',
- help='Blogger export file from which the import is '
- 'made.')
- parser.add_option('-o', '--output-folder', dest='output_folder',
- default='new_site',
- help='The location into which the imported content '
- 'will be written')
- parser.add_option('-d', '--no-drafts', dest='exclude_drafts',
- default=False, action="store_true", help='Do not '
- 'import drafts.')
-
- (options, args) = parser.parse_args(list(arguments))
-
- if not options.filename and args:
- options.filename = args[0]
-
- if not options.filename:
- parser.print_usage()
- return
-
- self.blogger_export_file = options.filename
- self.output_folder = options.output_folder
- self.import_into_existing_site = False
- self.exclude_drafts = options.exclude_drafts
- self.url_map = {}
- channel = self.get_channel_from_file(self.blogger_export_file)
- self.context = self.populate_context(channel)
- conf_template = self.generate_base_site()
- self.context['REDIRECTIONS'] = self.configure_redirections(
- self.url_map)
-
- self.import_posts(channel)
- self.write_urlmap_csv(
- os.path.join(self.output_folder, 'url_map.csv'), self.url_map)
-
- self.write_configuration(self.get_configuration_output_path(
- ), conf_template.render(**self.context))
-
def replacer(dst):
return links.get(dst, dst)
diff --git a/nikola/plugins/command_import_wordpress.py b/nikola/plugins/command_import_wordpress.py
index 07028d8..e7ecca0 100644
--- a/nikola/plugins/command_import_wordpress.py
+++ b/nikola/plugins/command_import_wordpress.py
@@ -28,7 +28,6 @@ import csv
import datetime
import os
import re
-from optparse import OptionParser
try:
from urlparse import urlparse
@@ -53,9 +52,104 @@ class CommandImportWordpress(Command):
"""Import a wordpress dump."""
name = "import_wordpress"
+ needs_config = False
+ doc_usage = "[options] wordpress_export_file"
+ doc_purpose = "Import a wordpress dump."
+ cmd_options = [
+ {
+ 'name': 'output_folder',
+ 'long': 'output-folder',
+ 'short': 'o',
+ 'default': 'new_site',
+ 'help': 'Location to write imported content.'
+ },
+ {
+ 'name': 'exclude_drafts',
+ 'long': 'no-drafts',
+ 'short': 'd',
+ 'default': False,
+ 'type': bool,
+ 'help': "Don't import drafts",
+ },
+ {
+ 'name': 'squash_newlines',
+ 'long': 'squash-newlines',
+ 'default': False,
+ 'type': bool,
+ 'help': "Shorten multiple newlines in a row to only two newlines",
+ },
+ {
+ 'name': 'no_downloads',
+ 'long': 'no-downloads',
+ 'default': False,
+ 'type': bool,
+ 'help': "Do not try to download files for the import",
+ },
+ ]
+
+ def _execute(self, options={}, args=[]):
+ """Import a Wordpress blog from an export file into a Nikola site."""
+ # Parse the data
+ print(options, args)
+ if requests is None:
+ print('To use the import_wordpress command,'
+ ' you have to install the "requests" package.')
+ return
- @staticmethod
- def read_xml_file(filename):
+ if not args:
+ print(self.help())
+ return
+
+ options['filename'] = args[0]
+
+ if len(args) > 1:
+ options['output_folder'] = args[1]
+
+ self.wordpress_export_file = options['filename']
+ self.squash_newlines = options.get('squash_newlines', False)
+ self.no_downloads = options.get('no_downloads', False)
+ self.output_folder = options.get('output_folder', 'new_site')
+ self.import_into_existing_site = False
+ self.exclude_drafts = options.get('exclude_drafts', False)
+ self.url_map = {}
+ channel = self.get_channel_from_file(self.wordpress_export_file)
+ self.context = self.populate_context(channel)
+ conf_template = self.generate_base_site()
+
+ self.import_posts(channel)
+
+ self.context['REDIRECTIONS'] = self.configure_redirections(
+ self.url_map)
+ self.write_urlmap_csv(
+ os.path.join(self.output_folder, 'url_map.csv'), self.url_map)
+ rendered_template = conf_template.render(**self.context)
+ rendered_template = re.sub('# REDIRECTIONS = ', 'REDIRECTIONS = ',
+ rendered_template)
+ self.write_configuration(self.get_configuration_output_path(),
+ rendered_template)
+
+ @classmethod
+ def _glue_xml_lines(cls, xml):
+ new_xml = xml[0]
+ previous_line_ended_in_newline = new_xml.endswith(b'\n')
+ previous_line_was_indentet = False
+ for line in xml[1:]:
+ if (re.match(b'^[ \t]+', line) and previous_line_ended_in_newline):
+ new_xml = b''.join((new_xml, line))
+ previous_line_was_indentet = True
+ elif previous_line_was_indentet:
+ new_xml = b''.join((new_xml, line))
+ previous_line_was_indentet = False
+ else:
+ new_xml = b'\n'.join((new_xml, line))
+ previous_line_was_indentet = False
+
+ previous_line_ended_in_newline = line.endswith(b'\n')
+
+ return new_xml
+
+ @classmethod
+ def read_xml_file(cls, filename):
xml = []
with open(filename, 'rb') as fd:
@@ -64,9 +158,8 @@ class CommandImportWordpress(Command):
if b'<atom:link rel=' in line:
continue
xml.append(line)
- xml = b'\n'.join(xml)
- return xml
+ return cls._glue_xml_lines(xml)
@classmethod
def get_channel_from_file(cls, filename):
@@ -82,7 +175,7 @@ class CommandImportWordpress(Command):
src = (urlparse(k).path + 'index.html')[1:]
dst = (urlparse(v).path)
if src == 'index.html':
- print("Can't do a redirect for: %r" % k)
+ print("Can't do a redirect for: {0!r}".format(k))
else:
redirections.append((src, dst))
@@ -90,11 +183,11 @@ class CommandImportWordpress(Command):
def generate_base_site(self):
if not os.path.exists(self.output_folder):
- os.system('nikola init --empty %s' % (self.output_folder, ))
+ os.system('nikola init ' + self.output_folder)
else:
self.import_into_existing_site = True
- print('The folder %s already exists - assuming that this is a '
- 'already existing nikola site.' % self.output_folder)
+ print('The folder {0} already exists - assuming that this is a '
+ 'already existing nikola site.'.format(self.output_folder))
conf_template = Template(filename=os.path.join(
os.path.dirname(utils.__file__), 'conf.py.in'))
@@ -111,15 +204,16 @@ class CommandImportWordpress(Command):
'PUT TITLE HERE')
context['BLOG_DESCRIPTION'] = get_text_tag(
channel, 'description', 'PUT DESCRIPTION HERE')
- context['BLOG_URL'] = get_text_tag(channel, 'link', '#')
- author = channel.find('{%s}author' % wordpress_namespace)
+ context['SITE_URL'] = get_text_tag(channel, 'link', '#')
+ context['BASE_URL'] = get_text_tag(channel, 'link', '#')
+ author = channel.find('{{{0}}}author'.format(wordpress_namespace))
context['BLOG_EMAIL'] = get_text_tag(
author,
- '{%s}author_email' % wordpress_namespace,
+ '{{{0}}}author_email'.format(wordpress_namespace),
"joe@example.com")
context['BLOG_AUTHOR'] = get_text_tag(
author,
- '{%s}author_display_name' % wordpress_namespace,
+ '{{{0}}}author_display_name'.format(wordpress_namespace),
"Joe Example")
context['POST_PAGES'] = '''(
("posts/*.wp", "posts", "post.tmpl", True),
@@ -134,25 +228,29 @@ class CommandImportWordpress(Command):
return context
- @staticmethod
- def download_url_content_to_file(url, dst_path):
+ def download_url_content_to_file(self, url, dst_path):
+ if self.no_downloads:
+ return
+
try:
with open(dst_path, 'wb+') as fd:
fd.write(requests.get(url).content)
except requests.exceptions.ConnectionError as err:
- print("Downloading %s to %s failed: %s" % (url, dst_path, err))
+ print("Downloading {0} to {1} failed: {2}".format(url, dst_path,
+ err))
def import_attachment(self, item, wordpress_namespace):
url = get_text_tag(
- item, '{%s}attachment_url' % wordpress_namespace, 'foo')
- link = get_text_tag(item, '{%s}link' % wordpress_namespace, 'foo')
+ item, '{{{0}}}attachment_url'.format(wordpress_namespace), 'foo')
+ link = get_text_tag(item, '{{{0}}}link'.format(wordpress_namespace),
+ 'foo')
path = urlparse(url).path
dst_path = os.path.join(*([self.output_folder, 'files']
+ list(path.split('/'))))
dst_dir = os.path.dirname(dst_path)
if not os.path.isdir(dst_dir):
os.makedirs(dst_dir)
- print("Downloading %s => %s" % (url, dst_path))
+ print("Downloading {0} => {1}".format(url, dst_path))
self.download_url_content_to_file(url, dst_path)
dst_url = '/'.join(dst_path.split(os.sep)[2:])
links[link] = '/' + dst_url
@@ -173,10 +271,18 @@ class CommandImportWordpress(Command):
return new_caption
- @classmethod
- def transform_content(cls, content):
- new_content = cls.transform_sourcecode(content)
- return cls.transform_caption(new_content)
+ def transform_multiple_newlines(self, content):
+ """Replaces multiple newlines with only two."""
+ if self.squash_newlines:
+ return re.sub(r'\n{3,}', r'\n\n', content)
+ else:
+ return content
+
+ def transform_content(self, content):
+ new_content = self.transform_sourcecode(content)
+ new_content = self.transform_caption(new_content)
+ new_content = self.transform_multiple_newlines(new_content)
+ return new_content
@classmethod
def write_content(cls, filename, content):
@@ -188,13 +294,16 @@ class CommandImportWordpress(Command):
@staticmethod
def write_metadata(filename, title, slug, post_date, description, tags):
+ if not description:
+ description = ""
+
with codecs.open(filename, "w+", "utf8") as fd:
- fd.write('%s\n' % title)
- fd.write('%s\n' % slug)
- fd.write('%s\n' % post_date)
- fd.write('%s\n' % ','.join(tags))
+ fd.write('{0}\n'.format(title))
+ fd.write('{0}\n'.format(slug))
+ fd.write('{0}\n'.format(post_date))
+ fd.write('{0}\n'.format(','.join(tags)))
fd.write('\n')
- fd.write('%s\n' % description)
+ fd.write('{0}\n'.format(description))
def import_item(self, item, wordpress_namespace, out_folder=None):
"""Takes an item from the feed and creates a post file."""
@@ -208,19 +317,19 @@ class CommandImportWordpress(Command):
slug = utils.slugify(urlparse(link).path)
if not slug: # it happens if the post has no "nice" URL
slug = get_text_tag(
- item, '{%s}post_name' % wordpress_namespace, None)
+ item, '{{{0}}}post_name'.format(wordpress_namespace), None)
if not slug: # it *may* happen
slug = get_text_tag(
- item, '{%s}post_id' % wordpress_namespace, None)
+ item, '{{{0}}}post_id'.format(wordpress_namespace), None)
if not slug: # should never happen
print("Error converting post:", title)
return
description = get_text_tag(item, 'description', '')
post_date = get_text_tag(
- item, '{%s}post_date' % wordpress_namespace, None)
+ item, '{{{0}}}post_date'.format(wordpress_namespace), None)
status = get_text_tag(
- item, '{%s}status' % wordpress_namespace, 'publish')
+ item, '{{{0}}}status'.format(wordpress_namespace), 'publish')
content = get_text_tag(
item, '{http://purl.org/rss/1.0/modules/content/}encoded', '')
@@ -237,13 +346,13 @@ class CommandImportWordpress(Command):
continue
tags.append(text)
- self.url_map[link] = self.context['BLOG_URL'] + '/' + \
- out_folder + '/' + slug + '.html'
-
if is_draft and self.exclude_drafts:
- print('Draft "%s" will not be imported.' % (title, ))
+ print('Draft "{0}" will not be imported.'.format(title))
elif content.strip():
# If no content is found, no files are written.
+ self.url_map[link] = self.context['SITE_URL'] + '/' + \
+ out_folder + '/' + slug + '.html'
+
content = self.transform_content(content)
self.write_metadata(os.path.join(self.output_folder, out_folder,
@@ -253,15 +362,15 @@ class CommandImportWordpress(Command):
os.path.join(self.output_folder, out_folder, slug + '.wp'),
content)
else:
- print('Not going to import "%s" because it seems to contain'
- ' no content.' % (title, ))
+ print('Not going to import "{0}" because it seems to contain'
+ ' no content.'.format(title))
def process_item(self, item):
# The namespace usually is something like:
# http://wordpress.org/export/1.2/
wordpress_namespace = item.nsmap['wp']
post_type = get_text_tag(
- item, '{%s}post_type' % wordpress_namespace, 'post')
+ item, '{{{0}}}post_type'.format(wordpress_namespace), 'post')
if post_type == 'attachment':
self.import_attachment(item, wordpress_namespace)
@@ -285,10 +394,10 @@ class CommandImportWordpress(Command):
if not self.import_into_existing_site:
filename = 'conf.py'
else:
- filename = 'conf.py.wordpress_import-%s' % datetime.datetime.now(
- ).strftime('%Y%m%d_%H%M%s')
+ filename = 'conf.py.wordpress_import-{0}'.format(
+ datetime.datetime.now().strftime('%Y%m%d_%H%M%s'))
config_output_path = os.path.join(self.output_folder, filename)
- print('Configuration will be written to: %s' % config_output_path)
+ print('Configuration will be written to:', config_output_path)
return config_output_path
@@ -297,53 +406,6 @@ class CommandImportWordpress(Command):
with codecs.open(filename, 'w+', 'utf8') as fd:
fd.write(rendered_template)
- def run(self, *arguments):
- """Import a Wordpress blog from an export file into a Nikola site."""
- # Parse the data
- if requests is None:
- print('To use the import_wordpress command,'
- ' you have to install the "requests" package.')
- return
-
- parser = OptionParser(usage="nikola %s [options] "
- "wordpress_export_file" % self.name)
- parser.add_option('-f', '--filename', dest='filename',
- help='WordPress export file from which the import '
- 'made.')
- parser.add_option('-o', '--output-folder', dest='output_folder',
- default='new_site', help='The location into which '
- 'the imported content will be written')
- parser.add_option('-d', '--no-drafts', dest='exclude_drafts',
- default=False, action="store_true", help='Do not '
- 'import drafts.')
-
- (options, args) = parser.parse_args(list(arguments))
-
- if not options.filename and args:
- options.filename = args[0]
-
- if not options.filename:
- parser.print_usage()
- return
-
- self.wordpress_export_file = options.filename
- self.output_folder = options.output_folder
- self.import_into_existing_site = False
- self.exclude_drafts = options.exclude_drafts
- self.url_map = {}
- channel = self.get_channel_from_file(self.wordpress_export_file)
- self.context = self.populate_context(channel)
- conf_template = self.generate_base_site()
- self.context['REDIRECTIONS'] = self.configure_redirections(
- self.url_map)
-
- self.import_posts(channel)
- self.write_urlmap_csv(
- os.path.join(self.output_folder, 'url_map.csv'), self.url_map)
-
- self.write_configuration(self.get_configuration_output_path(
- ), conf_template.render(**self.context))
-
def replacer(dst):
return links.get(dst, dst)
diff --git a/nikola/plugins/command_init.py b/nikola/plugins/command_init.py
index e9bd001..bc36266 100644
--- a/nikola/plugins/command_init.py
+++ b/nikola/plugins/command_init.py
@@ -23,7 +23,6 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-from optparse import OptionParser, OptionGroup
import os
import shutil
import codecs
@@ -39,16 +38,23 @@ class CommandInit(Command):
name = "init"
- usage = """Usage: nikola init folder [options].
-
-That will create a sample site in the specified folder.
-The destination folder must not exist.
-"""
+ doc_usage = "[--demo] folder"
+ needs_config = False
+ doc_purpose = """Create a Nikola site in the specified folder."""
+ cmd_options = [
+ {
+ 'name': 'demo',
+ 'long': 'demo',
+ 'default': False,
+ 'type': bool,
+ 'help': "Create a site filled with example data.",
+ }
+ ]
SAMPLE_CONF = {
'BLOG_AUTHOR': "Your Name",
'BLOG_TITLE': "Demo Site",
- 'BLOG_URL': "http://nikola.ralsina.com.ar",
+ 'SITE_URL': "http://nikola.ralsina.com.ar",
'BLOG_EMAIL': "joe@demo.site",
'BLOG_DESCRIPTION': "This is a demo site for Nikola.",
'DEFAULT_LANG': "en",
@@ -67,7 +73,7 @@ The destination folder must not exist.
"wiki": ('.wiki',),
"ipynb": ('.ipynb',),
"html": ('.html', '.htm')
- }""",
+}""",
'REDIRECTIONS': '[]',
}
@@ -95,32 +101,22 @@ The destination folder must not exist.
def get_path_to_nikola_modules():
return os.path.dirname(nikola.__file__)
- def run(self, *args):
+ def _execute(self, options={}, args=None):
"""Create a new site."""
- parser = OptionParser(usage=self.usage)
- group = OptionGroup(parser, "Site Options")
- group.add_option(
- "--empty", action="store_true", dest='empty', default=True,
- help="Create an empty site with only a config.")
- group.add_option("--demo", action="store_false", dest='empty',
- help="Create a site filled with example data.")
- parser.add_option_group(group)
- (options, args) = parser.parse_args(list(args))
-
if not args:
print("Usage: nikola init folder [options]")
- return
+ return False
target = args[0]
if target is None:
print(self.usage)
else:
- if options.empty:
+ if not options or not options.get('demo'):
self.create_empty_site(target)
- print('Created empty site at %s.' % target)
+ print('Created empty site at {0}.'.format(target))
else:
self.copy_sample_site(target)
- print("A new site with example data has been created at %s."
- % target)
+ print("A new site with example data has been created at "
+ "{0}.".format(target))
print("See README.txt in that folder for more information.")
self.create_configuration(target)
diff --git a/nikola/plugins/command_install_theme.py b/nikola/plugins/command_install_theme.py
index 0dc000b..04a2cce 100644
--- a/nikola/plugins/command_install_theme.py
+++ b/nikola/plugins/command_install_theme.py
@@ -23,7 +23,6 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-from optparse import OptionParser
import os
import json
from io import BytesIO
@@ -41,31 +40,39 @@ class CommandInstallTheme(Command):
"""Start test server."""
name = "install_theme"
+ doc_usage = "[[-u] theme_name] | [[-u] -l]"
+ doc_purpose = "Install theme into current site."
+ cmd_options = [
+ {
+ 'name': 'list',
+ 'short': 'l',
+ 'long': 'list',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Show list of available themes.'
+ },
+ {
+ 'name': 'url',
+ 'short': 'u',
+ 'long': 'url',
+ 'type': str,
+ 'help': "URL for the theme repository (default: "
+ "http://nikola.ralsina.com.ar/themes/index.json)",
+ 'default': 'http://nikola.ralsina.com.ar/themes/index.json'
+ },
+ ]
- def run(self, *args):
+ def _execute(self, options, args):
"""Install theme into current site."""
- if requests is None:
- print('To use the install_theme command, you need to install the '
- '"requests" package.')
- return
- parser = OptionParser(usage="nikola %s [options]" % self.name)
- parser.add_option("-l", "--list", dest="list", action="store_true",
- help="Show list of available themes.")
- parser.add_option("-n", "--name", dest="name", help="Theme name",
- default=None)
- parser.add_option("-u", "--url", dest="url", help="URL for the theme "
- "repository" "(default: "
- "http://nikola.ralsina.com.ar/themes/index.json)",
- default='http://nikola.ralsina.com.ar/themes/'
- 'index.json')
- (options, args) = parser.parse_args(list(args))
-
- listing = options.list
- name = options.name
- url = options.url
+ listing = options['list']
+ url = options['url']
+ if args:
+ name = args[0]
+ else:
+ name = None
if name is None and not listing:
- print("This command needs either the -n or the -l option.")
+ print("This command needs either a theme name or the -l option.")
return False
data = requests.get(url).text
data = json.loads(data)
@@ -84,11 +91,11 @@ class CommandInstallTheme(Command):
os.makedirs("themes")
except:
raise OSError("mkdir 'theme' error!")
- print('Downloading: %s' % data[name])
+ print('Downloading: ' + data[name])
zip_file = BytesIO()
zip_file.write(requests.get(data[name]).content)
- print('Extracting: %s into themes' % name)
+ print('Extracting: {0} into themes'.format(name))
utils.extract_all(zip_file)
else:
- print("Can't find theme %s" % name)
+ print("Can't find theme " + name)
return False
diff --git a/nikola/plugins/command_new_post.py b/nikola/plugins/command_new_post.py
index 9b6397b..a823da3 100644
--- a/nikola/plugins/command_new_post.py
+++ b/nikola/plugins/command_new_post.py
@@ -25,7 +25,6 @@
from __future__ import unicode_literals, print_function
import codecs
import datetime
-from optparse import OptionParser
import os
import sys
@@ -51,9 +50,9 @@ def filter_post_pages(compiler, is_post, post_compilers, post_pages):
if not filtered:
type_name = "post" if is_post else "page"
raise Exception("Can't find a way, using your configuration, to create"
- "a %s in format %s. You may want to tweak "
- "post_compilers or post_pages in conf.py" %
- (type_name, compiler))
+ "a {0} in format {1}. You may want to tweak "
+ "post_compilers or post_pages in conf.py".format(
+ type_name, compiler))
return filtered[0]
@@ -61,42 +60,88 @@ class CommandNewPost(Command):
"""Create a new post."""
name = "new_post"
-
- def run(self, *args):
- """Create a new post."""
+ doc_usage = "[options] [path]"
+ doc_purpose = "Create a new blog post or site page."
+ cmd_options = [
+ {
+ 'name': 'is_page',
+ 'short': 'p',
+ 'long': 'page',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Create a page instead of a blog post.'
+ },
+ {
+ 'name': 'title',
+ 'short': 't',
+ 'long': 'title',
+ 'type': str,
+ 'default': '',
+ 'help': 'Title for the page/post.'
+ },
+ {
+ 'name': 'tags',
+ 'long': 'tags',
+ 'type': str,
+ 'default': '',
+ 'help': 'Comma-separated tags for the page/post.'
+ },
+ {
+ 'name': 'onefile',
+ 'short': '1',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Create post with embedded metadata (single file format)'
+ },
+ {
+ 'name': 'twofile',
+ 'short': '2',
+ 'type': bool,
+ 'default': False,
+ 'help': 'Create post with separate metadata (two file format)'
+ },
+ {
+ 'name': 'post_format',
+ 'short': 'f',
+ 'long': 'format',
+ 'type': str,
+ 'default': 'rest',
+ 'help': 'Markup format for post, one of rest, markdown, wiki, '
+ 'bbcode, html, textile, txt2tags',
+ }
+ ]
+
+ def _execute(self, options, args):
+ """Create a new post or page."""
compiler_names = [p.name for p in
self.site.plugin_manager.getPluginsOfCategory(
"PageCompiler")]
- parser = OptionParser(usage="nikola %s [options]" % self.name)
- parser.add_option('-p', '--page', dest='is_post', action='store_false',
- default=True, help='Create a page instead of a blog '
- 'post.')
- parser.add_option('-t', '--title', dest='title', help='Title for the '
- 'page/post.', default=None)
- parser.add_option('--tags', dest='tags', help='Comma-separated tags '
- 'for the page/post.', default='')
- parser.add_option('-1', dest='onefile', action='store_true',
- help='Create post with embedded metadata (single '
- 'file format).',
- default=self.site.config.get('ONE_FILE_POSTS', True))
- parser.add_option('-2', dest='onefile', action='store_false',
- help='Create post with separate metadata (two file '
- 'format).',
- default=self.site.config.get('ONE_FILE_POSTS', True))
- parser.add_option('-f', '--format', dest='post_format', default='rest',
- help='Format for post (one of %s)' %
- ','.join(compiler_names))
- (options, args) = parser.parse_args(list(args))
-
- is_post = options.is_post
- title = options.title
- tags = options.tags
- onefile = options.onefile
- post_format = options.post_format
+ if len(args) > 1:
+ print(self.help())
+ return False
+ elif args:
+ path = args[0]
+ else:
+ path = None
+
+ is_page = options.get('is_page', False)
+ is_post = not is_page
+ title = options['title'] or None
+ tags = options['tags']
+ onefile = options['onefile']
+ twofile = options['twofile']
+
+ if twofile:
+ onefile = False
+ if not onefile and not twofile:
+ onefile = self.site.config.get('ONE_FILE_POSTS', True)
+
+ post_format = options['post_format']
+
if post_format not in compiler_names:
- print("ERROR: Unknown post format %s" % post_format)
+ print("ERROR: Unknown post format " + post_format)
return
compiler_plugin = self.site.plugin_manager.getPluginByName(
post_format, "PageCompiler").plugin_object
@@ -118,19 +163,29 @@ class CommandNewPost(Command):
if isinstance(title, bytes):
title = title.decode(sys.stdin.encoding)
title = title.strip()
- slug = utils.slugify(title)
+ if not path:
+ slug = utils.slugify(title)
+ else:
+ slug = utils.slugify(os.path.splitext(os.path.basename(path))[0])
date = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
data = [title, slug, date, tags]
output_path = os.path.dirname(entry[0])
meta_path = os.path.join(output_path, slug + ".meta")
pattern = os.path.basename(entry[0])
suffix = pattern[1:]
- txt_path = os.path.join(output_path, slug + suffix)
+ if not path:
+ txt_path = os.path.join(output_path, slug + suffix)
+ else:
+ txt_path = path
if (not onefile and os.path.isfile(meta_path)) or \
os.path.isfile(txt_path):
print("The title already exists!")
exit()
+
+ d_name = os.path.dirname(txt_path)
+ if not os.path.exists(d_name):
+ os.makedirs(d_name)
compiler_plugin.create_post(txt_path, onefile, title, slug, date, tags)
if not onefile: # write metadata file
diff --git a/nikola/plugins/command_serve.py b/nikola/plugins/command_serve.py
index 75e07a9..64efe7d 100644
--- a/nikola/plugins/command_serve.py
+++ b/nikola/plugins/command_serve.py
@@ -23,7 +23,6 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
-from optparse import OptionParser
import os
try:
from BaseHTTPServer import HTTPServer
@@ -39,26 +38,39 @@ class CommandBuild(Command):
"""Start test server."""
name = "serve"
+ doc_usage = "[options]"
+ doc_purpose = "Start the test webserver."
- def run(self, *args):
- """Start test server."""
-
- parser = OptionParser(usage="nikola %s [options]" % self.name)
- parser.add_option("-p", "--port", dest="port", help="Port numer "
- "(default: 8000)", default=8000, type="int")
- parser.add_option("-a", "--address", dest="address", help="Address to "
- "bind (default: 127.0.0.1)", default='127.0.0.1')
- (options, args) = parser.parse_args(list(args))
+ cmd_options = (
+ {
+ 'name': 'port',
+ 'short': 'p',
+ 'long': 'port',
+ 'default': 8000,
+ 'type': int,
+ 'help': 'Port nummber (default: 8000)',
+ },
+ {
+ 'name': 'address',
+ 'short': 'a',
+ 'long': '--address',
+ 'type': str,
+ 'default': '127.0.0.1',
+ 'help': 'Address to bind (default: 127.0.0.1)',
+ },
+ )
+ def _execute(self, options, args):
+ """Start test server."""
out_dir = self.site.config['OUTPUT_FOLDER']
if not os.path.isdir(out_dir):
- print("Error: Missing '%s' folder?" % out_dir)
+ print("Error: Missing '{0}' folder?".format(out_dir))
else:
os.chdir(out_dir)
- httpd = HTTPServer((options.address, options.port),
+ httpd = HTTPServer((options['address'], options['port']),
OurHTTPRequestHandler)
sa = httpd.socket.getsockname()
- print("Serving HTTP on {0[0]} port {0[1]}...".format(sa))
+ print("Serving HTTP on", sa[0], "port", sa[1], "...")
httpd.serve_forever()
diff --git a/nikola/plugins/compile_bbcode.py b/nikola/plugins/compile_bbcode.py
index fd7fe1a..26de727 100644
--- a/nikola/plugins/compile_bbcode.py
+++ b/nikola/plugins/compile_bbcode.py
@@ -68,10 +68,10 @@ class CompileTextile(PageCompiler):
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
fd.write('[note]<!--\n')
- fd.write('.. title: %s\n' % title)
- fd.write('.. slug: %s\n' % slug)
- fd.write('.. date: %s\n' % date)
- fd.write('.. tags: %s\n' % tags)
+ fd.write('.. title: {0}\n'.format(title))
+ fd.write('.. slug: {0}\n'.format(slug))
+ fd.write('.. date: {0}\n'.format(date))
+ fd.write('.. tags: {0}\n'.format(tags))
fd.write('.. link: \n')
fd.write('.. description: \n')
fd.write('-->[/note]\n\n')
diff --git a/nikola/plugins/compile_html.py b/nikola/plugins/compile_html.py
index 850a3e5..6c1c381 100644
--- a/nikola/plugins/compile_html.py
+++ b/nikola/plugins/compile_html.py
@@ -51,10 +51,10 @@ class CompileHtml(PageCompiler):
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
fd.write('<!-- \n')
- fd.write('.. title: %s\n' % title)
- fd.write('.. slug: %s\n' % slug)
- fd.write('.. date: %s\n' % date)
- fd.write('.. tags: %s\n' % tags)
+ fd.write('.. title: {0}\n'.format(title))
+ fd.write('.. slug: {0}\n'.format(slug))
+ fd.write('.. date: {0}\n'.format(date))
+ fd.write('.. tags: {0}\n'.format(tags))
fd.write('.. link: \n')
fd.write('.. description: \n')
fd.write('-->\n\n')
diff --git a/nikola/plugins/compile_markdown/__init__.py b/nikola/plugins/compile_markdown/__init__.py
index 5eb25c8..7aa03a9 100644
--- a/nikola/plugins/compile_markdown/__init__.py
+++ b/nikola/plugins/compile_markdown/__init__.py
@@ -55,8 +55,10 @@ class CompileMarkdown(PageCompiler):
output = markdown(data, ['fenced_code', 'codehilite'])
# 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)
+ output = re.sub('<h{0}>'.format(n), '<h{0}>'.format(n + 1),
+ output)
+ output = re.sub('</h{0}>'.format(n), '</h{0}>'.format(n + 1),
+ output)
# python-markdown's highlighter uses the class 'codehilite' to wrap
# code, # instead of the standard 'code'. None of the standard
# pygments stylesheets use this class, so swap it to be 'code'
@@ -69,10 +71,10 @@ class CompileMarkdown(PageCompiler):
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
fd.write('<!-- \n')
- fd.write('.. title: %s\n' % title)
- fd.write('.. slug: %s\n' % slug)
- fd.write('.. date: %s\n' % date)
- fd.write('.. tags: %s\n' % tags)
+ fd.write('.. title: {0}\n'.format(title))
+ fd.write('.. slug: {0}\n'.format(slug))
+ fd.write('.. date: {0}\n'.format(date))
+ fd.write('.. tags: {0}\n'.format(tags))
fd.write('.. link: \n')
fd.write('.. description: \n')
fd.write('-->\n\n')
diff --git a/nikola/plugins/compile_rest/__init__.py b/nikola/plugins/compile_rest/__init__.py
index 4191add..b0a0c00 100644
--- a/nikola/plugins/compile_rest/__init__.py
+++ b/nikola/plugins/compile_rest/__init__.py
@@ -44,6 +44,8 @@ from .slides import slides
directives.register_directive('slides', slides)
from .gist_directive import GitHubGist
directives.register_directive('gist', GitHubGist)
+from .soundcloud import soundcloud
+directives.register_directive('soundcloud', soundcloud)
from nikola.plugin_categories import PageCompiler
@@ -75,10 +77,10 @@ class CompileRest(PageCompiler):
tags=""):
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
- fd.write('.. title: %s\n' % title)
- fd.write('.. slug: %s\n' % slug)
- fd.write('.. date: %s\n' % date)
- fd.write('.. tags: %s\n' % tags)
+ fd.write('.. title: {0}\n'.format(title))
+ fd.write('.. slug: {0}\n'.format(slug))
+ fd.write('.. date: {0}\n'.format(date))
+ fd.write('.. tags: {0}\n'.format(tags))
fd.write('.. link: \n')
fd.write('.. description: \n\n')
fd.write("\nWrite your post here.")
diff --git a/nikola/plugins/compile_rest/gist_directive.py b/nikola/plugins/compile_rest/gist_directive.py
index 3bfe818..0ea8f23 100644
--- a/nikola/plugins/compile_rest/gist_directive.py
+++ b/nikola/plugins/compile_rest/gist_directive.py
@@ -24,11 +24,11 @@ class GitHubGist(Directive):
has_content = False
def get_raw_gist_with_filename(self, gistID, filename):
- url = "https://raw.github.com/gist/%s/%s" % (gistID, filename)
+ url = '/'.join(("https://raw.github.com/gist", gistID, filename))
return requests.get(url).text
def get_raw_gist(self, gistID):
- url = "https://raw.github.com/gist/%s/" % (gistID)
+ url = "https://raw.github.com/gist/{0}/".format(gistID)
return requests.get(url).text
def run(self):
@@ -43,12 +43,12 @@ class GitHubGist(Directive):
if 'file' in self.options:
filename = self.options['file']
rawGist = (self.get_raw_gist_with_filename(gistID, filename))
- embedHTML = ('<script src="https://gist.github.com/%s.js?file=%s">'
- '</script>') % (gistID, filename)
+ embedHTML = ('<script src="https://gist.github.com/{0}.js'
+ '?file={1}"></script>').format(gistID, filename)
else:
rawGist = (self.get_raw_gist(gistID))
- embedHTML = ('<script src="https://gist.github.com/%s.js">'
- '</script>') % gistID
+ embedHTML = ('<script src="https://gist.github.com/{0}.js">'
+ '</script>').format(gistID)
return [nodes.raw('', embedHTML, format='html'),
nodes.raw('', '<noscript>', format='html'),
diff --git a/nikola/plugins/compile_rest/pygments_code_block_directive.py b/nikola/plugins/compile_rest/pygments_code_block_directive.py
index f858427..79bada2 100644
--- a/nikola/plugins/compile_rest/pygments_code_block_directive.py
+++ b/nikola/plugins/compile_rest/pygments_code_block_directive.py
@@ -165,9 +165,9 @@ def code_block_directive(name, arguments, options, content, lineno,
after_index = content.find(after_text)
if after_index < 0:
raise state_machine.reporter.severe(
- 'Problem with "start-at" option of "%s" '
- 'code-block directive:\nText not found.'
- % options['start-at'])
+ 'Problem with "start-at" option of "{0}" '
+ 'code-block directive:\nText not found.'.format(
+ options['start-at']))
# patch mmueller start
# Move the after_index to the beginning of the line with the
# match.
@@ -192,9 +192,9 @@ def code_block_directive(name, arguments, options, content, lineno,
after_index = content.find(after_text)
if after_index < 0:
raise state_machine.reporter.severe(
- 'Problem with "start-after" option of "%s" '
- 'code-block directive:\nText not found.' %
- options['start-after'])
+ 'Problem with "start-after" option of "{0}" '
+ 'code-block directive:\nText not found.'.format(
+ options['start-after']))
line_offset = len(content[:after_index +
len(after_text)].splitlines())
content = content[after_index + len(after_text):]
@@ -207,9 +207,9 @@ def code_block_directive(name, arguments, options, content, lineno,
before_index = content.find(before_text)
if before_index < 0:
raise state_machine.reporter.severe(
- 'Problem with "end-at" option of "%s" '
- 'code-block directive:\nText not found.' %
- options['end-at'])
+ 'Problem with "end-at" option of "{0}" '
+ 'code-block directive:\nText not found.'.format(
+ options['end-at']))
content = content[:before_index + len(before_text)]
before_text = options.get('end-before', None)
@@ -219,9 +219,9 @@ def code_block_directive(name, arguments, options, content, lineno,
before_index = content.find(before_text)
if before_index < 0:
raise state_machine.reporter.severe(
- 'Problem with "end-before" option of "%s" '
- 'code-block directive:\nText not found.' %
- options['end-before'])
+ 'Problem with "end-before" option of "{0}" '
+ 'code-block directive:\nText not found.'.format(
+ options['end-before']))
content = content[:before_index]
else:
@@ -246,8 +246,9 @@ def code_block_directive(name, arguments, options, content, lineno,
lineno = 1 + line_offset
total_lines = content.count('\n') + 1 + line_offset
lnwidth = len(str(total_lines))
- fstr = "\n%%%dd " % lnwidth
- code_block += nodes.inline(fstr[1:] % lineno, fstr[1:] % lineno,
+ fstr = "\n%{0}d ".format(lnwidth)
+ code_block += nodes.inline(fstr[1:].format(lineno),
+ fstr[1:].format(lineno),
classes=['linenumber'])
# parse content with pygments and add to code_block element
@@ -272,7 +273,8 @@ def code_block_directive(name, arguments, options, content, lineno,
linenos = list(range(lineno, lineno + len(values)))
for chunk, ln in zip(values, linenos)[1:]:
if ln <= total_lines:
- code_block += nodes.inline(fstr % ln, fstr % ln,
+ code_block += nodes.inline(fstr.format(ln),
+ fstr.format(ln),
classes=['linenumber'])
code_block += nodes.Text(chunk, chunk)
lineno += len(values) - 1
@@ -319,8 +321,8 @@ def string_bool(argument):
elif argument.lower() == 'false':
return False
else:
- raise ValueError('"%s" unknown; choose from "True" or "False"' %
- argument)
+ raise ValueError('"{0}" unknown; choose from "True" or "False"'.format(
+ argument))
def csharp_unicodelevel(argument):
@@ -340,7 +342,8 @@ def listings_directive(name, arguments, options, content, lineno,
fname = arguments[0]
options['include'] = os.path.join('listings', fname)
target = urlunsplit(("link", 'listing', fname, '', ''))
- generated_nodes = [core.publish_doctree('`%s <%s>`_' % (fname, target))[0]]
+ generated_nodes = [core.publish_doctree('`{0} <{1}>`_'.format(fname,
+ target))[0]]
generated_nodes += code_block_directive(name, [arguments[1]], options,
content, lineno, content_offset,
block_text, state, state_machine)
diff --git a/nikola/plugins/compile_rest/slides.py b/nikola/plugins/compile_rest/slides.py
index c9d55f3..f9901f5 100644
--- a/nikola/plugins/compile_rest/slides.py
+++ b/nikola/plugins/compile_rest/slides.py
@@ -77,12 +77,13 @@ class slides(Directive):
options.update(self.options)
options = json.dumps(options)
output = []
- output.append('<script> $(function(){ $("#slides").slides(%s); });'
- '</script>' % options)
+ output.append('<script> $(function(){ $("#slides").slides(' + options +
+ '); });'
+ '</script>')
output.append('<div id="slides" class="slides"><div '
'class="slides_container">')
for image in self.content:
- output.append("""<div><img src="%s"></div>""" % image)
+ output.append("""<div><img src="{0}"></div>""".format(image))
output.append("""</div></div>""")
return [nodes.raw('', '\n'.join(output), format='html')]
diff --git a/nikola/plugins/compile_rest/soundcloud.py b/nikola/plugins/compile_rest/soundcloud.py
new file mode 100644
index 0000000..d47bebf
--- /dev/null
+++ b/nikola/plugins/compile_rest/soundcloud.py
@@ -0,0 +1,32 @@
+from docutils import nodes
+from docutils.parsers.rst import directives
+
+CODE = ("""<iframe width="{width}" height="{height}"
+scrolling="no" frameborder="no"
+src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/tracks/"""
+ """{sid}">
+</iframe>""")
+
+
+def soundcloud(name, args, options, content, lineno,
+ contentOffset, blockText, state, stateMachine):
+ """ Restructured text extension for inserting SoundCloud embedded music """
+ string_vars = {
+ 'sid': content[0],
+ 'width': 600,
+ 'height': 160,
+ 'extra': ''
+ }
+ extra_args = content[1:] # Because content[0] is ID
+ extra_args = [ea.strip().split("=") for ea in extra_args] # key=value
+ extra_args = [ea for ea in extra_args if len(ea) == 2] # drop bad lines
+ extra_args = dict(extra_args)
+ if 'width' in extra_args:
+ string_vars['width'] = extra_args.pop('width')
+ if 'height' in extra_args:
+ string_vars['height'] = extra_args.pop('height')
+
+ return [nodes.raw('', CODE.format(**string_vars), format='html')]
+
+soundcloud.content = True
+directives.register_directive('soundcloud', soundcloud)
diff --git a/nikola/plugins/compile_rest/vimeo.py b/nikola/plugins/compile_rest/vimeo.py
index 3eefcc4..34f2a50 100644
--- a/nikola/plugins/compile_rest/vimeo.py
+++ b/nikola/plugins/compile_rest/vimeo.py
@@ -37,8 +37,8 @@ except ImportError:
except ImportError:
json = None
-CODE = """<iframe src="http://player.vimeo.com/video/%(vimeo_id)s"
-width="%(width)s" height="%(height)s"
+CODE = """<iframe src="http://player.vimeo.com/video/{vimeo_id}"
+width="{width}" height="{height}"
frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen>
</iframe>
"""
@@ -76,8 +76,8 @@ def vimeo(name, args, options, content, lineno, contentOffset, blockText,
if json: # we can attempt to retrieve video attributes from vimeo
try:
- url = ('http://vimeo.com/api/v2/video/%(vimeo_id)s.json' %
- string_vars)
+ url = ('http://vimeo.com/api/v2/video/{vimeo_id}'
+ '.json'.format(**string_vars))
data = requests.get(url).text
video_attributes = json.loads(data)
string_vars['height'] = video_attributes['height']
@@ -86,7 +86,7 @@ def vimeo(name, args, options, content, lineno, contentOffset, blockText,
# fall back to the defaults
pass
- return [nodes.raw('', CODE % string_vars, format='html')]
+ return [nodes.raw('', CODE.format(**string_vars), format='html')]
vimeo.content = True
directives.register_directive('vimeo', vimeo)
diff --git a/nikola/plugins/compile_rest/youtube.py b/nikola/plugins/compile_rest/youtube.py
index fe3b28b..30ac000 100644
--- a/nikola/plugins/compile_rest/youtube.py
+++ b/nikola/plugins/compile_rest/youtube.py
@@ -26,9 +26,9 @@ from docutils import nodes
from docutils.parsers.rst import directives
CODE = """\
-<iframe width="%(width)s"
-height="%(height)s"
-src="http://www.youtube.com/embed/%(yid)s?rel=0&amp;hd=1&amp;wmode=transparent"
+<iframe width="{width}"
+height="{height}"
+src="http://www.youtube.com/embed/{yid}?rel=0&amp;hd=1&amp;wmode=transparent"
></iframe>"""
@@ -51,6 +51,6 @@ def youtube(name, args, options, content, lineno,
string_vars['width'] = extra_args.pop('width')
if 'height' in extra_args:
string_vars['height'] = extra_args.pop('height')
- return [nodes.raw('', CODE % (string_vars), format='html')]
+ return [nodes.raw('', CODE.format(**string_vars), format='html')]
youtube.content = True
directives.register_directive('youtube', youtube)
diff --git a/nikola/plugins/compile_textile.py b/nikola/plugins/compile_textile.py
index 7fa4e3f..3ca370d 100644
--- a/nikola/plugins/compile_textile.py
+++ b/nikola/plugins/compile_textile.py
@@ -62,10 +62,10 @@ class CompileTextile(PageCompiler):
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
fd.write('<notextile> <!--\n')
- fd.write('.. title: %s\n' % title)
- fd.write('.. slug: %s\n' % slug)
- fd.write('.. date: %s\n' % date)
- fd.write('.. tags: %s\n' % tags)
+ fd.write('.. title: {0}\n'.format(title))
+ fd.write('.. slug: {0}\n'.format(slug))
+ fd.write('.. date: {0}\n'.format(date))
+ fd.write('.. tags: {0}\n'.format(tags))
fd.write('.. link: \n')
fd.write('.. description: \n')
fd.write('--></notextile>\n\n')
diff --git a/nikola/plugins/compile_txt2tags.py b/nikola/plugins/compile_txt2tags.py
index 2446dfd..90372bd 100644
--- a/nikola/plugins/compile_txt2tags.py
+++ b/nikola/plugins/compile_txt2tags.py
@@ -65,10 +65,10 @@ class CompileTextile(PageCompiler):
with codecs.open(path, "wb+", "utf8") as fd:
if onefile:
fd.write("\n'''\n<!--\n")
- fd.write('.. title: %s\n' % title)
- fd.write('.. slug: %s\n' % slug)
- fd.write('.. date: %s\n' % date)
- fd.write('.. tags: %s\n' % tags)
+ fd.write('.. title: {0}\n'.format(title))
+ fd.write('.. slug: {0}\n'.format(slug))
+ fd.write('.. date: {0}\n'.format(date))
+ fd.write('.. tags: {0}\n'.format(tags))
fd.write('.. link: \n')
fd.write('.. description: \n')
fd.write("-->\n'''\n")
diff --git a/nikola/plugins/task_create_bundles.py b/nikola/plugins/task_create_bundles.py
index 95f10c2..ad670e1 100644
--- a/nikola/plugins/task_create_bundles.py
+++ b/nikola/plugins/task_create_bundles.py
@@ -77,7 +77,8 @@ class BuildBundles(LateTask):
output_path = os.path.join(kw['output_folder'], name)
dname = os.path.dirname(name)
file_dep = [get_asset_path(
- os.path.join(dname, fname), kw['themes'], kw['files_folders'])
+ os.path.join(dname, fname), kw['themes'],
+ kw['files_folders'])
for fname in files
]
file_dep = filter(None, file_dep) # removes missing files
@@ -108,16 +109,17 @@ def get_asset_path(path, themes, files_folders={'files': ''}):
If the asset is not provided by a theme, then it will be checked for
in the FILES_FOLDERS
- >>> get_asset_path('assets/css/rst.css', ['site','default'])
+ >>> get_asset_path('assets/css/rst.css', ['site', 'default'])
'nikola/data/themes/default/assets/css/rst.css'
- >>> get_asset_path('assets/css/theme.css', ['site','default'])
+ >>> get_asset_path('assets/css/theme.css', ['site', 'default'])
'nikola/data/themes/site/assets/css/theme.css'
- >>> get_asset_path('nikola.py',['site','default'],{'nikola':''})
+ >>> get_asset_path('nikola.py', ['site', 'default'], {'nikola': ''})
'nikola/nikola.py'
- >>> get_asset_path('nikola/nikola.py',['site','default'],{'nikola':'nikola'})
+ >>> get_asset_path('nikola/nikola.py', ['site', 'default'],
+ ... {'nikola':'nikola'})
'nikola/nikola.py'
"""
diff --git a/nikola/plugins/task_indexes.py b/nikola/plugins/task_indexes.py
index 757998e..7baf660 100644
--- a/nikola/plugins/task_indexes.py
+++ b/nikola/plugins/task_indexes.py
@@ -79,11 +79,11 @@ class Indexes(Task):
context["nextlink"] = None
context['index_teasers'] = kw['index_teasers']
if i > 1:
- context["prevlink"] = "index-%s.html" % (i - 1)
+ context["prevlink"] = "index-{0}.html".format(i - 1)
if i == 1:
context["prevlink"] = "index.html"
if i < num_pages - 1:
- context["nextlink"] = "index-%s.html" % (i + 1)
+ context["nextlink"] = "index-{0}.html".format(i + 1)
context["permalink"] = self.site.link("index", i, lang)
output_name = os.path.join(
kw['output_folder'], self.site.path("index", i,
diff --git a/nikola/plugins/task_redirect.py b/nikola/plugins/task_redirect.py
index b133948..e440c30 100644
--- a/nikola/plugins/task_redirect.py
+++ b/nikola/plugins/task_redirect.py
@@ -71,5 +71,6 @@ def create_redirect(src, dst):
except:
pass
with codecs.open(src, "wb+", "utf8") as fd:
- fd.write('<head><meta http-equiv="refresh" content="0; '
- 'url=%s"></head>' % dst)
+ fd.write('<!DOCTYPE html><head><title>Redirecting...</title>'
+ '<meta http-equiv="refresh" content="0; '
+ 'url={0}"></head>'.format(dst))
diff --git a/nikola/plugins/task_render_galleries.py b/nikola/plugins/task_render_galleries.py
index e69a457..0880e3e 100644
--- a/nikola/plugins/task_render_galleries.py
+++ b/nikola/plugins/task_render_galleries.py
@@ -136,7 +136,6 @@ class Galleries(Task):
# Sort by date
image_list.sort(key=lambda a: self.image_date(a))
image_name_list = [os.path.basename(x) for x in image_list]
-
thumbs = []
# Do thumbnails and copy originals
for img, img_name in list(zip(image_list, image_name_list)):
@@ -187,7 +186,7 @@ class Galleries(Task):
output_gallery, ".thumbnail".join([fname, ext]))
excluded_dest_path = os.path.join(output_gallery, img_name)
yield {
- 'basename': str('render_galleries'),
+ 'basename': str('render_galleries_clean'),
'name': excluded_thumb_dest_path.encode('utf8'),
'file_dep': [exclude_path],
#'targets': [excluded_thumb_dest_path],
@@ -198,7 +197,7 @@ class Galleries(Task):
'uptodate': [utils.config_changed(kw)],
}
yield {
- 'basename': str('render_galleries'),
+ 'basename': str('render_galleries_clean'),
'name': excluded_dest_path.encode('utf8'),
'file_dep': [exclude_path],
#'targets': [excluded_dest_path],
@@ -214,9 +213,9 @@ class Galleries(Task):
context["title"] = os.path.basename(gallery_path)
context["description"] = kw["blog_description"]
if kw['use_filename_as_title']:
- img_titles = ['id="%s" alt="%s" title="%s"' %
- (fn[:-4], fn[:-4], utils.unslugify(fn[:-4]))
- for fn in image_name_list]
+ img_titles = ['id="{0}" alt="{1}" title="{2}"'.format(
+ fn[:-4], fn[:-4], utils.unslugify(fn[:-4])) for fn
+ in image_name_list]
else:
img_titles = [''] * len(image_name_list)
context["images"] = list(zip(image_name_list, thumbs, img_titles))
diff --git a/nikola/plugins/task_render_listings.py b/nikola/plugins/task_render_listings.py
index a899f10..b115a2f 100644
--- a/nikola/plugins/task_render_listings.py
+++ b/nikola/plugins/task_render_listings.py
@@ -50,29 +50,32 @@ class Listings(Task):
# Things to ignore in listings
ignored_extensions = (".pyc",)
- def render_listing(in_name, out_name):
- with open(in_name, 'r') as fd:
- try:
- lexer = get_lexer_for_filename(in_name)
- except:
- lexer = TextLexer()
- code = highlight(fd.read(), lexer,
- HtmlFormatter(cssclass='code',
- linenos="table", nowrap=False,
- lineanchors=utils.slugify(f),
- anchorlinenos=True))
- title = os.path.basename(in_name)
- print("CRUMBSINOUT", in_name, out_name)
- #crumbs = out_name.split(os.sep)[1:-1] + [title]
- # TODO: write this in human
- #paths = ['/'.join(['..'] * (len(crumbs) - 2 - i)) for i in
- #range(len(crumbs[:-2]))] + ['.', '#']
- crumbs = utils.get_crumbs(os.path.relpath(out_name, kw['output_folder']), is_file=True)
+ def render_listing(in_name, out_name, folders=[], files=[]):
+ if in_name:
+ with open(in_name, 'r') as fd:
+ try:
+ lexer = get_lexer_for_filename(in_name)
+ except:
+ lexer = TextLexer()
+ code = highlight(fd.read(), lexer,
+ HtmlFormatter(cssclass='code',
+ linenos="table", nowrap=False,
+ lineanchors=utils.slugify(f),
+ anchorlinenos=True))
+ title = os.path.basename(in_name)
+ else:
+ code = ''
+ title = ''
+ crumbs = utils.get_crumbs(os.path.relpath(out_name,
+ kw['output_folder']),
+ is_file=True)
context = {
'code': code,
'title': title,
'crumbs': crumbs,
'lang': kw['default_lang'],
+ 'folders': folders,
+ 'files': files,
'description': title,
}
self.site.render_template('listing.tmpl', out_name.encode('utf8'),
@@ -80,12 +83,27 @@ class Listings(Task):
flag = True
template_deps = self.site.template_system.template_deps('listing.tmpl')
for root, dirs, files in os.walk(kw['listings_folder']):
+ flag = False
# Render all files
+ out_name = os.path.join(
+ kw['output_folder'],
+ root, 'index.html'
+ )
+ yield {
+ 'basename': self.name,
+ 'name': out_name.encode('utf8'),
+ 'file_dep': template_deps,
+ 'targets': [out_name],
+ 'actions': [(render_listing, [None, out_name, dirs, files])],
+ # This is necessary to reflect changes in blog title,
+ # sidebar links, etc.
+ 'uptodate': [utils.config_changed(
+ self.site.config['GLOBAL_CONTEXT'])]
+ }
for f in files:
ext = os.path.splitext(f)[-1]
if ext in ignored_extensions:
continue
- flag = False
in_name = os.path.join(root, f)
out_name = os.path.join(
kw['output_folder'],
diff --git a/nikola/plugins/task_render_rss.py b/nikola/plugins/task_render_rss.py
index fb35843..9ce1d63 100644
--- a/nikola/plugins/task_render_rss.py
+++ b/nikola/plugins/task_render_rss.py
@@ -39,7 +39,7 @@ class RenderRSS(Task):
"translations": self.site.config["TRANSLATIONS"],
"filters": self.site.config["FILTERS"],
"blog_title": self.site.config["BLOG_TITLE"],
- "blog_url": self.site.config["BLOG_URL"],
+ "site_url": self.site.config["SITE_URL"],
"blog_description": self.site.config["BLOG_DESCRIPTION"],
"output_folder": self.site.config["OUTPUT_FOLDER"],
"rss_teasers": self.site.config["RSS_TEASERS"],
@@ -59,7 +59,7 @@ class RenderRSS(Task):
'file_dep': deps,
'targets': [output_name],
'actions': [(utils.generic_rss_renderer,
- (lang, kw["blog_title"], kw["blog_url"],
+ (lang, kw["blog_title"], kw["site_url"],
kw["blog_description"], posts, output_name,
kw["rss_teasers"]))],
'clean': True,
diff --git a/nikola/plugins/task_render_tags.py b/nikola/plugins/task_render_tags.py
index a561a81..744f0cb 100644
--- a/nikola/plugins/task_render_tags.py
+++ b/nikola/plugins/task_render_tags.py
@@ -22,7 +22,7 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#from __future__ import unicode_literals
+from __future__ import unicode_literals
import codecs
import json
import os
@@ -42,7 +42,7 @@ class RenderTags(Task):
kw = {
"translations": self.site.config["TRANSLATIONS"],
"blog_title": self.site.config["BLOG_TITLE"],
- "blog_url": self.site.config["BLOG_URL"],
+ "site_url": self.site.config["SITE_URL"],
"blog_description": self.site.config["BLOG_DESCRIPTION"],
"messages": self.site.MESSAGES,
"output_folder": self.site.config['OUTPUT_FOLDER'],
@@ -56,6 +56,8 @@ class RenderTags(Task):
self.site.scan_posts()
+ yield self.list_tags_page(kw)
+
if not self.site.posts_per_tag:
yield {'basename': str(self.name), 'actions': []}
return
@@ -73,8 +75,6 @@ class RenderTags(Task):
else:
yield self.tag_page_as_list(tag, lang, post_list, kw)
- yield self.list_tags_page(kw)
-
# Tag cloud json file
tag_cloud_data = {}
for tag, posts in self.site.posts_per_tag.items():
@@ -136,7 +136,7 @@ class RenderTags(Task):
"""Given tag, n, returns a page name."""
name = self.site.path("tag", tag, lang)
if i:
- name = name.replace('.html', '-%s.html' % i)
+ name = name.replace('.html', '-{0}.html'.format(i))
return name
# FIXME: deduplicate this with render_indexes
@@ -152,11 +152,11 @@ class RenderTags(Task):
# On a tag page, the feeds include the tag's feeds
rss_link = ("""<link rel="alternate" type="application/rss+xml" """
"""type="application/rss+xml" title="RSS for tag """
- """%s (%s)" href="%s">""" %
- (tag, lang, self.site.link("tag_rss", tag, lang)))
+ """{0} ({1})" href="{2}">""".format(
+ tag, lang, self.site.link("tag_rss", tag, lang)))
context['rss_link'] = rss_link
- output_name = os.path.join(kw['output_folder'], page_name(tag, i,
- lang))
+ output_name = os.path.join(kw['output_folder'],
+ page_name(tag, i, lang))
output_name = output_name.encode('utf8')
context["title"] = kw["messages"][lang][
"Posts about %s"] % tag
@@ -231,8 +231,8 @@ class RenderTags(Task):
'file_dep': deps,
'targets': [output_name],
'actions': [(utils.generic_rss_renderer,
- (lang, "%s (%s)" % (kw["blog_title"], tag),
- kw["blog_url"], kw["blog_description"], post_list,
+ (lang, "{0} ({1})".format(kw["blog_title"], tag),
+ kw["site_url"], kw["blog_description"], post_list,
output_name, kw["rss_teasers"]))],
'clean': True,
'uptodate': [utils.config_changed(kw)],
diff --git a/nikola/plugins/task_sitemap/__init__.py b/nikola/plugins/task_sitemap/__init__.py
index 96b9dbd..9d89070 100644
--- a/nikola/plugins/task_sitemap/__init__.py
+++ b/nikola/plugins/task_sitemap/__init__.py
@@ -49,7 +49,8 @@ class Sitemap(LateTask):
return
"""Generate Google sitemap."""
kw = {
- "blog_url": self.site.config["BLOG_URL"],
+ "base_url": self.site.config["BASE_URL"],
+ "site_url": self.site.config["SITE_URL"],
"output_folder": self.site.config["OUTPUT_FOLDER"],
}
output_path = os.path.abspath(kw['output_folder'])
@@ -59,18 +60,14 @@ class Sitemap(LateTask):
# Generate config
config_data = """<?xml version="1.0" encoding="UTF-8"?>
<site
- base_url="%s"
- store_into="%s"
+ base_url="{0}"
+ store_into="{1}"
verbose="1" >
- <directory path="%s" url="%s" />
+ <directory path="{2}" url="{3}" />
<filter action="drop" type="wildcard" pattern="*~" />
<filter action="drop" type="regexp" pattern="/\.[^/]*" />
- </site>""" % (
- kw["blog_url"],
- sitemap_path,
- output_path,
- kw["blog_url"],
- )
+ </site>""".format(kw["site_url"], sitemap_path, output_path,
+ kw["base_url"])
config_file = tempfile.NamedTemporaryFile(delete=False)
config_file.write(config_data.encode('utf8'))
config_file.close()
@@ -82,14 +79,15 @@ class Sitemap(LateTask):
0)
else:
sitemap.Generate()
- sitemap_gen.output.Log('Number of errors: %d' %
- sitemap_gen.output.num_errors, 1)
- sitemap_gen.output.Log('Number of warnings: %d' %
- sitemap_gen.output.num_warns, 1)
+ sitemap_gen.output.Log('Number of errors: {0}'.format(
+ sitemap_gen.output.num_errors), 1)
+ sitemap_gen.output.Log('Number of warnings: {0}'.format(
+ sitemap_gen.output.num_warns), 1)
os.unlink(config_file.name)
yield {
"basename": "sitemap",
+ "name": os.path.join(kw['output_folder'], "sitemap.xml.gz"),
"targets": [sitemap_path],
"actions": [(sitemap,)],
"uptodate": [config_changed(kw)],
diff --git a/nikola/plugins/task_sitemap/sitemap_gen.py b/nikola/plugins/task_sitemap/sitemap_gen.py
index a877c24..898325a 100644
--- a/nikola/plugins/task_sitemap/sitemap_gen.py
+++ b/nikola/plugins/task_sitemap/sitemap_gen.py
@@ -90,7 +90,7 @@ if sys.version_info[0] == 3:
unichr = chr
else:
bytes_str = str
- unicode_str = unicode
+ unicode_str = unicode # NOQA
# Text encodings
ENC_ASCII = 'ASCII'